子组件中的角度4调用父方法

我想在角度4的子组件中调用父方法(deltePhone)。 我怎么才能做到呢?

我的父组件看起来像:

export class ContactInfo implements OnInit {
phoneForm: FormGroup;
phones: Phone[];




constructor(private fb: FormBuilder,
private userService: UserService) {
}


ngOnInit() {
this.userService.getDataPhones().subscribe(
phones => {
this.phones = phones;
});


this.phoneForm = this.fb.group({
phone: ['', [Validators.pattern(PHONE_PATTERN)]]
});
}


deletePhone(phone: Phone) {
this.userService.deleteUserPhone(phone)
.subscribe(res => {
let index = this.phones.indexOf(phone);
if (index > -1) {
this.phones.splice(index, 1);
}
});
}
}
132022 次浏览
import { Output, EventEmitter } from '@angular/core';


...


class ChildComponent {
@Output() someEvent = new EventEmitter<string>();


callParent(): void {
this.someEvent.next('somePhone');
}
}

In ContactInfo's template

<child-component (someEvent)="deletePhone($event)"

This worked for me (example from official docs):

https://angular.io/api/core/EventEmitter#examples

Child:

@Component({
selector: 'zippy',
template: `
<div class="zippy">
<div (click)="toggle()">Toggle</div>
<div [hidden]="!visible">
<ng-content></ng-content>
</div>
</div>`})
export class Zippy {
visible: boolean = true;
@Output() open: EventEmitter<any> = new EventEmitter();
@Output() close: EventEmitter<any> = new EventEmitter();


toggle() {
this.visible = !this.visible;
if (this.visible) {
this.open.emit(null); //emit event here
} else {
this.close.emit(null);
}
}
}

Parent:

<zippy (open)="onOpen($event)" (close)="onClose($event)"></zippy>

I don't like boilerplate code like @Output(). I found another solution, just pass object with any number of anonymous functions

import { Component, OnInit } from '@angular/core';


@Component({
selector: 'app-parent',
styleUrls: ['./parent.component.css'],
template: `
<app-child [parentApi]="getParentApi()"></app-child>
`,
})
export class ParentComponent implements OnInit {


getParentApi(): ParentComponentApi {
return {
callParentMethod: (name) => {
this.parentMethod(name)
}
}
}


constructor() { }


ngOnInit() {
}


parentMethod(name: string) {
console.log(`Hello ${name} from parent`)
}
  

}


export interface ParentComponentApi {
callParentMethod: (string) => void
}

And child:

import { Component, OnInit, Input } from '@angular/core';
import { ParentComponentApi } from '../parent/parent.component';


@Component({
selector: 'app-child',
template: `<button (click)="callParent()">call parent</button>`,
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {


@Input() parentApi: ParentComponentApi


constructor() { }


callParent() {
this.parentApi.callParentMethod("child")
}


ngOnInit() {


}


}

I think this is pretty safe to do this way, no?

It's simpler than you might think. The key is to pass a parent method to a child @Input property. test it online

Parent component

@Component({
selector: 'my-app',
template: `
<h1>Parent:</h1>
<p>Parent counting: \{\{this.count}}</p>


<child-comp [childInc]="this.inc"></child-comp>
`
})
export class AppComponent {
name = "I'm Parent";


count = 0;


inc = () => {
this.count++;
}
}


Child component

@Component({
selector: 'child-comp',
template: `
<h1>Child:</h1>
<button (click)="childInc()">Click me!</button>
`
})
export class ChildComponent  {
name = "I'm child"


@Input() childInc: () => void
}

I've used inc = () => {...} notion in parent, which can remember the right this. If you use the inc(){...} notion, then you need to bind parent this as [childInc]="this.inc.bind(this)".