【问题标题】:Render an AngularJS directive only after $scope.myVar is defined仅在定义 $scope.myVar 之后才呈现 AngularJS 指令
【发布时间】:2015-02-03 05:58:17
【问题描述】:

当我的 AngularJS “页面”加载时,我从服务器获取一些数据并将其设置为范围:

myApp.controller('somePage', ['$scope', 'User', '$routeParams', function($scope, User, $routeParams){

  // Get the user.
  User.get('1234').then(function(user){
    $scope.user = user;
  });

});

在我的页面上,我有一个需要定义 $scope.user 的指令。

<div>
  <user-profile-info></user-profile-info>
</div>

指令:

myApp.directive('addActionButton', function() {
  return {
    scope: false,
    link: function(scope, element, attrs){
      element.bind('click', function(){
        alert(scope.user.name);
      });
    },
    template: '<button id="foo">Say hi to {{ user.name }}</button>'
  };
})

现在页面在$scope.user定义之前渲染组件,所以有错误。

如何使该指令仅在 $scope.user 存在时呈现? 或者如何使我的页面视图仅在控制器完成获取其数据后呈现?

编辑:以上所有代码都已大大简化,因此您不必阅读额外信息 - 但仍然具有组件所需的约束(例如链接、带有属性的模板、带有 ajax 调用的范围)。

【问题讨论】:

  • 在 scope.user 上添加 watch 并查看 newvalue
  • 但是如果获取scope.user值需要5秒,那么组件在准备好之前仍然会被破坏。
  • 使用 ng-show 来隐藏无效值
  • @DonnyP 你能展示你的指令代码吗? @Ulterior,即使有一个包装 ng-show 元素,Angular 仍然会编译和链接指令;所以如果指令之前抛出异常,它仍然会抛出异常。但这是正确的想法,带有条件user !== undefinedng-if 应该可以解决问题,因为ng-if 将明确停止编译任何嵌套指令..
  • 我认为您更担心的是处理而不是渲染。您可以设置 2 路绑定并附加承诺,或者您可以使用事件来让指令知道开始,或者您可以在初始化指令过程之前对数据设置一次性监视。你的指令看起来如何?

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

ng-if 就是为了这个:

<user-profile-info ng-if="user"></user-profile-info>

看这个例子:


angular.module('myApp', [])
.controller('somePage', ['$scope', '$timeout', function($scope, $timeout){

  // Get the user
  // simulating delayed request, 3 secs
  $timeout(function(){
    $scope.user = {
      name: 'Shomz'
    };
  }, 3000);
  

}])
.directive('userProfileInfo', function() {
  return {
    restrict: 'E',
    link: function(scope, element, attrs){
      element.bind('click', function(){
        alert(scope.user.name);
      });
      alert(scope.user.name); // this would throw an error without ng-if
    },
    template: '<button id="foo">Say hi to {{ user.name }}</button>'
  };
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="somePage">
  <p ng-hide="user">Waiting for user data...</p>
  <user-profile-info ng-if="user">qwe</user-profile-info>
</div>

【讨论】:

  • @Shornz - 如果我希望 ng-if 等待多个模型,例如“用户”和“问题”,我该怎么做? ng-if="user &amp;&amp; question" 看起来很合理,但角度正确吗?
  • 感谢这项工作:) 让我在接受之前阅读 PSL 的答案
  • 不客气!没问题,@PSL 写了很棒的答案。
  • @DonnyP 我认为这可能是针对该指令的确切目的的精确答案,在编辑问题以包含该指令之前,我用所有选项编写了我的答案:)。这可能是一个问题,该指令应该如何自包含?用户应该担心在需要时放置 ng-if 还是指令可以自行处理? _shomz 我从来没有意识到......谢谢你:)
  • 是的,这里的问题就像@PSL 指出的关于自包含的问题。尽管如此,我还是在我的用例中使用了这个解决方案,并确保对其进行评论。手表、事件等往往会添加一些额外的代码和臃肿。老实说,对这两种解决方案都不满意。希望 Angular 可以为我们处理它,我想它会与生命挂钩事件一起处理。可悲的是旧版本:(
【解决方案2】:

我认为您更担心指令内部的处理过早而不是渲染指令。您可以设置 2 路绑定并附加承诺,或者您可以使用事件来让指令知道开始,或者您可以在初始化指令过程之前对数据设置一次性监视。所以基本思想不是直接在指令链接函数内部编写处理代码。将控制器关联到指令并在获得数据后触发指令控制器中的 init 函数也是一个好主意。

一个使用一次性和承诺方法的简单示例。

.directive('userProfileInfo', function($q){
   return{
     /*Your configuration*/,
     scope:{user:"="},
     link: function linker(scope, elm, attrs){
        /*
         Promise way
        */
         //Set up data or promise, q.when will make sure it is always a promise, be careful about not setting values like null etc..
         $q.when(scope.user).then(init);
        /*
          One time watch way
        */
        var unwatch = scope.$watch('user', function(user){
             if(angular.isDefined(user)){
                 unwatch(); //Remove the watch
                 init(); //initialize
             }
        });
        function init(){
           //Initialize directive processing accessing scope.user
        }
     }
   }
});

并将其绑定为:

<user-profile-info user="user"></user-profile-info>

如果您使用的是一次性手表,请保持代码不变,如果使用的是 Promise 方法。绑定承诺,即

在您的控制器中:

 $scope.userPromise = User.get('1234');

 <user-profile-info user="userPromise"></user-profile-info>

如果您担心根本不渲染指令,只需在指令元素上使用ng-if,只要您的指令优先级低于 ng-ifs,它就不会渲染。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-12
    • 1970-01-01
    • 2015-05-05
    • 2013-02-18
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多