为什么我的组件绑定在其控制器中未定义?


70

我正在写一个简单的角度分量。我将参数作为绑定传递并在屏幕上显示其值。一切正常:我可以看到该参数显示在屏幕上。

零件:

var app = angular.module("test", []);
app.component("test", {
  bindings: {
    "contactId": "<"
  },
  controllerAs: "model",
  controller: () => {
    //output: 'contact id from controller: undefined'
    console.log(`contact id from controller: ${this.contactId}`);
  },
  template: "<div>Contact id from view: {{model.contactId}}</div>"
});

HTML:

<test contact-id="8"></test>

但是,当我尝试从控制器内部访问绑定时(请参阅console.log),绑定值为undefined。我不明白如何在视图中使用它,但在控制器中却不可用。

我究竟做错了什么?

这是说明问题的plnkr


2
我缺少一些简单的东西。为什么“ contactId”用引号引起来?
Winnemucca

Answers:


60

使用angular的组件时,有时还没有通过内部链接将控制器连接起来。如果试图在控制器的构造函数中执行此操作,则尚未链接到绑定。Component API公开了一些生命周期挂钩,您可以定义这些挂钩在特定时间触发。您正在寻找$onInit钩子。

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

每个文档-https: //docs.angularjs.org/guide/component


1
我认为你是对的,$onInit应该使用。这对我有用:`var vm = this; vm。$ onInit = function(){console.log('在init上加载'); console.log('vm',vm.YOUR_BINDING); console.log('def yes?',angular.isDefined(vm.YOUR_BINDINGj)); }; `
逸出的猫'17

6
在某些情况下,您的绑定可以稍后进行更新,并且在$onInit调用该挂钩时,绑定的值尚未准备好。在这种情况下,您应该使用$onChanges并跳过第一个更改。工作示例:jsfiddle.net/auxcoder/4hq5gaq0
aUXcoder '17

3
@aUXcoder这是我的问题。我试图在绑定到组件的数据准备就绪之前创建组件。放置一个ng-if指令以确保在初始化组件之前(例如<custom-component ng-if="!$ctrl.data" data="$ctrl.data"></custom-component>)我拥有数据,从而解决了该问题。
Xchai

“ ...在一个元素上的所有控制器都构建好之后”,这是否意味着一个组件可以通过一次使用组件标签来拥有多个控制器?有例子吗?
Buksy

@Buksy我认为它们的意思是,对于一个给定的HTML元素,该元素可能与某个组件相对应,也可能不与某个组件相对应,在其上可以有多个指令。例如<custom-component ng-model="" nx-save=""></>。在这种情况下,您只有一个元素,包括一个组件控制器,一个ngModelController和其他可能具有控制器的指令。
jusopi

32

确保在HTML中使用连字号进行绑定,在Javascript中使用camelCase进行绑定。

