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.
What am I doing wrong?
Here's a plnkr illustrating the problem.
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 linked to 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 $onInit
hook.
$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.
per docs - https://docs.angularjs.org/guide/component
Make sure you use hyphens for bindings in HTML and camelCase for bindings in Javascript.
app.component("test", {
bindings: {
"myContactId": "<"
}
}
<test my-contact-id="8"></test>
That's what I always forget to do.
The value for contactId
is available on the $scope
in your controller:
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.
The keyword this doesn't seem to works with arrow function, this works with
controller: function() {
alert('contact id from controller: ' + this.contactId);
}
When using arrow function, this, seems to refer to the window object because
An arrow function does not create it's own this context, rather it captures the this value of the enclosing context
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 :
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.
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
bindings:{ value:'@', object:'<', // also known as one-way twoWay:'=' }
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.
I hope its help
There are two problems with the code causing the "undefined" error.
From the official documentation:AngularJs Documentation
$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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With