0

I have two angularJS controllers that should be synchronized. The first is a filter on a list, second displays the list. I have a service user by both controllers and that makes some async ajax-like calls.

My problem is that the filter filters before the list is initialized, so when the page loads for the first time I have unfiltered results. How to solve it?

Here is my JSFiddle

Here is the code:

var myApp = angular.module('myApp', []);

myApp.controller("infoCtrl", function ($scope, $timeout, person) {
    person.get().then(function (response) {
        // timeout to prevent '$digest already in progress' error
        $timeout(function () {
            $scope.people = response;
            $scope.$apply();
        })
    });
});

myApp.controller("filterCtrl", function ($scope, person) {
    $scope.$watch("maxAge", function (newValue) {
        if (newValue) {
            person.filterPeople(newValue);
        }
    });
});

myApp.service("person", function ($q, $timeout) {
    var _me = this;
    var AjaxGetPeople = function () {
        return $timeout(function () {
            var somedata = [{name: 'Marcel Sapin',age: 26}, 
                            {name: 'Anhel De Niro',age: 42}, 
                            {name: 'Johny Resset',age: 30}];
            _me.people = somedata;
            return somedata;
        });
    };
    var filterPeople = function (maxAge, collection) {
        if (!collection) collection = _me.people;
        if (!collection) return;
        angular.forEach(collection, function (p) {
            p.visible = (p.age <= maxAge);
        });
    };
    var get = function () {
        if (_me.people) { // return from 'cache'
            return $q.resolve(_me.people);
        }
        // if not 'cached', call 'ajax'
        return AjaxGetPeople().then(function (response) {
            // add visible property to people
            filterPeople(100, response);
            _me.people = response;
            return response;
        });
    };

    return {
        'get': get,
            'filterPeople': filterPeople
    };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="filterCtrl" ng-init="maxAge=30">People younger than
    <input ng-model="maxAge" type="number" /> years:
</div>
<hr/>
<div ng-controller="infoCtrl">
    <div ng-repeat="person in people" ng-show="person.visible">
        {{person.name}}, age {{person.age}}
    </div>
</div>
 </div>

Anhel De Niro, age 42 should not be displayed when the page is loaded initially, because my filter's max age is 30...

serge
  • 13,940
  • 35
  • 121
  • 205
  • 1
    You should be using an angular filter like http://stackoverflow.com/questions/24081004/angularjs-ng-repeat-filter-when-value-is-greater-than, but I can't quite work out how to do it for oyu – Simon H Nov 25 '15 at 11:25
  • Actually currently you are complementing things .You can have one controller instead of two and custom filter – rupesh_padhye Nov 25 '15 at 11:29

2 Answers2

0

Well, try initialize like this:

var myApp = angular.module('myApp', []);

myApp.controller("infoCtrl", function ($scope, $timeout, person) {
    person.get(30).then(function (response) {
        // timeout to prevent '$digest already in progress' error
        $timeout(function () {
            $scope.people = response;
            $scope.$apply();
        })
    });
});

myApp.controller("filterCtrl", function ($scope, person) {
    $scope.$watch("maxAge", function (newValue) {
        if (newValue) {
            person.filterPeople(newValue);
        }
    });
});

myApp.service("person", function ($q, $timeout) {
    var _me = this;
    var AjaxGetPeople = function () {
        return $timeout(function () {
            var somedata = [{name: 'Marcel Sapin',age: 26}, 
                            {name: 'Anhel De Niro',age: 42}, 
                            {name: 'Johny Resset',age: 30}];
            _me.people = somedata;
            return somedata;
        });
    };
    var filterPeople = function (maxAge, collection) {
        if (!collection) collection = _me.people;
        if (!collection) return;
        angular.forEach(collection, function (p) {
            p.visible = (p.age <= maxAge);
        });
    };
    var get = function (init) {
        if (_me.people) { // return from 'cache'
            return $q.resolve(_me.people);
        }
        // if not 'cached', call 'ajax'
        return AjaxGetPeople().then(function (response) {
            // add visible property to people
            filterPeople(init, response);
            _me.people = response;
            return response;
        });
    };

    return {
        'get': get,
            'filterPeople': filterPeople
    };
});

Its work's in your JSFiddle, hope help you ;D

Javierif
  • 632
  • 1
  • 6
  • 18
  • I don't need to hardcode "30"... I need that maxAge be taken into consideration in ng-init – serge Nov 25 '15 at 16:24
0

Following Filter(ageFilter) will filter depending upon maxAge variable

HTML

<div ng-app='myApp' ng-controller="Main" ng-init="maxAge=30">
    <input type="text" ng-model="maxAge">
    <li ng-repeat="user in users | ageFilter:maxAge">{{user.name}}</li>
   </div>

Script

var myApp = angular.module('myApp', []);

myApp.filter('ageFilter', function() {
  return function(input, Maxage) {
    var out = [];
      for (var i = 0; i < input.length; i++){
          if(input[i].age <= Maxage)
              out.push(input[i]);
      }     
    return out;
  };
});

function Main($scope){

    $scope.users = [{name: 'Marcel Sapin',age: 26}, 
                            {name: 'Anhel De Niro',age: 42}, 
                            {name: 'Johny Resset',age: 30}]
}    
rupesh_padhye
  • 1,355
  • 2
  • 13
  • 25