angularjs - otro - pasar parametros entre componentes angular 4
FunciĆ³n de devoluciĆ³n de llamada de paso angular al componente secundario como @Input similar a la forma AngularJS (7)
AngularJS tiene los parámetros & donde puede pasar una devolución de llamada a una directiva (por ejemplo,
forma de devolución de llamada AngularJS
. ¿Es posible pasar una devolución de llamada como
@Input
para un componente angular (algo como a continuación)? Si no, ¿cuál sería la cosa más cercana? a lo que hace AngularJS?
@Component({
selector: ''suggestion-menu'',
providers: [SuggestService],
template: `
<div (mousedown)="suggestionWasClicked(suggestion)">
</div>`,
changeDetection: ChangeDetectionStrategy.Default
})
export class SuggestionMenuComponent {
@Input() callback: Function;
suggestionWasClicked(clickedEntry: SomeModel): void {
this.callback(clickedEntry, this.query);
}
}
<suggestion-menu callback="insertSuggestion">
</suggestion-menu>
Como ejemplo, estoy usando una ventana modal de inicio de sesión, donde la ventana modal es la principal, el formulario de inicio de sesión es el secundario y el botón de inicio de sesión vuelve a llamar a la función de cierre de la principal modal.
El modal primario contiene la función para cerrar el modal. Este padre pasa la función de cierre al componente hijo de inicio de sesión.
import { Component} from ''@angular/core'';
import { LoginFormComponent } from ''./login-form.component''
@Component({
selector: ''my-modal'',
template: `<modal #modal>
<login-form (onClose)="onClose($event)" ></login-form>
</modal>`
})
export class ParentModalComponent {
modal: {...};
onClose() {
this.modal.close();
}
}
Después de que el componente de inicio de sesión secundario envíe el formulario de inicio de sesión, cierra el modal primario mediante la función de devolución de llamada principal
import { Component, EventEmitter, Output } from ''@angular/core'';
@Component({
selector: ''login-form'',
template: `<form (ngSubmit)="onSubmit()" #loginForm="ngForm">
<button type="submit">Submit</button>
</form>`
})
export class ChildLoginComponent {
@Output() onClose = new EventEmitter();
submitted = false;
onSubmit() {
this.onClose.emit();
this.submitted = true;
}
}
Creo que es una mala solución.
Si desea pasar una función al componente con
@Input()
, el decorador
@Output()
es lo que está buscando.
export class SuggestionMenuComponent {
@Output() onSuggest: EventEmitter<any> = new EventEmitter();
suggestionWasClicked(clickedEntry: SomeModel): void {
this.onSuggest.emit([clickedEntry, this.query]);
}
}
<suggestion-menu (onSuggest)="insertSuggestion($event[0],$event[1])">
</suggestion-menu>
En algunos casos (raros) es posible que necesite que un componente principal realice la lógica de negocios. En el siguiente ejemplo, tenemos un componente secundario que representa la fila de la tabla dependiendo de la lógica proporcionada por el componente primario:
@Component({
...
template: ''<table-component [getRowColor]="getColor"></table-component>'',
directives: [TableComponent]
})
export class ParentComponent {
// Pay attention on the way this function is declared. Using fat arrow (=>) declaration
// we can ''fixate'' the context of `getColor` function
// so that it is bound to ParentComponent as if .bind(this) was used.
getColor = (row: Row) => {
return this.fancyColorService.getUserFavoriteColor(row);
}
}
@Component({...})
export class TableComponent{
// This will be bound to the ParentComponent.getColor.
// I found this way of declaration a bit safer and convenient than just raw Function declaration
@Input(''getRowColor'') getRowColor: (row: Row) => Color;
renderRow(){
....
// Notice that `getRowColor` function holds parent''s context because of a fat arrow function used in the parent
const color = this.getRowColor(row);
renderRow(row, color);
}
}
Tal vez no sea un caso ideal y esto se puede hacer de una mejor manera, pero solo quería demostrar 2 cosas aquí:
- Fat arrow (=>) funciona en lugar de .bind (this) para mantener el contexto correcto;
- Declaración de tipo seguro de la función de devolución de llamada en el componente secundario.
La respuesta actual se puede simplificar a ...
@Component({
...
template: ''<child [myCallback]="theCallback"></child>'',
directives: [ChildComponent]
})
export class ParentComponent{
public theCallback(){
...
}
}
@Component({...})
export class ChildComponent{
//This will be bound to the ParentComponent.theCallback
@Input()
public myCallback: Function;
...
}
Pasar método con argumento, usando .bind dentro de la plantilla
@Component({
...
template: ''<child [action]="foo.bind(this, ''someArgument'')"></child>'',
...
})
export class ParentComponent {
public foo(someParameter: string){
...
}
}
@Component({...})
export class ChildComponent{
@Input()
public action: Function;
...
}
Una alternativa a la respuesta que SnareChops dio.
Puede usar .bind (this) en su plantilla para tener el mismo efecto. Puede que no sea tan limpio pero ahorra un par de líneas. Actualmente estoy en angular 2.4.0
@Component({
...
template: ''<child [myCallback]="theCallback.bind(this)"></child>'',
directives: [ChildComponent]
})
export class ParentComponent {
public theCallback(){
...
}
}
@Component({...})
export class ChildComponent{
//This will be bound to the ParentComponent.theCallback
@Input()
public myCallback: Function;
...
}
ACTUALIZAR
Esta respuesta se envió cuando Angular 2 todavía estaba en alfa y muchas de las características no estaban disponibles / indocumentadas. Si bien lo siguiente seguirá funcionando, este método ahora está completamente desactualizado. Recomiendo encarecidamente la respuesta aceptada a continuación.
Respuesta original
Sí, de hecho lo es, sin embargo, querrás asegurarte de que tenga un alcance correcto.
Para esto, he usado una propiedad para asegurar que
this
significa lo que quiero.
@Component({
...
template: ''<child [myCallback]="theBoundCallback"></child>'',
directives: [ChildComponent]
})
export class ParentComponent{
public theBoundCallback: Function;
public ngOnInit(){
this.theBoundCallback = this.theCallback.bind(this);
}
public theCallback(){
...
}
}
@Component({...})
export class ChildComponent{
//This will be bound to the ParentComponent.theCallback
@Input()
public myCallback: Function;
...
}