0

I'm having an issue using a dropdown that is populated with ng-repeat option values or even when using ng-options.

Basically I'm pulling a list of subsidiaries from the database. I then have a dropdown to choose a company, which in turn should populate the subsidiary dropdown with subsidiaries of the chosen company. Since many of the subsidiaries are of the same company, if I try and pull the the company name in ng-repeat, I get the same company several times. So I have created a custom filter that filters out the companyName and companyID of each company listed only once.

Everything works in the theory that when I change the value of the company dropdown, the correct subsidiaries are listed. However the value shown in the company box is stuck on the first option listed and will not change. If I remove the custom filter and allow it to list all the repeat names, the box displays correctly.

My first thought is to make a separate HTTP call that would just get companies from my companies table, but I would think I want to limit HTTP calls to as few as possible. Plus it would seem that I should be able to accomplish this.

What concept am I not grasping that prevents this from displaying correctly when I use my filter and what should I do to fix this? thanks

HTML:

<div class="col-sm-5">
   <select ng-model ="parentCompany" name="company">
      <option ng-repeat="company in companies | uniqueCompanies:'companyName'" value="{{company.id}}" >{{company.name}}</option>
    </select>                                                 
</div>

<div class="col-sm-5">
   <select name="subsidiary">
    <option ng-repeat="subsidary in companies" value="{{subsidary.subID}}" ng-hide="$parent.parentCompany !== subsidary.companyID">{{subsidary.subName}}</option>
   </select>
</div>

Controller:

  getCompanies();
            function getCompanies(){
                 $http.get("get.php?table=getcompanies").success(function(data) {
                    $scope.companies = data;
                });
            }

Filter:

.filter("uniqueCompanies", function() {
            return function(data, propertyName) {
                if (angular.isArray(data) && angular.isString(propertyName)) {
                    var results = [];
                    var keys = {};
                    for (var i = 0; i < data.length; i++) {
                        var val = data[i][propertyName];
                        var val2 = data[i]['companyID'];
                        if (angular.isUndefined(keys[val])) {
                            keys[val] = true;
                            results.push({'name':val, 'id':val2});
                        }
                    }
                    return results;
                } else {
                    return data;
                }
            };
        });

Sample Data :

[{"subID":null,"subName":null,"companyID":"1","companyName":"DWG"},
 {"subID":null,"subName":null,"companyID":"2","companyName":"Vista"},
 {"subID":"1008","subName":"Data Services","companyID":"3","companyName":"Medcare"},
 {"subID":"1009","subName":"Companion","companyID":"3","companyName":"Medcare"},
 {"subID":"1010","subName":"GBA","companyID":"3","companyName":"Medcare"},
 {"subID":"1011","subName":"PGBA","companyID":"3","companyName":"Medcare"},
 {"subID":"1013","subName":"Health Plan","companyID":"3","companyName":"Medcare"},
 {"subID":"1014","subName":"PAISC","companyID":"3","companyName":"Medcare"},
 {"subID":"1015","subName":"CGS","companyID":"3","companyName":"Medcare"}]
9
  • 1
    Would it help to run the filter in the controller prior to the select? Commented Aug 11, 2014 at 19:21
  • Because the filter is returning an array of new objects each time, you need to provide a track by expression. See if that makes a difference. Commented Aug 11, 2014 at 19:36
  • Can you give some sample data? It's a little hard to follow because you rename properties in your filter. It looks like your data has companyName, companyID, subID and subName. What are the rules if a subsidiary has a subsidiary of it's own? i.e. "GE->NBC Universal->NBC Broadcasting"? Commented Aug 11, 2014 at 19:49
  • @Dylan - I have not used filters int he controller before. But on your advice i just tried adding $filter to my controller and then filtering via $scope.oldCo = $filter('uniqueCompanies')($scope.companies, 'companyName') however $scope.oldCo was coming up empty. Am I doing this incorrectly? Commented Aug 11, 2014 at 20:01
  • 1
    @AndyMcCormick like this works - jsfiddle.net/devitate/zfx6sbdf Commented Aug 11, 2014 at 23:13

2 Answers 2

1

You are creating new objects in your filter with different properties so they will be different every time. You can you track by as mentioned by others. Since filters are executed every digest cycle you may want to set up a $watch and only create a new list of unique companies when your companies change. I actually get the 10 $digest() iterations reached error without doing this.

$scope.$watchCollection('companies', function(newValue) {
    $scope.filteredCompanies = $filter('uniqueCompanies')($scope.companies, 
        'companyName');
});

You could also set a watch on parentCompany and create the list of subsidiaries only when it changes, as well as clear out the value you have for subsidiaryCompany:

$scope.$watch('parentCompany', function(newValue) {
  $scope.subsidiaries = [];
  for (var i = 0; i < $scope.companies.length; i++) {
    var c = $scope.companies[i];
    if (c.companyID === newValue) {
      $scope.subsidiaries.push(c);
    }
  }
  $scope.subsidiaryCompany = undefined;
});
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this! I was concerned about the 10 $digest() iterations reached error, however most of the places I found talking about it online seemed to have the idea of 'just ignore it'. I tried adding the watch in the fiddle and it worked, however there seems to be another issue in my code as the fiddle that Dylan linked to works fine, however is not working in my actual app. I'll come back and mark this as best answer when I can officially say that it solves the problem. thanks
got it! this worked great and did get rid of the iterations reached error. I've been wanting to take a minute to understand how watchers worked and this was great to force me into when, where, and why to use them. thanks!
Glad it worked. It's worth noting the differences between $watch and $watchCollection if you're learning. Watch comparisons are done every $digest too, it might be better to set the uniqueCompanies in your getCompanies() function if they won't be modified. Since you're creating new objects too, $watchCollection won't catch differences to the objects' properties, if you change a company name for instance.
0

I may not be fully understanding you're issue here, but it looks like you could filter the data when you get it. Such as ...

function getCompanies(){
  $http.get("get.php?table=getcompanies").success(function(data) {
    $scope.companies = data.reduce(function (prev, cur) {
      // some code for skipping duplicates goes here                              
    }, []);
  });
}

Array.reduce may not be the best way to get a new array without duplicates, but that's the general idea, anyway.

1 Comment

thanks for the response. filtering when I get my data would not work as I still need all the subsidiaries no matter their parentCompany. I guess I could dump $scope.companies into an array and reduce that, and then pull from that for my companies list, but that seems to go around and defeat the purpose of using Angularjs.

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.