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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38591685/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:37:42  来源:igfitidea点击:

Why are my component bindings undefined in its controller?

javascriptangularjsangularjs-1.5

提问by fikkatra

I'm writing a simple angular component. I'm passing a parameter as a binding and display its value on the screen. All works fine: I can see the parameter being displayed on the screen.

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

Component:

成分:

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>

However, when I try to access the binding from within the controller (see the console.log), the binding value is undefined. I don't understand how it can be available in the view, but not in the controller.

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

What am I doing wrong?

我究竟做错了什么?

Here's a plnkrillustrating the problem.

这是一个说明问题的plnkr

采纳答案by jusopi

When using angular's components, there is a point where the controller hasn't been wired up via the internal linking. If you're trying to do this in the constructor of your controller, you haven't been linkedto the bindings. The Component API exposes a few life-cycle hooks that you can define that will fire at certain times. You're looking for the $onInithook.

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

$onInit() - Called on each controller after all the controllers on an element have been constructed and had their bindings initialized (and before the pre & post linking functions for the directives on this element). This is a good place to put initialization code for your controller.

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

per docs - https://docs.angularjs.org/guide/component

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

回答by kolobok

Make sure you use hyphensfor bindings in HTML and camelCase for bindings in Javascript.

确保在 HTML 中使用连字符进行绑定,在 Javascript 中使用驼峰式大小写进行绑定。

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

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

That's what I always forget to do.

这就是我总是忘记做的事情。

回答by JohnnyCoder

The value for contactIdis available on the $scopein your controller:

的值在您的控制器中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>"
});

Link to another version of your Plunker here.

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

回答by Olivier Boissé

The keyword thisdoesn't seem to works with arrow function, this works with

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

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

When using arrow function, this, seems to refer to the window object because

使用箭头函数时,this似乎指的是 window 对象,因为

An arrow function does not create it's own this context, rather it captures the this value of the enclosing context

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

回答by hannad rehman

i will suggest some changes which you would really need to avoid these unusual bugs.

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

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>

some points :

几点:

  1. passing bindings to a component in html is always going to be kebab cased ex my-contact-id and its respective javascript variable will be cammal cased : myContactId.

  2. if you are passing the value insted of the object use '@' in bindings. if you are using an object and passing the object to bindigs use '<. if you want 2-way-binding to that object use '=' in the bindings config

  1. 将绑定传递到 html 中的组件总是会以 kebab 大小写 ex my-contact-id 并且其各自的 javascript 变量将是 cammal 大小写:myContactId。

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

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

回答by BratisLatas

Its maybe its not the best practice, but you have a easyer access to those values:

这可能不是最佳实践,但您可以更轻松地访问这些值:

$scope.$ctrl.contactId

You can get all the bindings in the property $ctrl inside the $scope.

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

I hope its help

我希望它的帮助

回答by Shovas

For those using Directives, where Components are assumed, if bindings{} is specified it appears adding those same parameters to scope{} works:

对于那些使用指令的人,其中假定组件,如果指定了 bindings{},则似乎将这些相同的参数添加到 scope 中:{}

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

*Discovered after I wrote the above that an additional scope parameter, foo, wasn't available on $scope until I assigned it from $scope.resolve. So I had to do this in $scope.init(): $scope.foo = $scope.resolve.foo. Not sure why. Guessing it has to do with my UI Bootstrap Modal + Directives usage

*在我写完上面的内容后发现,在我从 $scope.resolve 分配它之前,$scope 上没有一个额外的作用域参数 foo。所以我必须在 $scope.init() 中这样做:$scope.foo = $scope.resolve.foo。不知道为什么。猜测它与我的 UI Bootstrap Modal + Directives 用法有关

This may be obvious for others but wasn't for me being relatively new to AnguluarJS.

这对其他人来说可能很明显,但对我来说并不是 AnguluarJS 的新手。

My problem was using Directives with UI-Bootstrap Modals which are compatible with Directives but designed and documented for use with Components.

我的问题是将指令与 UI-Bootstrap Modals 一起使用,这些指令与指令兼容,但设计和文档化用于与组件一起使用。

回答by CoolestNerdIII

I am going to add another answer as a follow up to @jusopi and the accepted answer, just for those who may encounter my issue. In regards to the component, even after the $onInithook, my data was still null, as the value from the server was still not received. To counteract this (though there may be a better way to handle this situation), I also leveraged the $onChangeshook. $onChangeswill return the data that has changed when it is passed it, and you can parse that information, or simply call the binding as this.contactIdand it will be updated.

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

More details are provided in the documentation: https://docs.angularjs.org/guide/component

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

回答by Sotem

There are two problems with the code causing the "undefined" error.

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

  1. As stated above the $onInit lifecycle hook should first be reached, the onInit is fired when all bindings have been made.
  1. 如上所述,首先应该到达 $onInit 生命周期钩子,当所有绑定都完成后,onInit 被触发。

From the official documentation:AngularJs Documentation

来自官方文档:AngularJs 文档

$onInit() - Called on each controller after all the controllers on an element have been constructed and had their bindings initialized (and before the pre & post linking functions for the directives on this element). This is a good place to put initialization code for your controller.

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

  1. The second problem you will likely have, is that your controller will not reach the lifecyclehook when using "() =>" arrow notation as a parameter for the controller function.
  1. 您可能会遇到的第二个问题是,当使用“() =>”箭头符号作为控制器函数的参数时,您的控制器将无法到达生命周期钩子。

The problem being is that arrow notation won't have it's own scope, but rather use it's enclosing scope. Meaning that when using "this" will refer to the window object rather than the component. So calling this.$onInit() will be called on the window, and will not be fired, because it doesn't exist on the window.

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