Angularjs binding value from async service

2019-08-21 09:37发布

Having resolved a couple of errors thanks to @sehaxx in Angularjs binding value from service I would like introduce async in the example as in the following code where a variable is initialized asynchronously and it's value is not reflected in the view.

(function(angular) {
  'use strict';
angular.
module('myServiceModule', []).
  controller('MyController', ['$scope', 'notify','$log', function($scope, notify, $log) {
    this.clickCount = 0;
    this.clickLimit = notify.clickLimit();
    this.callNotify = function(msg) {
        notify.push(msg);
        this.clickCount = notify.clickCount();
        $log.debug("[controller] Click count is now", this.clickCount, " and limit is ", this.clickLimit);
    };

  }]).
factory('notify', ['$window','$log', '$timeout', function(win,$log, $timeout) {
    var msgs = [];
    var clickCounter = 0;
    var countLimit = 0;

    $timeout( function(){
      countLimit = Math.floor(Math.random() * 10)+1;
      $log.debug("[service] Click limit initialized at", countLimit);
      return countLimit;
    }, 10);

    return {
        clickLimit: function(){
          return countLimit;
        },
        clickCount: function() {
            clickCounter = msgs.length;
            $log.debug("[service] You are clicking, click count is now", clickCounter, " limit is ", countLimit);
            return clickCounter;
          },
        push: function(msg) {
              msgs.push(msg);
              clickCounter = msgs.length;
              $log.debug("[service] Counter is", clickCounter, " on ", countLimit);
              if (msgs.length === countLimit) {
                win.alert(msgs.join('\n'));
                msgs = [];
              }
            }
      }
  }]);
})(window.angular);

Working example in pen

1条回答
太酷不给撩
2楼-- · 2019-08-21 10:17

The reason this isn't working as expected is due to the fact that countLimit is a Primitive, and Primitives are always passed byVal rather than byRef, so there is no way for the factory to update the value at a later date.

Changing the countLimit to an Object fixes this, because the value of the Object is the Reference to the properties of the Object. In other words, we are able to pass byRef. We just have to update our code to refer to the Object's child property instead of referring to the value directly, i.e. countLimit.value.

working example: https://codepen.io/anon/pen/VVmdbE?editors=1111

(function(angular) {
  'use strict';
  angular.
  module('myServiceModule', []).
  controller('MyController', ['$scope', 'notify', '$log', function($scope, notify, $log) {
    this.clickCount = 0;
    this.clickLimit = notify.clickLimit();
    this.callNotify = function(msg) {
      notify.push(msg);
      this.clickCount = notify.clickCount();
      $log.debug("[controller] Click count is now", this.clickCount, " and limit is ", this.clickLimit.value);
    };

  }]).
  factory('notify', ['$window', '$log', '$timeout', function(win, $log, $timeout) {
    var msgs = [];
    var clickCounter = 0;
    var countLimit = {
      value: 0,
    };

    $timeout(function() {
      countLimit.value = Math.floor(Math.random() * 10) + 1;
      $log.debug("[service] Click limit initialized at", countLimit.value);
      return countLimit;
    }, 10);

    return {
      clickLimit: function() {
        $log.debug("called clickLimit");
        return countLimit;
      },
      clickCount: function() {
        clickCounter = msgs.length;
        $log.debug("[service] You are clicking, click count is now", clickCounter, " limit is ", countLimit);
        return clickCounter;
      },
      push: function(msg) {
        msgs.push(msg);
        clickCounter = msgs.length;
        $log.debug("[service] Counter is", clickCounter, " on ", countLimit);
        if (msgs.length === countLimit.value) {
          win.alert(msgs.join('\n'));
          msgs = [];
        }
      }
    }
  }]);
})(window.angular);
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Example - example-services-usage-production</title>


  <script src="https://code.angularjs.org/snapshot/angular.min.js"></script>
  <script src="script.js"></script>



</head>

<body ng-app="myServiceModule">
  <div id="simple" ng-controller="MyController as self">
    <p>Let's try this simple notify service, injected into the controller...</p>
    <input ng-init="message='test'" ng-model="message">
    <button ng-click="self.callNotify(message);">NOTIFY</button>
    <p>(you have to click {{self.clickLimit.value-self.clickCount}} times more to see an alert)</p>
    <div>You have clicked {{ self.clickCount }} times</div>
  </div>

</body>

</html>

查看更多
登录 后发表回答