javascripthtmlangularjsng-options

AngularJS - Data Model Doesn't Bind in Dropdown


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.


Solution

  • 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;