valor switch obtener con cloak angularjs angularjs-directive angularjs-scope angularjs-components angularjs-1.5

switch - Los componentes de AngularJS 1.5+ no son compatibles con Watchers, ¿en qué consiste el trabajo?



ng-value (7)

He estado actualizando mis directivas personalizadas a la nueva arquitectura de componentes . He leído que los componentes no son compatibles con los observadores. ¿Es esto correcto? Si es así, ¿cómo detecta cambios en un objeto? Para un ejemplo básico, tengo un componente personalizado myBox que tiene un juego de componentes secundarios con un enlace en el juego. Si hay un cambio de juego dentro del componente del juego, ¿cómo puedo mostrar un mensaje de alerta dentro de myBox? Entiendo que hay un método rxJS, ¿es posible hacer esto puramente en angular? My JSFiddle

JavaScript

var app = angular.module(''myApp'', []); app.controller(''mainCtrl'', function($scope) { $scope.name = "Tony Danza"; }); app.component("myBox", { bindings: {}, controller: function($element) { var myBox = this; myBox.game = ''World Of warcraft''; //IF myBox.game changes, show alert message ''NAME CHANGE'' }, controllerAs: ''myBox'', templateUrl: "/template", transclude: true }) app.component("game", { bindings: {game:''=''}, controller: function($element) { var game = this; }, controllerAs: ''game'', templateUrl: "/template2" })

HTML

<div ng-app="myApp" ng-controller="mainCtrl"> <script type="text/ng-template" id="/template"> <div style=''width:40%;border:2px solid black;background-color:yellow''> Your Favourite game is: {{myBox.game}} <game game=''myBox.game''></game> </div> </script> <script type="text/ng-template" id="/template2"> <div> </br> Change Game <textarea ng-model=''game.game''></textarea> </div> </script> Hi {{name}} <my-box> </my-box> </div><!--end app-->


Escribir componentes sin Watchers

Esta respuesta describe cinco técnicas para usar para escribir componentes de AngularJS 1.5 sin usar Watchers

Utilice la directiva ng-change

¿Qué métodos alternativos están disponibles para observar los cambios de estado de obj sin usar watch en preparación para AngularJs2?

Puede usar la directiva ng-change para reaccionar a los cambios de entrada.

<textarea ng-model=''game.game'' ng-change="game.textChange(game.game)"> </textarea>

Y para propagar el evento a un componente primario, el controlador de eventos debe agregarse como un atributo del componente secundario.

<game game=''myBox.game'' game-change=''myBox.gameChange($value)''></game>

JS

app.component("game", { bindings: {game:''='', gameChange: ''&''}, controller: function() { var game = this; game.textChange = function (value) { game.gameChange({$value: value}); }); }, controllerAs: ''game'', templateUrl: "/template2" });

Y en el componente padre:

myBox.gameChange = function(newValue) { console.log(newValue); });

Este es el método preferido en el futuro. La estrategia de AngularJS de usar $watch no es escalable porque es una estrategia de sondeo. Cuando el número de oyentes de $watch alcanza alrededor de 2000, la interfaz de usuario se vuelve lenta. La estrategia en Angular 2 es hacer que el marco sea más reactivo y evitar colocar $watch en $scope .

Use el $onChanges de ciclo de vida $onChanges

Con la versión 1.5.3 , AngularJS agregó el $onChanges de ciclo de vida $onChanges al servicio de $compile .

De los documentos:

El controlador puede proporcionar los siguientes métodos que actúan como ganchos de ciclo de vida:

  • $ onChanges (changesObj): se llama cada vez que se actualizan los enlaces unidireccionales ( < ) o de interpolación ( @ ). changesObj es un hash cuyas claves son los nombres de las propiedades enlazadas que han cambiado, y los valores son un objeto de la forma { currentValue: ..., previousValue: ... } . Use este enlace para activar actualizaciones dentro de un componente, como clonar el valor enlazado para evitar la mutación accidental del valor externo.

- Referencia de API de directiva integral AngularJS - Ganchos de ciclo de vida

El $onChanges se usa para reaccionar a cambios externos en el componente con enlaces < unidireccionales. La directiva ng-change se usa para proponer cambios desde el controlador ng-model fuera del componente con & bindings.

Use el $doCheck de ciclo de vida $doCheck

Con la versión 1.5.8 , AngularJS agregó el $doCheck de ciclo de vida $doCheck al servicio de $compile .

De los documentos:

El controlador puede proporcionar los siguientes métodos que actúan como ganchos de ciclo de vida:

  • $doCheck() : se llama en cada turno del ciclo de resumen. Brinda la oportunidad de detectar y actuar sobre los cambios. Cualquier acción que desee realizar en respuesta a los cambios que detecte debe invocarse desde este enlace; implementar esto no tiene efecto cuando se llama $onChanges . Por ejemplo, este enlace podría ser útil si desea realizar una verificación de igualdad profunda o verificar un objeto Date, cuyos cambios no serían detectados por el detector de cambios de Angular y, por lo tanto, no $onChanges . Este gancho se invoca sin argumentos; si detecta cambios, debe almacenar los valores anteriores para compararlos con los valores actuales.

- Referencia de API de directiva integral AngularJS - Ganchos de ciclo de vida

Comunicación intercomponente con require

Las directivas pueden require los controladores de otras directivas permitan la comunicación entre ellas. Esto se puede lograr en un componente al proporcionar una asignación de objetos para la propiedad require . Las claves de objeto especifican los nombres de propiedad bajo los cuales los controladores requeridos (valores de objeto) estarán vinculados al controlador del componente requerido.

app.component(''myPane'', { transclude: true, require: { tabsCtrl: ''^myTabs'' }, bindings: { title: ''@'' }, controller: function() { this.$onInit = function() { this.tabsCtrl.addPane(this); console.log(this); }; }, templateUrl: ''my-pane.html'' });

Para obtener más información, consulte la Guía del desarrollador de AngularJS: comunicación intercomponente

Valores de inserción de un servicio con RxJS

¿Qué pasa en una situación en la que tiene un Servicio que tiene el estado en espera, por ejemplo? ¿Cómo podría enviar cambios a ese Servicio, y otros componentes aleatorios en la página estar al tanto de tal cambio? He estado luchando para abordar este problema últimamente

Cree un servicio con RxJS .

<script src="//unpkg.com/angular/angular.js"></script> <script src="//unpkg.com/rx/dist/rx.all.js"></script> <script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>

var app = angular.module(''myApp'', [''rx'']); app.factory("DataService", function(rx) { var subject = new rx.Subject(); var data = "Initial"; return { set: function set(d){ data = d; subject.onNext(d); }, get: function get() { return data; }, subscribe: function (o) { return subject.subscribe(o); } }; });

Luego simplemente suscríbase a los cambios.

app.controller(''displayCtrl'', function(DataService) { var $ctrl = this; $ctrl.data = DataService.get(); var subscription = DataService.subscribe(function onNext(d) { $ctrl.data = d; }); this.$onDestroy = function() { subscription.dispose(); }; });

Los clientes pueden suscribirse a los cambios con DataService.subscribe y los productores pueden impulsar los cambios con DataService.set .

La DEMO en PLNKR .


Disponible en IE11, MutationObserver https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver . Necesitas inyectar el servicio $ element en el controlador que semi-rompe la separación DOM / controlador, pero creo que esta es una excepción fundamental (es decir, falla) en angularjs. Dado que hide / show es asíncrono, necesitamos devolución de llamada en el show, que angularjs y angular-bootstrap-tab no proporcionan. También requiere que sepa qué elemento DOM específico desea observar. Usé el siguiente código para el controlador angularjs para activar el reflujo de gráficos Highcharts en el programa.

const myObserver = new MutationObserver(function (mutations) { const isVisible = $element.is('':visible'') // Requires jquery if (!_.isEqual(isVisible, $element._prevIsVisible)) { // Lodash if (isVisible) { $scope.$broadcast(''onReflowChart'') } $element._prevIsVisible = isVisible } }) myObserver.observe($element[0], { attributes: true, attributeFilter: [''class''] })


Muy buena respuesta aceptada, pero podría agregar que también puede usar el poder de los eventos (un poco como en la señal Qt / ranuras si lo desea).

Se transmite un evento: $rootScope.$broadcast("clickRow", rowId) por cualquier padre (o incluso controlador $rootScope.$broadcast("clickRow", rowId) ). Luego, en su controlador, puede manejar el evento de esta manera:

$scope.$on("clickRow", function(event, data){ // do a refresh of the view with data == rowId });

También puede agregar algo de inicio de sesión como este (tomado de aquí: https://.com/a/34903433/3147071 )

var withLogEvent = true; // set to false to avoid events logs app.config(function($provide) { if (withLogEvent) { $provide.decorator("$rootScope", function($delegate) { var Scope = $delegate.constructor; var origBroadcast = Scope.prototype.$broadcast; var origEmit = Scope.prototype.$emit; Scope.prototype.$broadcast = function() { console.log("$broadcast was called on $scope " + this.$id + " with arguments:", arguments); return origBroadcast.apply(this, arguments); }; Scope.prototype.$emit = function() { console.log("$emit was called on $scope " + this.$id + " with arguments:", arguments); return origEmit.apply(this, arguments); }; return $delegate; }); } });


Para cualquier persona interesada en mi solución, termino recurriendo a RXJS Observables, que tendrá que usar cuando llegue a Angular 2. Aquí hay un violín que funciona para las comunicaciones entre componentes, me da más control sobre qué mirar.

JS FIDDLE RXJS Observables

class BoxCtrl { constructor(msgService) { this.msgService = msgService this.msg = '''' this.subscription = msgService.subscribe((obj) => { console.log(''Subscribed'') this.msg = obj }) } unsubscribe() { console.log(''Unsubscribed'') msgService.usubscribe(this.subscription) } } var app = angular .module(''app'', [''ngMaterial'']) .controller(''MainCtrl'', ($scope, msgService) => { $scope.name = "Observer App Example"; $scope.msg = ''Message''; $scope.broadcast = function() { msgService.broadcast($scope.msg); } }) .component("box", { bindings: {}, controller: ''BoxCtrl'', template: `Listener: </br> <strong>{{$ctrl.msg}}</strong></br> <md-button ng-click=''$ctrl.unsubscribe()'' class=''md-warn''>Unsubscribe A</md-button>` }) .factory(''msgService'', [''$http'', function($http) { var subject$ = new Rx.ReplaySubject(); return { subscribe: function(subscription) { return subject$.subscribe(subscription); }, usubscribe: function(subscription) { subscription.dispose(); }, broadcast: function(msg) { console.log(''success''); subject$.onNext(msg); } } }])


Un pequeño aviso sobre el uso de ng-change , como se recomienda con la respuesta aceptada, junto con un componente angular 1.5.

En caso de que necesite ver un componente que ng-model y ng-change no funcionan, puede pasar los parámetros como:

Marcado en qué componente se utiliza:

<my-component on-change="$ctrl.doSth()" field-value="$ctrl.valueToWatch"> </my-component>

Componente js:

angular .module(''myComponent'') .component(''myComponent'', { bindings: { onChange: ''&'', fieldValue: ''='' } });

Marcado de componentes:

<select ng-model="$ctrl.fieldValue" ng-change="$ctrl.onChange()"> </select>


Voy tarde. Pero puede ayudar a otras personas.

app.component("headerComponent", { templateUrl: "templates/header/view.html", controller: ["$rootScope", function ($rootScope) { let $ctrl = this; $rootScope.$watch(() => { return $ctrl.val; }, function (newVal, oldVal) { // do something }); }] });


$watch objeto $watch está disponible dentro del objeto $scope , por lo que debe agregar $scope dentro de la función de fábrica de su controlador y luego colocar watcher sobre la variable.

$scope.$watch(function(){ return myBox.game; }, function(newVal){ alert(''Value changed to ''+ newVal) });

Demo aquí

Nota: Sé que habías convertido la directive a component , para eliminar la dependencia de $scope para que te acerques un paso más a Angular2. Pero parece que no se eliminó para este caso.

Actualizar

Básicamente, angular 1.5 agrega .component método jus diferenciar dos funcionalidades diferentes. Al igual que el component realiza un selector adición de comportamiento particular, donde, como directive se agrega un comportamiento específico al DOM. La directiva es solo un método envoltorio en .directive DDO (objeto de definición de directiva). Solo lo que puede ver es que eliminaron la función de link/compile mientras usaban el método .component donde tenían la capacidad de obtener DOM compilado angular.

Utilice el gancho de ciclo de vida $onChanges / $doCheck gancho de ciclo de vida del componente angular, estos estarán disponibles después de la versión Angular 1.5.3+.

$ onChanges (changesObj) : se llama cada vez que se actualizan los enlaces. ChangeObj es un hash cuyas claves son los nombres de las propiedades enlazadas.

$ doCheck () : se llama en cada turno del ciclo de resumen cuando los cambios de enlace. Brinda la oportunidad de detectar y actuar sobre los cambios.

Al usar la misma función dentro del componente se asegurará de que su código sea compatible para moverse a Angular 2.