eventos entre descargar controladores comunicacion componentes javascript angularjs angular-directive angular-components

javascript - entre - descargar angular



Comunicando eventos de padres a hijos en los componentes de AngularJS (3)

Comunicando eventos de padres a hijos en los componentes de AngularJS

Publique la directiva $ API usando el enlace de expresiones

Para permitir que los componentes principales comuniquen eventos a un componente secundario, haga que el niño publique una API:

<grid-component grid-on-init="$ctrl.gridApi=$API; $ctrl.someFn($API)"> </grid-component>

JS

app.component(''gridComponent'', { //Create API binding bindings: {gridOnInit: "&"}, template: ` <h4>Grid component</h4> <p> Save count = {{$ctrl.count}}</p> `, controller: function() { var ctrl = this; this.$onInit = function() { ctrl.count = 0; ctrl.api = {}; //Publish save function ctrl.api.save = save; //Invoke Expression with $API as local ctrl.gridOnInit({$API: ctrl.api}); }; function save(){ console.log("saved!"); ctrl.count++; } } });

El ejemplo anterior invoca la Expresión Angular definida por el atributo grid-on-init con su API expuesta como $API . La ventaja de este enfoque es que el padre puede reaccionar a la inicialización del niño pasando una función al componente del niño con la Expresión Angular.

De los docs:

El hash del objeto de alcance ''aislado'' define un conjunto de propiedades de alcance local derivadas de los atributos en el elemento de la directiva. Estas propiedades locales son útiles para los valores de alias para plantillas. Las claves en el hash del objeto se asignan al nombre de la propiedad en el ámbito de aislamiento; los valores definen cómo se vincula la propiedad al ámbito principal, a través de atributos coincidentes en el elemento de la directiva:

  • & o &attr : proporciona una forma de ejecutar una expresión en el contexto del ámbito principal. Si no se especifica ningún nombre attr, se asume que el nombre del atributo es el mismo que el nombre local. Dado <my-component my-attr="count = count + value"> y el alcance de definición de alcance de aislamiento: { localFn:''&myAttr'' } , la propiedad de alcance de aislamiento localFn apuntará a una envoltura de función para count = count + value expression A menudo es deseable pasar datos del ámbito aislado a través de una expresión al ámbito primario. Esto se puede hacer pasando un mapa de nombres y valores de variables locales a la expresión wrapper fn. Por ejemplo, si la expresión es increment($amount) entonces podemos especificar el valor de la cantidad llamando a localFn como localFn({$amount: 22}) .

- AngularJS Completa directiva API - alcance

Como convención, recomiendo prefijar variables locales con $ para distinguirlas de las variables primarias.

Utilice alternativamente la unión bidireccional

NOTA: Para facilitar la transición a Angular 2+, evite el uso de enlace bidireccional = . En su lugar, use unidireccional < enlace y expresión & enlace. Para obtener más información, consulte la Guía del desarrollador de AngularJS - Descripción de los componentes .

Para permitir que los componentes principales comuniquen eventos a un componente secundario, haga que el niño publique una API:

<grid-component api="$ctrl.gridApi"></grid-component>

En el ejemplo anterior, el grid-component utiliza enlaces para publicar su API en el ámbito principal utilizando el atributo api .

app.component(''gridComponent'', { //Create API binding bindings: {api: "="}, template: ` <h4>Grid component</h4> <p> Save count = {{$ctrl.count}}</p> `, controller: function() { var ctrl = this; this.$onInit = function() { ctrl.count = 0; ctrl.api = {}; //Publish save function ctrl.api.save = save; }; function save(){ console.log("saved!"); ctrl.count++; } } });

Luego, el componente principal puede invocar la función de save secundaria utilizando la API publicada:

ctrl.click = function(){ console.log("Search clicked"); ctrl.gridApi.save(); }

La DEMO en PLNKR .

En el nuevo proyecto en el que estoy trabajando, comencé a usar los componentes en lugar de las directivas.

sin embargo, he encontrado un problema en el que no puedo encontrar una manera estándar concreta de hacerlo.

Es fácil notificar un evento de niño a padre, puede encontrarlo en mi plunkr a continuación, pero ¿cuál es la forma correcta de notificar un evento de padre a hijo?

Angular2 parece resolver este problema usando algo como esto: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-local-var Pero no lo hago Hay una posibilidad de definir un "puntero" para el componente secundario, como lo hizo el ejemplo con #timer.

Para mantener una posible conversión fácil a Angular2 quiero evitar:

  • Emisión de eventos (emitir y transmitir desde los ámbitos)
  • usando el requisito del hijo (y luego agregue una devolución de llamada al padre ... MUY BIEN)
  • utilizando un enlace unidireccional, inyectando el alcance en el elemento secundario y luego "observe" esta propiedad. MÁS UGLY

Código de ejemplo:

var app = angular.module(''plunker'', []); app.controller(''RootController'', function() { }); app.component(''parentComponent'', { template: ` <h3>Parent component</h3> <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Notify Child</a> <span data-ng-bind="$ctrl.childMessage"></span> <child-component on-change="$ctrl.notifiedFromChild(count)"></child-component> `, controller: function() { var ctrl = this; ctrl.notifiedFromChild = function(count){ ctrl.childMessage = "From child " + count; } ctrl.click = function(){ } }, bindings: { } }); app.component(''childComponent'', { template: ` <h4>Child component</h4> <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Notify Parent</a> `, controller: function() { var ctrl = this; ctrl.counter = 0; ctrl.click = function(){ ctrl.onChange({ count: ++ctrl.counter }); } }, bindings: { onChange: ''&'' } });

Puedes encontrar un ejemplo aquí:

http://plnkr.co/edit/SCK8XlYoYCRceCP7q2Rn?p=preview

Esta es una posible solución que he creado.

http://plnkr.co/edit/OfANmt4zLyPG2SZyVNLr?p=preview

donde el niño requiere el padre, y luego el niño establece una referencia del padre al niño ... ahora el padre puede usar el niño ... feo pero es como el ejemplo angular2 de arriba


Aquí hay una manera fácil: http://morrisdev.com/2017/03/triggering-events-in-a-child-component-in-angular/

básicamente, agrega una variable enlazada llamada "comando" (o lo que quiera) y usa $ onChanges para prestar atención a los cambios de esa variable y desencadenar cualquier evento que diga para disparar manualmente.

Personalmente, me gusta poner todas mis variables en un objeto llamado "configuración" y enviarlo a todos mis componentes. Sin embargo, un cambio en un valor dentro de un objeto NO desencadena el evento $ onChanges, por lo que NECESITA indicarle que active el evento con una variable plana.

Yo diría que no es la forma "correcta" de hacerlo, pero es mucho más fácil de programar, mucho más fácil de entender y mucho más fácil de convertir a A2 más adelante.


Me enfrenté con la misma pregunta. ¿Qué piensa acerca de este enfoque: utilizar la herencia a través de la require lugar de la vinculación bidireccional?

http://plnkr.co/edit/fD1qho3eoLoEnlvMzzbw?p=preview

var app = angular.module(''plunker'', []); app.controller(''RootController'', function() { }); app.component(''filterComponent'', { template: ` <h3>Filter component</h3> <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Search</a> <span data-ng-bind="$ctrl.childMessage"></span> <grid-component api="$ctrl.gridApi"></grid-component> `, controller: function() { var ctrl = this; ctrl.click = function(){ console.log("Search clicked"); ctrl.gridApi.save(); }; } }); app.component(''gridComponent'', { require: {parent:''^^filterComponent''}, bindings: {api: "<"}, template: ` <h4>Grid component</h4> <p> Save count = {{$ctrl.count}} `, controller: function() { var ctrl = this; this.$onInit = function() { ctrl.count = 0; ctrl.api = {}; ctrl.api.save = save; ctrl.parent.gridApi = ctrl.api; }; function save(){ console.log("saved!"); ctrl.count++; } } });

O podemos definir el método de establecimiento para que el padre lo haga más explícito.

http://plnkr.co/edit/jmETwGt32BIn3Tl0yDzY?p=preview

var app = angular.module(''plunker'', []); app.controller(''RootController'', function() { }); app.component(''filterComponent'', { template: ` <h3>Filter component</h3> <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Search</a> <span data-ng-bind="$ctrl.childMessage"></span> <grid-component pass-api="$ctrl.setGridApi(api)"></grid-component> `, controller: function() { var ctrl = this; var gridApi = {}; ctrl.setGridApi = function(api){ gridApi = api; }; ctrl.click = function(){ console.log("Search clicked"); gridApi.save(); }; } }); app.component(''gridComponent'', { bindings: { passApi:''&'' }, template: ` <h4>Grid component</h4> <p> Save count = {{$ctrl.count}} `, controller: function() { var ctrl = this; this.$onInit = function() { ctrl.count = 0; ctrl.api = {}; ctrl.api.save = save; ctrl.passApi({api: ctrl.api}); }; function save(){ console.log("saved!"); ctrl.count++; } } });