Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Update a Parent Scope Variable from within ng-repeat Expression?

I've run into a situation where I had to update a scope variable from within an ng-repeat expression (ng-class call within ng-repeat in fact).

<div id="page" ng-controller="MainCtrl">
.
 <section id="body" ng-init="countMis = {num:0}">
.
<tbody>
  <tr ng-repeat="upperCaseLetter in alphabet.specialsUpper" ng-controller="letterController">
    <td>{{upperCaseLetter}}</td>
    <td>{{filteredLetter=(upperCaseLetter | lowercase)}}</td>
    <td>{{alphabet.specialsLower[$index]}}</td>
    <td><span ng-class="lowercaseEqual($index,filteredLetter)"></span></td>
  </tr>
</tbody>

and in app.js:

function letterController($scope)
{
    $scope.lowercaseEqual = function(indx,letter)
    {       
        var returnStr="";

        if(letter == $scope.alphabet.specialsLower[indx])
        {
             returnStr = "glyphicon glyphicon-ok";
        }
        else
        {   
            $scope.countMis.num = $scope.countMis.num + 1;
            returnStr = "glyphicon glyphicon-remove";
        }

        return returnStr;
    };

}

Example App Screenshot

Ng-repeat is in a child controller and data I want to update is in its parent controller. I know you've read same question many times, please keep reading and see JsFiddle example.

So expression function checks filtered data of that particular ng-repeat iteration, if it doesn't match with some other corresponding parent scope variable it returns a class but also it should update parent scope counter. As those expressions don't evaluate just once, but at least once (because of dirty check in digest) it results counter being incremented more than once for each case.

I've solved my problem by counting classes applied to that particular data after ng-repeat (you'll see in the JsFiddle example). However I think I may run into same problem in the future, so I want to learn how to update parent scope within an expression of ng-repeat iteration.

I've put a second JsFiddle, I've tried using a factory on both parent controller and child, hoping to update a common variable for both controllers. When I log (consol.log) each iteration and factory method variable, it shows iteration times + 1 (still false value), but it's not reflected on page expression...doesn't make sense at all.

I'd appreciate any help. Thanks.

JsFiddle 1 JsFiddle 2

like image 950
Bogac Avatar asked Nov 10 '22 10:11

Bogac


1 Answers

Since watched expressions (like the one implicitely set up by the ng-class directive) "can execute multiple times per $digest() and should be idempotent". You should understand what the $watch() and $digest() functions do and look for resources regarding Angular's digest cycle.

So, incrementing a counter inside a watchExpression is not a good idea.
Counting classes seems ok though.


BTW, the factory-approach will help you share data across scopes, but it won't help with the "multiple executions per digest cycle" problem. Furthermore, it might be redundant in your situation, since the child- and parent-scopes can share data directly.
In any case, for the results to be displayed you have to "bind" the factory's getMismatchCount() function with the getMismatchCount() function that you use in your HTML (in Mismatches Count from Factory: {{getMismatchCount()}}):

function mainCtrl($scope, $window, repeatFactory)
    ...
    $scope.getMismatchCount = repeatFactory.getMismatchCount;
like image 135
gkalpak Avatar answered Nov 14 '22 21:11

gkalpak