Parent component:
.ts:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit } 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;
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();
// });
//}
}
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" [node]="activeElement"></app-node-item>
<!--Property code doesn't exist, it's mistake. I suppose I will need to to replace it-->
Child component:
.ts:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ChangeDetectorRef, Component, HostListener, Input, 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();
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()
}
}
}
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, которое находится в дочернем компоненте, имеет идентификатор, имя, параметры и т. д., и activeElement также должен иметь их. Я имею в виду, что при изменении currentNode, activeElement тоже должен изменяться. Речь идет о привязке данных. Но я не понимаю, как это сделать правильно. Я хочу, чтобы каждый раз, когда изменяется currentNode, activeElement также менялся (я имею в виду, что это должны быть две одинаковые переменные, когда дело доходит до изменения currentNode).