javascript - Force refresh on nested function in Angular -


i'm complete beginner in angular(1.x) , i've been trying stitch app i'm developing.

it receives whole user data via ajax (multiple nested arrays) , proceeds render them using nested ng-repeat directives. in innermost repeat run function returns data based on current date.

<div ng-repeat="i in rootarray">    <div ng-repeat="h in i.array1">      <div ng-repeat="j in h.array2">        <span>{{datebasedfunction(j.data)}}</span>      </div>    </div>  </div>

the data function changes on time (even though input remains same), , want re run in order reflect changes without rendering whole structure again.

is possible? i'm not sure if i'm following best framework's practices, maybe there better approach?

thanks!

background

the ng-repeats aren't causing problems here. need focus on interpolation expression: {{datebasedfunction(j.data)}}

angular creating watcher dirty-check expression datebasedfunction(j.data) on each iteration of digest cycle. if resulting value has changed since last digest, dom updated new value.

the problem is, there's nothing in code triggering angular digest cycle.

working example

here can see situation working triggering digest manually via user interaction:

var myapp = angular.module('myapp', []);  myapp.controller('myctrl', ['$scope', myctrl]);    function myctrl($scope) {        $scope.rootarray = [{      "array1": [{        "array2": [{          "data": "hello"        }, {          "data": "world"        }]      }]    }];      //dummy $watch alerts whenever digest called    $scope.$watch(function() {      console.log('digest called');    });      $scope.datebasedfunction = function(x) {      var d = new date();      return x + ' (' + d.getminutes() + ":" + d.getseconds() + ")";    }  }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>    <div ng-app="myapp">    <div ng-controller="myctrl">        <button ng-click="">ng-click calls digest()</button>          <div ng-repeat="i in rootarray">        <div ng-repeat="h in i.array1">          <div ng-repeat="j in h.array2">            <span>{{datebasedfunction(j.data)}}</span>          </div>        </div>      </div>          </div>  </div>

every time click button, ng-click triggers angular digest. re-evaluates datebasedfunction. because value has changed, dom gets re-drawn.

but, i'm assuming don't want rely on ng-clicks keep dom updated. want dom update periodically, since changes in response current date/time.

possible solutions

  1. decide on frequency makes sense needs, , force digest cycle periodically:

var myapp = angular.module('myapp', []);  myapp.controller('myctrl', ['$scope', myctrl]);    function myctrl($scope) {        $scope.rootarray = [{      "array1": [{        "array2": [{          "data": "hello"        }, {          "data": "world"        }]      }]    }];      //dummy $watch alerts whenever digest called    $scope.$watch(function() {      console.log('digest called');    });      $scope.datebasedfunction = function(x) {      var d = new date();      return x + ' (' + d.getminutes() + ":" + d.getseconds() + ")";    }        //call $scope.$apply() every second.    setinterval(function() {      //$scope.$apply() triggers digest cycle      $scope.$apply();    }, 1000);  }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>    <div ng-app="myapp">    <div ng-controller="myctrl">          <div ng-repeat="i in rootarray">        <div ng-repeat="h in i.array1">          <div ng-repeat="j in h.array2">            <span>{{datebasedfunction(j.data)}}</span>          </div>        </div>      </div>          </div>  </div>

  1. if know frequency of updates, may consider writing directive directly updates dom @ right times, without calling apply() on whole scope. more efficient, require more development effort.

    this angular-moment am-time-ago directive. directive has similar goal: update data changes in response current date/time.

  2. use angular watch model changes, handle date/time-based changes outside of angular:

var myapp = angular.module('myapp', []);  myapp.controller('myctrl', ['$scope', myctrl]);    function myctrl($scope) {      $scope.rootarray = [{      "array1": [{        "array2": [{          "data": "hello"        }, {          "data": "world"        }]      }]    }];      //dummy $watch alerts whenever digest called    $scope.$watch(function() {      console.log('digest called');    });  }    function datebasedfunction(x) {    var d = new date();    return x + ' (' + d.getminutes() + ":" + d.getseconds() + ")";  }    setinterval(function() {    $('[data-date-based-value]').each(function() {      this.textcontent = datebasedfunction(this.dataset['datebasedvalue']);    });  }, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>    <div ng-app="myapp">    <div ng-controller="myctrl">        <div ng-repeat="i in rootarray">        <div ng-repeat="h in i.array1">          <div ng-repeat="j in h.array2">                      <!--set data-date-based-value attribute-->            <!--angular keep attribute value updated-->            <!--but element's text updated via jquery-->            <span ng-attr-data-date-based-value="{{j.data}}"></span>                      </div>        </div>      </div>      </div>  </div>

notice solution updates dom directly, without running additional digest cycles.

this article job of explaining digest cycle if you're interested in learning more angular.


Comments

Popular posts from this blog

python - Selenium remoteWebDriver (& SauceLabs) Firefox moseMoveTo action exception -

html - How to custom Bootstrap grid height? -

transpose - Maple isnt executing function but prints function term -