1

HTML:

<select class="form-control" name="paramType" ng-change="setParamC($index)" ng-model="row.ParameterT" ng-options="item.ReferenceValue for item in pagemodel.ParamTList" required></select>

<select class="form-control" name="paramCat" ng-change="validatePCat($index)" ng-model="row.ParameterC" ng-options="item.ReferenceValue for item in pagemodel.ParamCList|filter:{ReferenceParentCode:row.ParameterT.ReferenceCode , ReferenceParentDomain:row.ParameterT.ReferenceDomain}" required></select>

<select class="form-control" name="paramName" ng-change="setParamV($index,0)" ng-model="row.ParameterN" ng-options="item.ReferenceValue for item in pagemodel.ParamNList|filter:{ReferenceParentCode:row.ParameterC.ReferenceCode , ReferenceParentDomain:row.ParameterC.ReferenceDomain}" required></select>

I have a list of data objects that are returned from the server to the front end via an ajax call. Each object contains three properties (ParameterT, ParameterC and ParameterN) that point to other objects.

I also have three lists of objects that are used as the options for my three dropdowns. These three lists are generated by the server and sent to the front end via the same ajax call.

The 3 lists of objects for my dropdown options and the three properties in my main data object are all the same object type.

Here's the data in my first list, ParamTList, as seen on the front end:

(2) [{…}, {…}]
0:
    $$hashKey:"object:503"
    ReferenceCode:1
    ReferenceDomain:"AGG_TIER_PARAMETER_TYPE"
    ReferenceParentCode:null
    ReferenceParentDomain:null
    ReferenceValue:"Static"
    __proto__:Object
1:
    $$hashKey:"object:504"
    ReferenceCode:2
    ReferenceDomain:"AGG_TIER_PARAMETER_TYPE"
    ReferenceParentCode:null
    ReferenceParentDomain:null
    ReferenceValue:"Dynamic"
    __proto__:Object
length:2
__proto__:Array(0)

and here's the ParameterT object:

{ReferenceDomain: "AGG_TIER_PARAMETER_TYPE", ReferenceCode: 2, ReferenceValue: "Dynamic", ReferenceParentDomain: null, ReferenceParentCode: null}
    ReferenceCode:2
    ReferenceDomain:"AGG_TIER_PARAMETER_TYPE"
    ReferenceParentCode:null
    ReferenceParentDomain:null
    ReferenceValue:"Dynamic"
    __proto__:Object

The ParameterT object that is used as the ng-model is identical to one object used in the ng-options list, except for the $$hashKey property. I'm guessing that is why the binding does not take place. The ParameterT object is a child object, but it's parent object, the main data object, does have a $$hashKey property.

Is that correct? If YES, how do I get around this? If NO, what am I doing wrong?

I could do all of this with strings istead of objects, but I'd loose the ability to filter the dropdown selections based on the previous dropdown's setting.

This currently works in production, because the three child properties are set up on the front end, by looping through all of the data objects, and then looping through the three lists of options searching for matches. This performs poorly, that's why I'm trying to move inefficient stuff like that to the server.

1
  • In angularJS in options if you want default selection to be there you have to pass the exact same object in ng-model as in options so for this you have to do something like this $scope.row.ParameterT = $scope.pagemodel.ParamTList[0] Commented Oct 26, 2018 at 4:42

1 Answer 1

1

Explanation:

You need to use a track by expression in each of your ng-options, which is standard practice.

The reason is that if you don't, Angular creates a $$hashkey property on your repeated data for DOM change tracking. And this $$hashkey causes the select object to be unmatchable with your http data, which doesn't have the property.

Using track by, Angular just compares the specified property for equality instead of the whole object (and $$hashkey is not added anyway.)

Solution:

So, using your ParamT as an example, and assuming there is a unique property (such as ReferenceCode) on each object, it would look like:

ng-options="item.ReferenceValue for item in pagemodel.ParamTList track by item.ReferenceCode"

Otherwise you can try:

ng-options="item.ReferenceValue for item in pagemodel.ParamTList track by $index"

which tracks by the position in the collection.

Here is a Working Fiddle;

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks.. I can try this when I get to the office today, I assumed the $$hashkey property was added during the deserialization process after the ajax call.
Understandable but no. You could test that by logging data from an http call and seeing there is no $$hashkey property. It is added explicitly to the repeated model in the case of ng-options and ng-repeat so Angular knows how to update the DOM properly when data changes. But this $$hashkey causes your problem because now your data object won't match the select objects. If you use track by, Angular just compares the specified track by property for equality instead of the whole object (and $$hashkey is not added.) Here's a Working Fiddle.
I'm getting close... the track by $index does fix my initial binding problem, but now my cascading filter doesn't work. (as shown in my drowpdown examples, setting the first dropdown limits the selections of the second... and setting the second dropdown limits the selections of the third) I should be able to have a filter and a track by in the same ng-options clause. Correct ?
Yes. Check this for filter syntax: stackoverflow.com/a/21416725/2185093 You should probably ask a new question for the dropdowns. Feel free to accept this answer for now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.