将异步获取的数据传递给指令 [英] Passing asynchronously obtained data to a directive

查看:24
本文介绍了将异步获取的数据传递给指令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一个 AngularJS controller,它基本上通过 $http.get() 调用异步获取一些 JSON,然后链接获取数据到某个范围变量.

controller 代码的恢复版本:

mapsControllers.controller('interactionsController', ['$http', function($http) {var ctrlModel = this;$http.get("data/interactionsPages.json").成功(功能(数据){ctrlModel.sidebar = {};ctrlModel.sidebar.pages = 数据;}).错误(函数(){...});}]);

然后,我有一个自定义 directive,它通过 HTML 元素接收相同的范围变量.

指令代码的恢复版本:

mapsDirectives.directive('sidebar', function() {返回 {限制:'E',范围 : {页数:'@'},控制器:函数($scope){$scope.firstPage = 0;$scope.lastPage = $scope.pages.length - 1;$scope.activePage = 0;//...},链接:功能(范围){控制台日志(范围.页面);},templateURL : 'sidebar.html'}});

HTML 的恢复版本:

<div ng-controller='interactionsController asinteractionsCtrl'><mm-sidebar pages='{{interactionsCtrl.ctrlModel.sidebar.pages}}'></mm-侧边栏>

问题是,由于 $http.get() 是异步的,指令被错误地初始化(例如:$scope.pages.length - 1 是未定义).

我找不到任何可以为我解决此问题的方法,尽管提供了一些似乎可以解决此问题的解决方案.也就是说,我试图观察变量,只在检测到变化后初始化变量,正如许多其他帖子中所建议的那样.为了测试,我使用了类似的东西:

//... 指令的 return{ }链接:函数(){scope.$watch('pages', function(pages){如果(页)控制台日志(页);});}

我已经测试过了,$watch 函数没有被多次调用(记录的值为 undefined),我认为这意味着它没有检测到变量值.但是,我确认该值正在更改.

那么,这里有什么问题?

解决方案

移动控制器中 sidebar 对象的声明并将范围绑定更改为 =.

mapsDirectives.controller("interactionsController", ["$http", "$timeout",功能($http,$超时){var ctrlModel = this;ctrlModel.sidebar = {页数:[]};/*$http.get("data/interactionsPages.json").成功(功能(数据){//ctrlModel.sidebar = {};ctrlModel.sidebar.pages = 数据;}).错误(函数(){});*/$超时(功能(){//ctrlModel.sidebar = {};ctrlModel.sidebar.pages = ["一", "二"];}, 2000);}]);mapsDirectives.directive('mmSidebar', [function() {返回 {限制:'E',范围: {页数:'='},控制器:函数(){},链接:函数(范围,元素,属性,ctrl){scope.$watch("pages", function(val) {scope.firstPage = 0;scope.lastPage = scope.pages.length - 1;scope.activePage = 0;});},templateUrl: 'sidebar.html'};}]);

然后匹配指令名称并去掉大括号.

</mm-侧边栏>

这是一个工作示例:http://plnkr.co/edit/VP79w4vL5xiifEWqAUGI

I currently have an AngularJS controller that is basically getting some JSON asynchronously through a $http.get() call, then linking the obtained data to some scope variable.

A resumed version of the controller code:

mapsControllers.controller('interactionsController', ['$http', function($http) {
  var ctrlModel = this;

  $http.get("data/interactionsPages.json").
  success(function(data) {
    ctrlModel.sidebar = {};
    ctrlModel.sidebar.pages = data;
  }).
  error(function() {...});
}]);

Then, I have a custom directive which receives those same scope variables through a HTML element.

A resumed version of the directive code:

mapsDirectives.directive('sidebar', function() {
  return {
    restrict : 'E',
    scope : {
      pages : '@'
    },
    controller : function($scope) {            
      $scope.firstPage = 0;

      $scope.lastPage = $scope.pages.length - 1;

      $scope.activePage = 0;

      //...
    },
    link : function(scope) {
      console.log(scope.pages);
    },
    templateURL : 'sidebar.html'
  }
});

A resumed version of the HTML:

<body>
  <div ng-controller='interactionsController as interactionsCtrl'>
    <mm-sidebar pages='{{interactionsCtrl.ctrlModel.sidebar.pages}}'>
    </mm-sidebar>
  </div>
</body>

The problem is, since the $http.get() is asynchronous, the directive is being badly initialised (e.g: $scope.pages.length - 1 is undefined).

I couldn't find anything that solved this problem for me, although there are some presented solutions that would seem to solve the case. Namely, I tried to watch the variables, only initialising the variables after detected changes, as suggested in many other posts. For testing, I used something like:

//... inside the directive's return{ }
link: function() {
  scope.$watch('pages', function(pages){
    if(pages)
      console.log(pages);
  });
}

I've tested it, and the $watch function wasn't called more than once (the logged value being undefined), which, I assume, means it isn't detecting the change in the variable value. However, I confirmed that the value was being changed.

So, what is the problem here?

解决方案

Move the declaration for the sidebar object in the controller and change the scope binding to =.

mapsDirectives.controller("interactionsController", ["$http", "$timeout",
    function($http, $timeout) {
        var ctrlModel = this;
        ctrlModel.sidebar = {
            pages: []
        };
      /*
      $http.get("data/interactionsPages.json").
          success(function(data) {
          //ctrlModel.sidebar = {};
          ctrlModel.sidebar.pages = data;
       }).
       error(function() {});
      */

      $timeout(function() {
        //ctrlModel.sidebar = {};
        ctrlModel.sidebar.pages = ["one", "two"];
      }, 2000);
    }
]);

mapsDirectives.directive('mmSidebar', [function() {
    return {
      restrict: 'E',
      scope: {
        pages: '='
      },
      controller: function() {},
      link: function(scope, element, attrs, ctrl) {
        scope.$watch("pages", function(val) {
          scope.firstPage = 0;
          scope.lastPage = scope.pages.length - 1;
          scope.activePage = 0;
        });
      },
      templateUrl: 'sidebar.html'
    };
}]);

Then match the directive name and drop the braces.

<mm-sidebar pages='interactionsCtrl.sidebar.pages'>
</mm-sidebar>

Here's a working example: http://plnkr.co/edit/VP79w4vL5xiifEWqAUGI

这篇关于将异步获取的数据传递给指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