簡體   English   中英

如何將數據從子組件傳遞到父組件?

[英]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);

有兩種方法可以將數據從子組件傳遞到父組件。

  1. 通過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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM