【问题标题】:How to wait for binding in Angular 1.5 component (without $scope.$watch)如何在 Angular 1.5 组件中等待绑定(没有 $scope.$watch)
【发布时间】:2016-06-08 22:38:46
【问题描述】:

我正在编写一个 Angular 1.5 指令,但在尝试在绑定数据存在之前对其进行操作时遇到了一个令人讨厌的问题。

这是我的代码:

app.component('formSelector', {
  bindings: {
    forms: '='
  },
  controller: function(FormSvc) {

    var ctrl = this
    this.favorites = []

    FormSvc.GetFavorites()
    .then(function(results) {
    ctrl.favorites = results
    for (var i = 0; i < ctrl.favorites.length; i++) {
      for (var j = 0; j < ctrl.forms.length; j++) {
          if (ctrl.favorites[i].id == ctrl.newForms[j].id) ctrl.forms[j].favorite = true
      }
     }
    })
}
...

如您所见,我正在进行 AJAX 调用以获取收藏夹,然后对照我的绑定表单列表检查它。

问题是,即使在绑定被填充之前,承诺就已经实现了......所以当我运行循环时, ctrl.forms 仍然未定义!

如果不使用 $scope.$watch(这是 1.5 组件吸引力的一部分),我如何等待绑定完成?

【问题讨论】:

  • 你试过 $timeout 吗?它可能会自行触发生命周期摘要。或者 $onInit

标签: javascript angularjs components


【解决方案1】:

我有一个类似的问题,我这样做是为了避免在我要发送的值准备好之前调用组件:

<form-selector ng-if="asyncValue" forms="asyncValue" ></form-selector>

【讨论】:

  • 这是一个优雅的解决方案。
  • @asiegfried 嗯,我同意你的观点,同时觉得这是一个 hack。应该有一个明确记录的解决方案。
【解决方案2】:

您可以使用新的生命周期挂钩,特别是$onChanges,通过调用isFirstChange 方法来检测绑定的第一次更改。阅读更多关于此here 的信息。

这是一个例子:

<div ng-app="app" ng-controller="MyCtrl as $ctrl">
  <my-component binding="$ctrl.binding"></my-component>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js"></script>
<script>
  angular
    .module('app', [])
    .controller('MyCtrl', function($timeout) {
      $timeout(() => {
        this.binding = 'first value';
      }, 750);

      $timeout(() => {
        this.binding = 'second value';
      }, 1500);
    })
    .component('myComponent', {
      bindings: {
        binding: '<'
      },
      controller: function() {
        // Use es6 destructuring to extract exactly what we need
        this.$onChanges = function({binding}) {
          if (angular.isDefined(binding)) {
            console.log({
              currentValue: binding.currentValue, 
              isFirstChange: binding.isFirstChange()
            });
          }
        }
      }
    });
</script>

【讨论】:

  • 太棒了!太感谢了。 Angular 现在处于一个奇怪的地方; 1.5 非常酷,对于从 1.3 或 1.4 开始的应用程序来说是一个非常好的选择......但是当您搜索 1.5 组件的帮助时,很难对所有 Angular 2 社区的讨论进行分类!
  • @HristoEnev 谢谢!你能告诉我具体是什么帮助了你吗?我正在考虑稍微改进一下答案,但我不确定要强调什么:我的自定义方法或 $onChanges() 钩子。
  • 您的自定义方法。我有两种方式绑定,我不知道为什么它在 $onInit 上未定义,所以我想知道如何处理它的绑定稳定性。这工作得很好。
  • 如果我们不知道绑定的类型会怎样?
  • @HristoEnev 如果你不知道它的类型,那么angular.isUndefined 就可以了。
【解决方案3】:

原发帖人说:

甚至在绑定被填充之前就已经实现了承诺... 当我运行循环时,ctrl.forms 仍然未定义

从 AngularJS 1.5.3 开始,我们就有 lifecycle hooks 并且为了满足 OP 的问题,您只需移动代码,这取决于 $onInit() 内部满足的绑定:

$onInit() - 在一个控制器上的所有控制器之后在每个控制器上调用 元素已经被构造并初始化了它们的绑定(和 在此指令的前后链接功能之前 元素)。这是放置初始化代码的好地方 控制器。

所以在示例中:

app.component('formSelector', {
  bindings: {
    forms: '='
  },
  controller: function(FormSvc) {
    var ctrl = this;
    this.favorites = [];

    this.$onInit = function() {
      // At this point, bindings have been resolved.
      FormSvc
          .GetFavorites()
          .then(function(results) {
            ctrl.favorites = results;
            for (var i = 0; i < ctrl.favorites.length; i++) {
              for (var j = 0; j < ctrl.forms.length; j++) {
                if (ctrl.favorites[i].id == ctrl.newForms[j].id) {
                  ctrl.forms[j].favorite = true;
                }
              }
            }
          });
    }
}

所以是的,有一个$onChanges(changesObj),但$onInit() 专门解决了最初的问题,即我们什么时候可以保证绑定已经解决。

【讨论】:

  • 我需要从组件的模板中获取一个
    ,但是在 $onInit() 方法中,表单是未定义的。如果我在 $timeout (100ms) 内访问它,那么我可以正确获取它。我不喜欢这种方法,但访问 $onInit() 中的表单对我不起作用,因为似乎并非所有绑定都已解决。
  • onInit 不保证已解析绑定。见这里:javascript.qahowto.com/… 看起来是同一个问题。 OnChanges 是要走的路,这意味着如果您需要您的代码等待有效的绑定,那么您需要在 onChanges 中检查它。
  • 我认为这个答案适用于 1.6 而不是 1.5。 $onInit 不保证绑定已在 1.5 中解析,而 1.6 则可以。
【解决方案4】:

我遇到了类似的问题,我发现这篇文章很有帮助。 http://blog.thoughtram.io/angularjs/2016/03/29/exploring-angular-1.5-lifecycle-hooks.html

我有一个 ajax 调用,它在页面加载时访问服务器,我的组件需要 ajax 返回值才能正确加载。我是这样实现的:

this.$onChanges = function (newObj) {
      if (newObj.returnValFromAJAX)
        this.returnValFromAJAX = newObj.returnValFromAJAX;
    };

现在我的组件可以完美运行了。作为参考,我使用的是 Angular 1.5.6

【讨论】:

  • 您的组件中是否嵌入了 ajax 调用?或者您只是将结果作为绑定传递?
猜你喜欢
  • 2017-03-21
  • 2017-08-23
  • 2016-09-10
  • 2016-09-12
  • 2017-01-24
  • 2016-10-30
  • 2016-07-25
  • 2015-12-11
  • 2017-05-10
相关资源
最近更新 更多