dalvarezmartinez1
dalvarezmartinez1

Reputation: 1405

Angular elements bound to same function. Avoid multiple call on each digest

Given the following:

<div data-ng-repeat="val in vals">
      <div data-ng-class:{'myClass':isEngineOn(val)}>
          <span data-ng-show="isEngineOn(val)">yeah it's on</span>
          <span data-ng-show="!isEngineOn(val)"> standby</span>
          <button data-ng-disabled="isEngineOn(val)">Start engine</button>
      <div>
</div>

isEngineOn changes with websocket messages I receive from the server.

Is there a way to avoid evaluating isEngineOn, 4 times during each digest, per each value in the repeat? Something like initializing a variable or something?

Upvotes: 0

Views: 370

Answers (3)

Pascal Ockert
Pascal Ockert

Reputation: 984

You can do that with simple CSS and without calling the function in the spans. I think thats much more efficient than a JavaScript solution, especially when you have a repeat over many elements because you can save bindings:

<div data-ng-repeat="val in vals">
    <div data-ng-class:{'myClass':isEngineOn(val)}>
        <span class="showWhenOn">yeah it's on</span>
        <span class="showWhenOff"> standby</span>
        <button onclick="alert('Starting...')">Start engine</button>
    </div>
</div>

CSS:

.showWhenOn {
    display: none;
}

.myClass .showWhenOn {
    display: inline;
}

.myClass .showWhenOff {
    display: none;
}

.myClass button {
    pointer-events: none;
    color: silver;
}

JS Fiddle

Upvotes: 1

Omri Aharon
Omri Aharon

Reputation: 17064

Yes, just have a variable in the controller that holds the result, and update that variable when you receive an update from the server:

In your controller:

$scope.engineOn = isEngineOn();//also make sure to update from server whenever you need

Note that if your isEngineOn() function is no longer called from the view it doesn't need to be on the scope, it can be declared as a regular variable.

HTML:

<div data-ng-class="{'myClass':engineOn}">
      <span data-ng-show="engineOn">yeah it's on</span>
      <span data-ng-show="!engineOn"> standby</span>
<div>

EDIT 2: The ng-init, as you said, did not update on digest so I've taken a second approach.

I've taken the long way round, and created a corresponding array for your values and you can read from that:

  <div data-ng-repeat="val in vals" >
      <div data-ng-class="{'myClass':enginOn[val]}">
          <span data-ng-show="engineOn[val]">yeah it's on</span>
          <span data-ng-show="!engineOn[val]"> standby</span>
          <button data-ng-disabled="isEngineOn(val)">Start engine</button>
      </div>
</div>

Fiddle.

Upvotes: 0

karaxuna
karaxuna

Reputation: 26940

You can set watcher to variable that changes when you receive answer from server, for example:

scope.$watch(function(){ return <var that changes>; }, function(oldv, newv){
    if(oldv !== newv)
        scope.isEngineOn = <Calculate here>;
});

Then use:

<span data-ng-show="isEngineOn">

Upvotes: 0

Related Questions