Подтвердить что ты не робот

Почему привязки моего компонента не определены в контроллере?

Я пишу простой компонент 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, иллюстрирующий проблему.

4b9b3361

Ответ 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

Есть две проблемы с кодом, вызывающие "неопределенную" ошибку.

  1. Как указывалось выше, сначала должен быть достигнут хук жизненного цикла $ onInit, onInit запускается, когда все привязки выполнены.

Из официальной документации: AngularJs Documentation

$ onInit() - вызывается на каждом контроллере после того, как все контроллеры в элементе были сконструированы и инициализированы их привязки (и до функций связывания pre и post для директив этого элемента). Это хорошее место, чтобы поместить код инициализации для вашего контроллера.

  1. Вторая проблема, с которой вы, вероятно, столкнетесь, заключается в том, что ваш контроллер не достигнет жизненного цикла при использовании обозначения стрелки "() =>" в качестве параметра функции контроллера.

Проблема заключается в том, что обозначение стрелки не будет иметь собственной области видимости, а вместо этого будет использовать ее внутри области видимости. Это означает, что при использовании "this" будет ссылаться на объект окна, а не на компонент. Поэтому вызов этого. $ OnInit() будет вызван в окне и не будет запущен, потому что он не существует в окне.