Почему привязки моего компонента не определены в контроллере?
Я пишу простой компонент angular. Я передаю параметр в качестве привязки и отображаю его значение на экране. Все работает нормально: я вижу, что параметр отображается на экране.
компонент:
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, иллюстрирующий проблему.
Ответы
Ответ 1
При использовании компонентов angular существует точка, в которой контроллер не был подключен через внутреннее соединение. Если вы пытаетесь сделать это в конструкторе вашего контроллера, вы не связаны с привязками. API-интерфейс Component предоставляет несколько крючков жизненного цикла, которые вы можете определить, которые будут срабатывать в определенное время. Вы ищете крюк $onInit
.
$onInit() - вызывается на каждом контроллере после того, как все контроллеры на элементе были построены и инициализированы их привязки (а также перед функциями предзапуска и пост-ссылок для директив этого элемента). Это хорошее место для ввода кода инициализации для вашего контроллера.
per docs - https://docs.angularjs.org/guide/component
Ответ 2
Убедитесь, что вы используете дефис для привязок в HTML и camelCase для привязок в Javascript.
app.component("test", {
bindings: {
"myContactId": "<"
}
}
<test my-contact-id="8"></test>
То, что я всегда забываю делать.
Ответ 3
Значение 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 здесь.
Ответ 4
Ключевое слово this, похоже, не работает со стрелкой, это работает с
controller: function() {
alert('contact id from controller: ' + this.contactId);
}
При использовании функции стрелки этот, похоже, относится к объекту window, потому что
Функция стрелки не создает в ней этого контекста, а скорее фиксирует это значение охватывающего контекста
Ответ 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>
несколько точек:
-
Передача привязок к компоненту в html всегда будет иметь кебаб с ex-my-contact-id, а его соответствующая переменная javascript будет работать с камнем: myContactId.
-
если вы передаете значение, указанное в объекте, используйте "@" в привязках.
если вы используете объект и передаете объект в bindigs, используйте '<.
если вы хотите, чтобы 2-сторонняя привязка к этому объекту использовала '=' в конфигурации привязок
bindings:{
value:'@',
object:'<', // also known as one-way
twoWay:'='
}
Ответ 6
Возможно, это не лучшая практика, но у вас есть более легкий доступ к этим значениям:
$scope.$ctrl.contactId
Вы можете получить все привязки в свойстве $ctrl внутри области $scope.
Я надеюсь, что его помощь
Ответ 7
Для тех, кто использует Директивы, где предполагается использование Компонентов, если указана привязка {}, появляется добавление тех же параметров в область действия {}:
/*bindings: {
modalInstance: '<',
resolve: '<'
},*/
scope: {
modalInstance: '<',
resolve: '<'
},
* Обнаружил после того, как я написал выше, что дополнительный параметр области, foo, не был доступен в $ scope, пока я не назначил его из $ scope.resolve. Поэтому я должен был сделать это в $ scope.init(): $ scope.foo = $ scope.resolve.foo. Не уверен почему. Предполагаю, что это связано с использованием моего UI Bootstrap Modal + Directives
Это может быть очевидно для других, но я не был относительно новым для AnguluarJS.
Моя проблема заключалась в использовании директив с модальностями UI-Bootstrap, которые совместимы с директивами, но разработаны и задокументированы для использования с компонентами.
Ответ 8
Я собираюсь добавить еще один ответ в качестве продолжения @jusopi и принятый ответ, только для тех, кто может столкнуться с моей проблемой. Что касается компонента, даже после $onInit
мои данные были все еще нулевыми, поскольку значение от сервера все еще не было получено. Чтобы противодействовать этому (хотя может быть лучший способ справиться с этой ситуацией), я также использовал хук $onChanges
. $onChanges
вернет данные, которые изменились, когда они были переданы, и вы можете проанализировать эту информацию или просто вызвать привязку как this.contactId
и она будет обновлена.
Более подробная информация представлена в документации: https://docs.angularjs.org/guide/component
Ответ 9
Есть две проблемы с кодом, вызывающие "неопределенную" ошибку.
- Как указывалось выше, сначала должен быть достигнут хук жизненного цикла $ onInit, onInit запускается, когда все привязки выполнены.
Из официальной документации: AngularJs Documentation
$ onInit() - вызывается на каждом контроллере после того, как все контроллеры в элементе были сконструированы и инициализированы их привязки (и до функций связывания pre и post для директив этого элемента). Это хорошее место, чтобы поместить код инициализации для вашего контроллера.
- Вторая проблема, с которой вы, вероятно, столкнетесь, заключается в том, что ваш контроллер не достигнет жизненного цикла при использовании обозначения стрелки "() =>" в качестве параметра функции контроллера.
Проблема заключается в том, что обозначение стрелки не будет иметь собственной области видимости, а вместо этого будет использовать ее внутри области видимости. Это означает, что при использовании "this" будет ссылаться на объект окна, а не на компонент. Поэтому вызов этого. $ OnInit() будет вызван в окне и не будет запущен, потому что он не существует в окне.