web-dev-qa-db-fra.com

Composants AngularJS: les liaisons ne sont pas définies dans le contrôleur

J'écris un composant angulaire simple. Je passe un paramètre en tant que liaison et affiche sa valeur à l'écran. Tout fonctionne bien: je peux voir le paramètre affiché à l'écran.

Composant:

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>

Toutefois, lorsque j'essaie d'accéder à la liaison depuis le contrôleur (voir le fichier console.log), la valeur de la liaison est undefined. Je ne comprends pas comment cela peut être disponible dans la vue, mais pas dans le contrôleur.

Qu'est-ce que je fais mal?

Voici un plnkr illustrant le problème.

54
fikkatra

Lors de l'utilisation des composants angular, il y a un point où le contrôleur n'a pas été câblé via le linkage interne. Si vous essayez de faire cela dans le constructeur de votre contrôleur, vous n'avez pas été lié aux liaisons. L'API de composant expose quelques points d'ancrage de cycle de vie que vous pouvez définir et qui se déclencheront à certains moments. Vous recherchez le crochet $onInit.

$ onInit () - Appelé sur chaque contrôleur une fois que tous les contrôleurs d'un élément ont été construits et que leurs liaisons ont été initialisées (et avant les fonctions de liaison préalable et postérieures pour les directives de cet élément). C’est un bon endroit pour mettre le code d’initialisation de votre contrôleur.

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

49
jusopi

Assurez-vous d’utiliser hyphens pour les liaisons en HTML et camelCase pour les liaisons en Javascript.

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

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

C'est ce que j'oublie toujours de faire.

20
kolobok

La valeur de contactId est disponible sur le $scope dans votre contrôleur:

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>"
});

Lien vers une autre version de votre Plunker ici .

7
JohnnyCoder

Le mot clé this ne semble pas fonctionner avec la fonction flèche, mais avec 

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

Lorsque vous utilisez la fonction flèche, this , semble faire référence à l’objet window car 

Une fonction de flèche ne crée pas son propre contexte, mais plutôt capture la cette valeur du contexte englobant

6
Olivier Boissé

je suggérerai quelques changements dont vous auriez vraiment besoin pour éviter ces bugs inhabituels.

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>

des points : 

  1. le passage de liaisons à un composant en HTML sera toujours une casse de kebab ex my-contact-id et sa variable javascript respective sera une casse cammale: myContactId.

  2. si vous transmettez la valeur insted de l'objet, utilisez '@' dans les liaisons . si vous utilisez un objet et que vous transmettez l'objet à bindigs, utilisez '<. si vous voulez une liaison bidirectionnelle avec cet objet utiliser '=' dans la configuration des liaisons

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

Ce n'est peut-être pas la meilleure pratique, mais vous avez un accès plus facile à ces valeurs:

$scope.$ctrl.contactId

Vous pouvez obtenir toutes les liaisons dans la propriété $ ctrl à l'intérieur de la portée $.

J'espère son aide

1
BratisLatas

Je vais ajouter une autre réponse à la suite de @jusopi et la réponse acceptée, uniquement pour ceux qui risquent de rencontrer mon problème. En ce qui concerne le composant, même après le hook $onInit, mes données étaient toujours nulles, car la valeur du serveur n’était toujours pas reçue. Pour remédier à cela (même s'il existe peut-être un meilleur moyen de gérer cette situation), j'ai également exploité le hook $onChanges. $onChanges renverra les données modifiées lors de leur transmission. Vous pouvez analyser ces informations ou simplement appeler la liaison en tant que this.contactId et les mettre à jour.

Plus de détails sont fournis dans la documentation : https://docs.angularjs.org/guide/component

0
CoolestNerdIII

Il y a deux problèmes avec le code provoquant l'erreur "indéfini".

  1. Comme indiqué ci-dessus, le hook du cycle de vie de $ onInit doit d'abord être atteint, onInit est activé lorsque toutes les liaisons ont été effectuées.

De la documentation officielle: Documentation AngularJs

$ onInit () - Appelé sur chaque contrôleur après que tous les contrôleurs d'un élément aient été construits et que leurs liaisons aient été initialisées (et avant les fonctions de liaison préalable et postérieures pour les directives de cet élément). C’est un bon endroit pour mettre le code d’initialisation de votre contrôleur.

  1. Le deuxième problème que vous aurez probablement, est que votre contrôleur n'atteindra pas le cycle de vie lorsque vous utiliserez la notation de flèche "() =>" en tant que paramètre de la fonction de contrôleur.

Le problème est que la notation de flèche n'aura pas sa propre portée, mais utilisera plutôt sa portée englobante. Cela signifie que lorsque vous utilisez "ceci", vous vous référez à l'objet window plutôt qu'au composant. Donc, appeler $ onInit () sera appelé sur la fenêtre et ne sera pas déclenché, car il n’existe pas sur la fenêtre.

0
Sotem

Pour ceux qui utilisent des directives, où les composants sont supposés, si les liaisons {} sont spécifiées, il apparaît que l'ajout de ces mêmes paramètres à la portée {} fonctionne:

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

* Découvert après avoir écrit ce qui précède qu’un paramètre supplémentaire de la portée, foo, n’était pas disponible sur $ scope tant que je ne l’avais pas assigné à partir de J'ai donc dû le faire dans $ scope.init (): $ scope.foo = $ scope.resolve.foo. Pas certain de pourquoi. En devinant que cela a à voir avec mon interface utilisateur Bootstrap Modal + utilisation des directives

Cela peut sembler évident pour d’autres mais ce n’était pas pour moi une connaissance relativement nouvelle d’AnguluarJS.

Mon problème était d'utiliser des directives avec des modules UI-Bootstrap, qui sont compatibles avec les directives, mais conçues et documentées pour être utilisées avec des composants.

0
Shovas