Tengo un componente principal ( CategoryComponent ), un componente secundario ( videoListComponent ) y un ApiService.
Tengo la mayor parte de esto funcionando bien, es decir, cada componente puede acceder a la API json y obtener sus datos relevantes a través de observables.
Actualmente, el componente de la lista de videos solo obtiene todos los videos, me gustaría filtrar esto solo a los videos en una categoría en particular, lo logré pasando el Id de categoría al niño a través de @Input()
.
CategoryComponent.html
<video-list *ngIf="category" [categoryId]="category.id"></video-list>
Esto funciona y cuando la categoría principal de CategoryComponent cambia, el valor de categoryId se transfiere a través de, @Input()
pero luego necesito detectar esto en VideoListComponent y volver a solicitar la matriz de videos a través de APIService (con el nuevo categoryId).
En AngularJS habría hecho un $watch
en la variable. ¿Cuál es la mejor manera de manejar esto?
fuente
Respuestas:
En realidad, hay dos formas de detectar y actuar cuando una entrada cambia en el componente secundario en angular2 +:
Enlaces de documentación: ngOnChanges, SimpleChanges, SimpleChange
Demo Ejemplo: Mira este plunker
Enlace de documentación: mira aquí .
Ejemplo de demostración: Mira este plunker .
¿QUÉ ENFOQUE DEBE USAR?
Si su componente tiene varias entradas, entonces, si usa ngOnChanges (), obtendrá todos los cambios para todas las entradas a la vez dentro de ngOnChanges (). Con este enfoque, también puede comparar los valores actuales y anteriores de la entrada que ha cambiado y tomar las medidas correspondientes.
Sin embargo, si desea hacer algo cuando solo cambia una entrada en particular (y no le importan las otras entradas), entonces podría ser más simple usar un configurador de propiedades de entrada. Sin embargo, este enfoque no proporciona una forma integrada de comparar los valores anteriores y actuales de la entrada modificada (que puede hacer fácilmente con el método del ciclo de vida ngOnChanges).
EDITAR 2017-07-25: LA DETECCIÓN DE CAMBIO ANGULAR PUEDE TODAVÍA NO FUERA DE FUEGO BAJO ALGUNAS CIRCUNSTANCIAS
Normalmente, la detección de cambios para setter y ngOnChanges se activará siempre que el componente principal cambie los datos que pasa al hijo, siempre que los datos sean un tipo de datos primitivo JS (cadena, número, booleano) . Sin embargo, en los siguientes escenarios, no se disparará y tendrá que tomar medidas adicionales para que funcione.
Si está utilizando un objeto anidado o una matriz (en lugar de un tipo de datos primitivo JS) para pasar datos de padre a hijo, la detección de cambios (usando setter o ngchanges) podría no activarse, como también se menciona en la respuesta del usuario: muetzerich. Para soluciones mira aquí .
Si está mutando datos fuera del contexto angular (es decir, externamente), entonces angular no sabrá los cambios. Puede que tenga que usar ChangeDetectorRef o NgZone en su componente para hacer que Angular tenga conocimiento de los cambios externos y, por lo tanto, desencadenar la detección de cambios. Consulte esto .
fuente
doSomething
método y tomar 2 argumentos los valores nuevos y viejos antes de establecer el nuevo valor, de otra manera estaría almacenando el valor anterior antes de configurar y llamar al método después de eso.Use el
ngOnChanges()
método del ciclo de vida en su componente.Aquí están los documentos .
fuente
MyComponent.myArray = []
, por ejemplo , pero si se altera un valor de entradaMyComponent.myArray.push(newValue)
, por ejemplo ,ngOnChanges()
no se activa. ¿Alguna idea sobre cómo capturar este cambio?ngOnChanges()
no se llama cuando un objeto anidado ha cambiado. Tal vez encuentre una solución aquíRecibía errores en la consola, así como en el compilador e IDE cuando usaba el
SimpleChanges
tipo en la firma de la función. Para evitar los errores, utilice laany
palabra clave en la firma en su lugar.EDITAR:
Como Jon señaló a continuación, puede usar la
SimpleChanges
firma al usar la notación de corchetes en lugar de la notación de puntos.fuente
SimpleChanges
interfaz en la parte superior de su archivo?<my-user-details [user]="selectedUser"></my-user-details>
). Se accede a esta propiedad desde la clase SimpleChanges llamandochanges.user.currentValue
. El avisouser
está vinculado en tiempo de ejecución y no forma parte del objeto SimpleChangesngOnChanges(changes: {[propName: string]: SimpleChange}) { console.log('onChanges - myProp = ' + changes['myProp'].currentValue); }
La apuesta más segura es ir con un servicio compartido en lugar de un
@Input
parámetro. Además, el@Input
parámetro no detecta cambios en el tipo de objeto anidado complejo.Un servicio de ejemplo simple es el siguiente:
Puede usar una implementación similar en otros componentes y todos sus componentes compartirán los mismos valores compartidos.
fuente
@Input
parámetro @JoshuaKemmerer no detecta cambios en el tipo de objeto anidado complejo, pero sí en objetos nativos simples.Solo quiero agregar que hay otro enlace de Lifecycle llamado
DoCheck
que es útil si el@Input
valor no es un valor primitivo.Tengo una matriz como,
Input
por lo que esto no dispara elOnChanges
evento cuando el contenido cambia (porque la comprobación de que Angular lo hace es 'simple' y no profunda, por lo que la matriz sigue siendo una matriz, a pesar de que el contenido de la matriz ha cambiado).Luego implemento un código de verificación personalizado para decidir si quiero actualizar mi vista con la matriz modificada.
fuente
Intenta usar este método. Espero que esto ayude
fuente
También puede tener un observable que desencadena los cambios en el componente principal (CategoryComponent) y hacer lo que desea hacer en la suscripción en el componente secundario. (videoListComponent)
fuente
Aquí ngOnChanges se activará siempre cuando cambie la propiedad de entrada:
fuente
Esta solución utiliza una clase proxy y ofrece las siguientes ventajas:
ngOnChanges()
Ejemplo de uso:
Función de utilidad:
fuente
Si no desea utilizar el método ngOnChange implement og onChange (), también puede suscribirse a los cambios de un elemento específico por el evento valueChanges , ETC.
});
el markForCheck () escrito debido al uso en esta declaración:
fuente
También podría pasar un EventEmitter como entrada. No estoy seguro si esta es la mejor práctica aunque ...
CategoryComponent.ts:
CategoryComponent.html:
Y en VideoListComponent.ts:
fuente