无法访问指令中 $http.get 设置的范围 属性

Unable to access scope property set by $http.get in directive

我正在使用这个 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 未定义。

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

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

你的问题是,$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>

[方案二]

使用 $watch 监听 ninjas 变化并在 $scope.theNinjas 的值不同于 undefined 时调用一些 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);
}

另一种方法是使用 $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 绑定使用来自服务器的数据更新时更新组件指令。

注意:该指令需要使用单向(<)绑定。

来自文档:

Life-cycle hooks

Directive controllers can provide the following methods that are called by AngularJS at points in the life-cycle of the directive:

  • $onChanges(changesObj) - Called whenever one-way (<) or interpolation (@) bindings are updated. The changesObj is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form { currentValue, previousValue, isFirstChange() }. Use this hook to trigger updates within a component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will also be called when your bindings are initialized.

有关详细信息,请参阅