【问题标题】:Unable to access scope property set by $http.get in directive无法访问 $http.get 在指令中设置的范围属性
【发布时间】:2020-09-10 20:39:09
【问题描述】:

我正在使用这个 app.js 文件:

var myNinjaApp = angular.module('myNinjaApp', []);

myNinjaApp.directive('randomNinja', [function(){
  return {
    restrict: 'E',
    scope: {
      theNinjas: '=',
      title: '='
    },
    template: '<img ng-src="{{theNinjas[random].thumb}}"/>',
    controller: function($scope) {
      let length = $scope.theNinjas.length; //$scope.theNinjas is undefined
      $scope.random = Math.floor(Math.random() * length);
      console.log($scope.random);
    }
  };
}]);

myNinjaApp.controller('NinjaController', ['$scope', '$http', function($scope, $http) {  
    $http.get('data/ninjas.json').then(function(data){
      $scope.ninjas = data.data;
    });
}]);

还有这个 index.html 文件:

<!DOCTYPE html>
<html lang="en" ng-app="myNinjaApp">
  <head>
    <title>TheNetNinja Angular Playlist</title>
    <link href="content/css/styles.css" rel="stylesheet" type="text/css" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-route/1.7.9/angular-route.min.js"></script>
    <script src="app\app.js"></script>
  </head>
  <body ng-controller="NinjaController">  
    <random-ninja the-ninjas="ninjas" title="'Random Ninja'"></random-ninja>
  </body>
</html>

我注意到在指令的控制器代码中,$scope.theNinjas 未定义,但 title 未定义。

当我调试代码时,我可以看到在读取$scope.theNinjas.length 之后调用了$http.get()

如何获取指令控制器中数组的长度?

【问题讨论】:

    标签: javascript angularjs angularjs-directive angularjs-1.6


    【解决方案1】:

    你的问题是,$http.get 是异步的,

    $http.get('data/ninjas.json').then(function(data){
       $scope.ninjas = data.data;
    });
    

    因此,您会收到响应 a.e.延迟初始化$scope.ninjas

    您可以继续使用 2 个解决方案:

    [解决方案 1]

    ninjas不是undefined时,使用ng-if初始化指令

    <random-ninja 
      ng-if="ninjas"
      the-ninjas="ninjas" 
      title="'Random Ninja'">
    </random-ninja>
    

    [解决方案 2]

    $scope.theNinjas 的值与undefined 不同时,使用$watch 监听ninjas 更改并调用run 方法。之后,拨打unreg()停止手表

    let length = 0;
    
    var unreg = $scope.$watch(function () {
        return $scope.theNinjas;
    },
    function (newVal, oldVal) {
       if (newVal !== undefined) {
            run(newVal);
            unreg();
        }
     });
    
    
    function run(){
     length = $scope.theNinjas.length; 
      $scope.random = Math.floor(Math.random() * length);
      console.log($scope.random);
    }
    

    【讨论】:

    • 解决方案 1 效果很好 :) 甚至不需要尝试解决方案 2。
    • @DavidKlempfner 很高兴听到 :)
    【解决方案2】:

    另一种方法是使用$onChanges 生命周期钩子:

    myNinjaApp.directive('randomNinja', [function(){
      return {
        restrict: 'E',
        scope: {
          ̶t̶h̶e̶N̶i̶n̶j̶a̶s̶:̶ ̶'̶=̶'̶,̶ 
          theNinjas: '<',
          title: '<'
        },
        template: '<img ng-src="{{theNinjas[random].thumb}}"/>',
        controller: function($scope) {
          this.$onChanges = function(changesObj) {
            if (changesObj.theNinjas) {
              let length = changesObj.theNinjas.currentValue.length;
              $scope.random = Math.floor(Math.random() * length);
              console.log($scope.random);
            };
          };
        }
      };
    }]);
    

    theNinjas 绑定使用来自服务器的数据更新时,这将更新组件指令。

    注意:该指令需要使用单向 (&lt;) 绑定来实现此方法。

    来自文档:

    生命周期挂钩

    指令控制器可以提供以下方法,由 AngularJS 在指令的生命周期中调用:

    • $onChanges(changesObj) - 每当单向 (&lt;) 或插值 (@) 绑定更新时调用。 changesObj 是一个散列,其键是已更改的绑定属性的名称,值是{ currentValue, previousValue, isFirstChange() } 形式的对象。使用此钩子触发组件内的更新,例如克隆绑定值以防止外部值的意外突变。请注意,这也会在您的绑定初始化时调用。

    有关详细信息,请参阅

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-27
      • 2014-01-20
      • 1970-01-01
      • 2013-05-22
      • 2018-11-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-09
      相关资源
      最近更新 更多