![](/img/trans.png)
[英]How to pass data from Child to Parent, if Child component dynamic component
[英]How can I pass data from child component to parent component?
父組件:.ts:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit, Input } from '@angular/core';
import { MainInteractComponent } from '../main-interact/main-interact.component';
import { HotKeys } from '../Enums/hot-keys';
import { NodeElement, NodeParameter } from '../Models/Node';
@Component({
selector: 'node-interactive-list',
templateUrl: './node-interactive-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./node-interactive-list.component.css']
})
export class NodeInteractiveListComponent implements OnInit {
nodes: NodeElement[] = [];
activeIndex = -1;
@Input() activeElement: NodeElement = null;
constructor(private parent: MainInteractComponent,
private http: HttpClient,
private ref: ChangeDetectorRef
) {
}
ngOnInit(): void {
}
@HostListener('document:keydown', ['$event'])
handleKeyboardEvent(e: any) {
if (e.altKey && e.keyCode === HotKeys.PressN) {
e.preventDefault();
this.ref.detectChanges();
this.addEmptyNode();
}
if (e.altKey && e.keyCode === HotKeys.PressS) {
//e.preventDefault();
//const model: any = {
// id: this.activeElement.id,
// properties: Object.assign({}, ...this.activeElement.parameters.concat([new NodeParameter("name", this.activeElement.name.toString())], this.activeElement.parameters)
// .map((x) => ({ [x.name.toString()]: x.value.toString() })))
//};
//if (!this.activeElement.id) {
// const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
// return this.http.post('https://localhost:44350/Node',
// JSON.stringify(model), { headers }).subscribe((x: any) => {
// this.activeElement.id = x.id;
// });
//}
//else {
// const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
// return this.http.put('https://localhost:44350/Node/' + this.activeElement.id,
// JSON.stringify(model), { headers }).subscribe((x: any) => { });
//}
}
if (e.altKey && e.keyCode === HotKeys.PressR) {
//if (this.activeElement.id != null) {
// this.http.delete('https://localhost:44350/Node/' + `${this.activeElement.id}`)
// .subscribe(() => {
// this.activeElement = new NodeElement();
// this.ref.detectChanges();
// });
//}
console.log(this.activeElement.id);
}
if (e.keyCode === HotKeys.ArrowUp) {
if (this.activeIndex > 0) {
this.activeIndex--;
this.activeElement = this.nodes[this.activeIndex];
this.ref.detectChanges();
}
}
if (e.keyCode === HotKeys.ArrowDown) {
if (this.activeIndex < this.nodes.length - 1) {
this.activeIndex++;
this.activeElement = this.nodes[this.activeIndex];
this.ref.detectChanges();
}
}
}
addEmptyNode() {
if (this.nodes.length == 0 || !this.nodes[this.nodes.length - 1].isClean()) {
let newNode = new NodeElement();
this.nodes.push(newNode);
this.activeIndex = this.nodes.length - 1;
this.activeElement = this.nodes[this.activeIndex];
this.ref.detectChanges();
}
}
}
.html:
<app-node-item *ngIf="activeElement" [(currentNode)]="activeElement"></app-node-item>
子組件:.ts:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ChangeDetectorRef, Component, HostListener, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { HotKeys } from '../Enums/hot-keys';
import { NodeElement, NodeParameter } from '../Models/Node';
@Component({
selector: 'app-node-item',
templateUrl: './node-item.component.html',
styleUrls: ['./node-item.component.css']
})
export class NodeItemComponent implements OnInit {
@Input() currentNode: NodeElement = new NodeElement();
@Output() currentNodeChanged: EventEmitter<NodeElement> = new EventEmitter();
public currentSelectedIndex: number = -1;
public searchResults: any[] = [];
constructor(private http: HttpClient,
private ref: ChangeDetectorRef ) { }
ngOnInit(): void {
}
@HostListener('document:keydown', ['$event'])
handleKeyboardEvent(e: any) {
if ((e.srcElement.classList[0] == 'name-input' || e.srcElement.classList[1] == 'name-input') && !this.currentNode.id) {
setTimeout(() => {
const model: any = {
properties: {
'name': this.currentNode.name.toString()
}
};
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
return this.http.post('https://localhost:44350/Node/specs',
JSON.stringify(model), { headers }).subscribe((x: any) => {
this.searchResults = x.map(node => {
var result: [string, string][] = Object.entries(node.properties)
var resultNode: NodeElement = new NodeElement();
resultNode.parameters = result.map(y => new NodeParameter(y[0], y[1])).filter(z => z[0] != 'name');
resultNode.id = node.id;
resultNode.name = result.filter(z => z[0] == 'name')[0][1];
return resultNode;
});
this.ref.detectChanges();
});
}, 0)
}
if (e.altKey && e.keyCode === HotKeys.PressF) {
e.preventDefault();
if (this.currentSelectedIndex == -1) {
this.currentNode.parameters.push(new NodeParameter('', ''));
}
else {
this.currentNode.parameters.splice(this.currentSelectedIndex+1, 0, new NodeParameter('', ''));
}
setTimeout(() => {
if (this.currentSelectedIndex != -1) {
e.srcElement.parentNode.nextSibling.children[1].focus()
}
}, 0)
}
if (e.altKey && e.keyCode === HotKeys.PressD) {
e.preventDefault();
this.currentNode.parameters = this.currentNode.parameters.filter((x, i) => i != this.currentSelectedIndex);
if (this.currentSelectedIndex != -1 && this.currentSelectedIndex != -1 && !!e.srcElement.parentNode.previousSibling.children[1]) {
e.srcElement.parentNode.previousSibling.children[1].focus()
}
}
this.currentNodeChanged.emit(this.currentNode);
}
public getHints(option: any) {
if (!!option)
return (option.name);
else
return ''
}
public getName() {
if (!!this.currentNode?.name) return !!this.currentNode?.name; else new NodeElement();
}
public setName(event) {
if (!!this.currentNode?.name)
this.currentNode.name = event;
}
public getParameters() {
if (!!this.currentNode?.parameters)
return this.currentNode?.parameters
else return [];
}
public onParameterFocus(i: number) {
setTimeout(() => {
this.currentSelectedIndex = i;
}, 0)
}
public onParameterBlur() {
this.currentSelectedIndex = -1;
}
displayFn = state => {
if (!!state) {
this.currentNode = state;
return state?.name;
}
}
}
.html:
<p>name:</p>
<input class="name-input" type="text" matInput [ngModel]="currentNode" (ngModelChange)="currentNode.name = $event" [matAutocomplete]="auto"/>
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let option of searchResults" [value]="option">
{{getHints(option)}}
</mat-option>
</mat-autocomplete>
<li *ngFor="let item of currentNode.parameters; index as i;">
<br />
<input [ngModel]="item.name" (ngModelChange)="item.name = $event" (focus)="onParameterFocus(i)" (blur)="onParameterBlur()" />
<input [ngModel]="item.value" (ngModelChange)="item.value = $event" (focus)="onParameterFocus(i)" (blur)="onParameterBlur()" />
<br />
</li>
子組件中的 currentNode 屬性有 id、name、parametrs、etc.,activeElement 也必須有。 我的意思是,當 currentNode 發生變化時,activeElement 也必須發生變化。 這是關於數據綁定的。 但我不明白如何正確地制作它。 我希望每次 currentNode 更改時,activeElement 也會更改(我的意思是它必須是兩個相似的變量,當涉及更改 currentNode 時)。
嘗試添加兩種方式綁定:
父組件 HTML:
<app-node-item *ngIf="activeElement" [(node)]="activeElement"></app-node-item>
也許你需要用*ngIf
來處理它有點不同
子組件:.ts:
添加這個:
@Output() currentNodeChange = new EventEmitter<NodeElement>();
在HostListener
中所有可能的更改(條件和所有操作)之后添加:
this.currentNodeChange.emit(this.currentNode);
有兩種方法可以將數據從子組件傳遞到父組件。
通過Event Emitter:在子component.ts中,
@Output() currentNodeChanged = new EventEmitter<NodeElement>();
無論您想在哪里發出 output,我們都必須在那里發出更改,
this.currentNodeChanged.emit(this.currentNode);
在父組件.html,
<app-node-item [currentNodeChanged]="currentNode.name = $event" *ngIf="activeElement" [(node)]="activeElement"></app-node-item>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.