1

I need to have a function in the scope which result will change asynchronously.

It's mandatory to have a function to be used as an expression, so I cannot use a single property.

In my example, the function returns a property of an object which will be modified asynchronously. This performs a digest error although the value is equal over the whole digest cycle. Here the example: http://plnkr.co/edit/YmyroMiMyMzUaLW4tc7V (Caution: it could hang your browser)

myApp.controller('Ctrl1', ['$scope', '$http',  function($scope, $http) {
    var myObj = {found:false};
    $scope.util = {};

    $scope.util.asyncFunc = function(){

      $http.get('http://localhost').then(changeValue,changeValue);

      return myObj.found;
    }

    function changeValue(){
      myObj.found = true;
    }
}]);

Any idea how to solve it?

  • 1
    How is that an asynchronous function? it will return false.... but after 2secs it will change the object reference `myObj.found` to true. In order to make it asynchronous, return a `$promise` from it. – Callum Linington Jun 08 '15 at 09:21
  • Can you show how the controller code is used in a template? What is bound? – Davin Tryon Jun 08 '15 at 09:29
  • You are doing killing thing simply. Every `$timeout` causes a `$digest()` and every `$digest()` re-evaluate all angular expressions which causes another` `$timeout` for your case and so on. Thats means it will simply reach `$digest()` iterations – Samir Das Jun 08 '15 at 09:48
  • @Samir , you are completely right. the '$timeout' causes a '$digest()'. Well, in my real problem what I do is an '$http.get', and I have the same problem. – Pablo Estornut Jun 08 '15 at 10:22
  • I changed the $timeout with an $http.get in the question and in the plunkr example: http://plnkr.co/edit/YmyroMiMyMzUaLW4tc7V , So, do you have an example of the good approach to achieve it working well? maybe with promises? – Pablo Estornut Jun 08 '15 at 10:49
  • Sorry I just saw your code. I was bit wrong in my first comment. `$timeout` or `$http` causes a `$digest()` but it would not be responsible for infinite `$digest` iteration. Main problem is changing value of an angular expression (i.e `ng-bind="iterations"`) inside another expression ( i.e. `{{util.asyncFunc()}}` ). $http by default return an promise, so your updated question code should be fine now. But your plnker code will create `$digest` iteration – Samir Das Jun 08 '15 at 12:08
  • I removed the "iterations" property which was wrong initially, sorry. With the $http.get seems that it does a $digest(), so it doesn't work. I have a solution which is using directly jquery.ajax, which does not do a digest, although it's ugly. I would like to solve it with a testeable code. Here is a similar problem: http://stackoverflow.com/questions/21935215/make-angularjs-skip-running-a-digest-loop-if-http-get-resulted-in-no-new-data . I will return here if I find a better solution. – Pablo Estornut Jun 08 '15 at 14:04

1 Answers1

0

I have a solution, the problem was that executing all the time $http.get, it creates promises which will be resolved at the same time. So, first I solve the problem by checking if the promise is already created. Afterwards in the callback of the promise I set my var which controls if teh promise is created to null, but I redefine the function doing a kind of bridge which returns the same value, to avoid executing $http.get in the same $digest: http://plnkr.co/edit/LOXDzVC4do2GTRtyNgSU

var myApp = angular.module('myApp', []);
//nueva 2015-06-09
myApp.controller('Ctrl1', ['$scope', '$http', '$q', function($scope, $http, $q) {
    var myObj = {found:false};
    $scope.util = {};
     var pro;
    $scope.util.asyncFunc = doGet;



    function doGet(param1, param2){
      if(!pro){
        pro = $http.get('http://localhost').then(changeValue,changeValue);
      }

      return myObj.found;

      function changeValue(){
        if(param1 !== "2"){
          myObj.found = true;
        }else{
          myObj.found = false;
        }


        $scope.util.asyncFunc = function(param1, param2){
          $scope.util.asyncFunc = doGet;
          pro = null;

          return myObj.found;
        }
    }
    }
}]);

and the html:

<body>
    <div ng-controller="Ctrl1">
          <br/><br/>
          Param1:<input type="text" ng-model="model.param1" />
          Param2:<input type="text" ng-model="model.param2" />

        AsyncFunc: {{util.asyncFunc(model.param1, model.param2)}}
    </div>

    <script src="http://code.angularjs.org/1.2.26/angular.js"></script>
    <script src="script.js"></script>
  </body>

Well, I think it's surely not the best solution, if you have other approach it would be very helpful.