Joe82
Joe82

Reputation: 1251

$scope.$watch with filtered scopes as output

This question is based in the answer provided here

I want to output the result from a lodash function applied to a scope ($scope.names) when another scope ($scope.switch) is set to true, and to output the result of that lodash function applied to a filtered scope when $scope.switch is set to false.

So my ng-repeat would be like this:

<ul>
    <li ng-repeat="things in (filtered=(names | filter:filterType))">{{things}}</li>
</ul>

I use two ng-click to change the state of $scope.switch and to apply/unapply the filter:

<a ng-click="switch = false; filterType=''">unswitch - No Filters</a><br><br>
<a ng-click="switch = true; filterType={name:'!Jimmy'}">switch - Not Jimmy</a>

And I used this code in order to watch the changes in $scope.switch:

$scope.$watch('switch', function() {
      $scope.thingScope =$scope.switch ? _.map($scope.names,"styles") : _.map($scope.filtered,"styles");
    });

Here is the working plunkr with all the code (it's much easier to notice the problem here)

The problem is that the output of $scope.thingScope doesn't correspond to the values showed in the ng-repeat (right now every time I click, it shows the values of the previous one, that is, it goes one step behind). Thanks in advance!

Upvotes: 0

Views: 268

Answers (2)

joseglego
joseglego

Reputation: 2109

Ok, I found few problems.

0 - You are working with a generated list element (Filtered. which is the result of apply the filter over names). When the switch change, the generated list is not finished. So, you will not find the elements.

1 - You have a lot of elements Trying to work over the same (the Swtich/Filter over names).

2 - You are showing using: $scope.thingScope = $scope.switch ? _.map($scope.names,"styles") : _.map($scope.filtered,"styles"); So, you are showing $scope.names when $scope.switch == true. So wrong conditional.

3 - You are applying first the change of the switch and then the filterType in the ng-click.

So, you can do 2 things.

  1. Work with duplicated filters in 2 places (Not recommended.)
  2. The ng-repeat work with the processed-list. And work all the filters in the controller. As @shaunhusain did it.

P.S. I think it could be cleaner with an active to filter. And not by Name, check this Plnkr: http://plnkr.co/edit/4uJ5AxP9xntgBe1hQrBW?p=preview

You can select by Name (only clicking) but you must click again in update filters to apply changes.

Upvotes: 2

shaunhusain
shaunhusain

Reputation: 19748

Think your logic in the view is getting to the slightly heavy and not making sense due to all the watching that goes on with things bound in the view... this is easier to solve if you instead do it procedurally.

http://plnkr.co/edit/ZExywkLtDxuT82Ud6gYl?p=preview

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="style.css">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
  </head>

  <body>
    <div ng-controller="myCtrl" ng-app="myApp">

      0. <b>Switch</b>: {{switch}} <br/><br/>
      1. <b>Output</b>: {{thingScope}} <br/><br/>
      2. <b>Filtered List</b>:
      <ul>
        <li ng-repeat="things in filtered">{{things}}</li>
      </ul>
      <a ng-click="changeSwitch(false, '')">unswitch - No Filters</a><br><br>
      <a ng-click="changeSwitch(true, {name:'!Jimmy'})">switch - Not Jimmy</a>
    </div>




    <script type="text/javascript">
      var app = angular.module('myApp', []);
      app.controller('myCtrl', function($scope, $filter) {
        $scope.switch = false;

        // set the default sort type
        $scope.filterType = '';

        var names=[{name:"Johny", styles:["one","two","three"]},{name:"Jimmy", styles:["two","three","four"]},{name:"Kevin", styles:["three","four","five"]}];

            // Option B:
        function filterData(searchObj){
          $scope.filtered = $filter('filter')(names, searchObj);
        };
        filterData();

        $scope.changeSwitch = function(newVal, filterType){
          $scope.switch = newVal;
          filterData(filterType);
          $scope.thingScope = !$scope.switch ? _.map(names,"styles") : _.map($scope.filtered,"styles");
        }

      });
    </script>
  </body>
</html>

Upvotes: 1

Related Questions