在Angular中强制刷新嵌套函数

时间:2017-07-26 09:33:03

标签: javascript angularjs arrays

我是Angular(1.x)的初学者,我一直试图将其拼接到我目前正在开发的应用中。

它基本上通过ajax(多个嵌套数组)接收整个用户数据,然后使用嵌套的ng-repeat指令继续渲染它们。在最里面的重复中,我运行一个函数,该函数根据当前日期返回数据。



<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>
&#13;
&#13;
&#13;

函数中的数据会随着时间的推移而变化(即使输入保持不变),我希望它能够重新运行以反映这些变化,而无需再次渲染整个结构。

有可能吗?我不确定我是否遵循最佳框架的做法,也许有更好的方法?

谢谢!

1 个答案:

答案 0 :(得分:0)

<强>背景

ng-repeats在这里没有引起任何问题。我们需要关注interpolation expression{{dateBasedFunction(j.data)}}

Angular正在watcher创建一个digest来检查angular-moment周期的每次迭代中的表达式dateBasedFunction(j.data)。如果自上次摘要以来结果值已更改,则将使用新值更新DOM。

问题是,代码中没有任何内容触发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 is 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>

每次单击该按钮,ng-click都会触发Angular摘要。这会重新评估dateBasedFunction。由于值已更改,因此DOM将重新绘制。

但是,我假设您不想依赖ng-click来更新DOM。您希望DOM定期更新,因为它会根据当前日期/时间而更改。

可能的解决方案

  1. 确定一个对您的需求有意义的频率,并定期强制消化周期:
  2. 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 is 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 a 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. 如果您知道更新的频率,您可以考虑编写一个在适当的时间直接更新DOM的指令,而不需要在整个范围内调用apply()。这将更有效,但需要更多的开发工作。

      这正是am-time-ago directiveThis article所做的事情。该指令具有类似的目标:更新响应当前日期/时间而变化的数据。

    2. 使用Angular观察模型是否有任何变化,但在Angular之外处理基于日期/时间的更改:

    3. 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 is 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 a data-date-based-value attribute-->
                <!--Angular will keep the attribute value updated-->
                <!--But the element's text will be updated via jQuery-->
                <span ng-attr-data-date-based-value="{{j.data}}"></span>
                
              </div>
            </div>
          </div>
      
        </div>
      </div>

      请注意,此解决方案直接更新DOM,而不运行其他摘要周期。

      如果您有兴趣了解有关Angular的更多信息,

      this可以很好地解释摘要周期。