app.component("test", {
  bindings: {
    "myContactId": "<"
  }
}

<test my-contact-id="8"></test>

那就是我总是忘记做的事。


1
作为参考,以及一些可能会咬你的特殊情况:docs.angularjs.org/guide/directive#normalization
jfroy

7

的值contactId$scope在您的控制器中使用:

var app = angular.module("test", []);
app.component("test", {
  bindings: {
    "contactId": "<"
  },
  controllerAs: "model",
  controller: ($scope) => {
    var model = $scope.model;
    alert(`contact id from controller: ${model.contactId}`);
  },
  template: "<div>Contact id from view: {{model.contactId}}</div>"
});

在此处链接到您的Plunker的另一个版本。


1
为什么在使用箭头功能样式时不能使用此关键字?
奥利维尔·布瓦西(OlivierBoissé)2016年

您可以使用this箭头函数样式,但是this.contactId由于@jusopi提到的原因,我认为在这种情况下尚不可用。如果您有API方法,例如someController.prototype.someMethod,则this应该具有您所期望的。如@jusopi所述,执行顺序不会this按预期在构造函数(非原型)中填充。
用户1058612 '16

1
我尝试超时,但不起作用。就像我在上面说的,箭头函数不会创建它自己的上下文,而是捕获封闭上下文的this值。因此,使用箭头功能时,它是指窗口对象,而不是控制器。
奥利维尔·布瓦西(OlivierBoissé)2016年

有趣。我没有意识到-谢谢!在这种情况下,无论函数语法如何,$scope注入都将解决OP所要求的问题。
用户1058612 '16

7

关键字this似乎不适用于箭头功能,而与

controller: function() {
   alert('contact id from controller: ' + this.contactId);
}

使用箭头功能时,this似乎是指窗口对象,因为

箭头函数不会创建它自己的上下文,而是捕获封闭上下文的this值


5

我将建议一些更改,这些更改是您真正需要避免这些异常错误的。

app.component("test", {
  bindings: {
    "myContactId": "<"
  },
  controller:function(){
   var self=this;
   this.$onInit=function(){
    // do all your initializations here.
    // create a local scope object for this component only. always update that scope with bindings. and use that in views also.

       self.myScopeObject=self.myContactId
   }
  },
   template:'<p>{{$ctrl.myScopeObject}}</p>'
 }

<test my-contact-id="8"></test>

一些要点:

  1. 将绑定传递到html中的组件总是要经过mybaby-case my-contact-id进行的,而其相应的javascript变量将为cammal cased:myContactId。

  2. 如果要传递对象的值,请在绑定中使用“ @”。如果您正在使用一个对象并将该对象传递给绑定,请使用'<。如果要对该对象进行2次绑定,请在绑定配置中使用'='

 bindings:{
      value:'@',
      object:'<', // also known as one-way
      twoWay:'='
    }

2

也许这不是最佳做法,但是您可以更轻松地访问这些值:

$scope.$ctrl.contactId

您可以在$ scope的$ ctrl属性中获取所有绑定。

希望对您有所帮助


0

对于那些使用伪指令的人(假定使用组件),如果指定bindings {},则将那些相同的参数添加到scope {}的工作似乎是:

/*bindings: {
    modalInstance: '<',
    resolve: '<'
},*/
scope: {
    modalInstance: '<',
    resolve: '<'
},

*在我写完上面的内容后发现,在我从$ scope.resolve分配它之前,在$ scope上没有可用的附加范围参数foo。因此,我必须在$ scope.init()中执行此操作:$ scope.foo = $ scope.resolve.foo。不知道为什么。猜猜这与我的UI Bootstrap Modal + Directives使用有关

这对于其他人可能是显而易见的,但是对我而言,对于AnguluarJS而言并不是一个新手。

我的问题是使用带有UI-Bootstrap Modals的指令,这些指令与指令兼容,但已设计并记录为可与组件一起使用。


0

我将为@jusopi和接受的答案添加另一个答案,仅供可能遇到我问题的人使用。关于组件,即使经过$onInit钩子,我的数据仍然为空,因为仍未收到来自服务器的值。为了解决这个问题(尽管可能有更好的方法来处理这种情况),我也利用了$onChanges挂钩。$onChanges会在传递时返回已更改的数据,您可以解析该信息,也可以简单地将其称为this.contactId,它将被更新。

文档中提供了更多详细信息:https : //docs.angularjs.org/guide/component


0

代码有两个问题,导致“未定义”错误。

  1. 如上所述,应该首先到达$ onInit生命周期钩子,在完成所有绑定后会触发onInit。

从官方文档:AngularJs文档

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

  1. 您可能遇到的第二个问题是,使用“()=>”箭头符号作为控制器功能的参数时,控制器将无法达到生命周期挂钩。

问题在于箭头表示法没有它自己的作用域,而是使用它的封闭范围。意味着使用“ this”时将引用窗口对象而不是组件。因此调用this。$ onInit()将在窗口上调用,并且不会被触发,因为它在窗口上不存在。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.