英文:
Communication between children in angular
问题
我正在制作一个学生列表。输入字段、添加按钮和更新按钮都在一个子组件中,而在另一个子组件中有包含删除和编辑按钮的列表。这两者都在父组件中处理。
当我点击编辑按钮时,我希望输入字段中有来自列表的值,并能够更新列表。
父组件 HTML
<ul>
<app-list-item
*ngFor="let studentName of students; let i = index"
[name]="studentName"
[index]="i"
(deleteNameByIndex)="onemitDeleteNameByIndex($event)"
(editNameById)="onemitEditNameById($event)"
>
</ul>
父组件 .ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
students = ['huzaifa', 'hunzila', 'waqar', 'sibte', 'shahzeen'];
student = '';
onemitAddNewName(newName: string) {
this.students.push(newName);
}
onemitDeleteNameByIndex(index: number) {
this.students.splice(index, 1);
}
onemitEditNameById(student: any) {
this.student = student;
console.log('app student: >> ', this.student);
}
}
子组件1 HTML
<input
type="text"
placeholder="enter name"
[value]="name"
(input)="oninputSetName($event)"
/>
{{ student }}
{{ name }}
<button (click)="onclickEmitNewName()">Add</button>
<button>Update</button>
子组件1 .ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-list-form',
templateUrl: './list-form.component.html',
styleUrls: ['./list-form.component.css'],
})
export class ListFormComponent {
name = '';
@Output() newName = new EventEmitter<string>();
@Input() student = '';
oninputSetName(event: any) {
this.name = event.target.value;
}
onclickEmitNewName() {
this.newName.emit(this.name);
}
updateInput() {
let obj = { name: this.student };
console.log('list-form student: >> ', this.student);
}
}
子组件2 HTML
{{ name }} -- {{ index }}
<button (click)="onclickDeleteName()">delete</button>
<button (click)="onclickEditName()">edit</button>
子组件2 .ts
@Component({
selector: 'app-list-item',
templateUrl: './list-item.component.html',
styleUrls: ['./list-item.component.css'],
})
export class ListItemComponent {
@Input() name = '';
@Input() index = 0;
@Output() deleteNameByIndex = new EventEmitter<number>();
@Output() editNameById = new EventEmitter<any>();
onclickDeleteName() {
this.deleteNameByIndex.emit(this.index);
}
onclickEditName() {
let obj = { index: this.index, name: this.name };
this.editNameById.emit(obj);
}
}
英文:
I am making a list of students. The input field, add button, and update button are inside one child and in other child there is the list with the delete and edit buttons. Both are handled in the parent component.
When I click edit button, I would like the input filed to have a value from that list and to be able to update the list.
parent html
<ul>
<app-list-item
*ngFor="let studentName of students; let i = index"
[name]="studentName"
[index]="i"
(deleteNameByIndex)="onemitDeleteNameByIndex($event)"
(editNameById)="onemitEditNameById($event)"
>
</ul>
parent .ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
students = ['huzaifa', 'hunzila', 'waqar', 'sibte', 'shahzeen'];
student = '';
onemitAddNewName(newName: string) {
this.students.push(newName);
}
onemitDeleteNameByIndex(index: number) {
this.students.splice(index, 1);
}
onemitEditNameById(student: any) {
this.student = student;
console.log('app student :>> ', this.student);
}
}
child 1 html
<input
type="text"
placeholder="enter name"
[value]="name"
(input)="oninputSetName($event)"
/>
{{ student }}
{{ name }}
<button (click)="onclickEmitNewName()">Add</button>
<button>Update</button>
child 1 .ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-list-form',
templateUrl: './list-form.component.html',
styleUrls: ['./list-form.component.css'],
})
export class ListFormComponent {
name = '';
@Output() newName = new EventEmitter<string>();
@Input() student = '';
oninputSetName(event: any) {
this.name = event.target.value;
}
onclickEmitNewName() {
this.newName.emit(this.name);
}
updateInput() {
let obj = { name: this.student };
console.log('list-form student :>> ', this.student);
}
}
child 2 html
{{ name }} -- {{ index }}
<button (click)="onclickDeleteName()">delete</button>
<button (click)="onclickEditName()">edit</button>
child 2 .ts
@Component({
selector: 'app-list-item',
templateUrl: './list-item.component.html',
styleUrls: ['./list-item.component.css'],
})
export class ListItemComponent {
@Input() name = '';
@Input() index = 0;
@Output() deleteNameByIndex = new EventEmitter<number>();
@Output() editNameById = new EventEmitter<any>();
onclickDeleteName() {
this.deleteNameByIndex.emit(this.index);
}
onclickEditName() {
let obj = { index: this.index, name: this.name };
this.editNameById.emit(obj);
}
}
答案1
得分: 1
甚至更加优雅的方式是,您可以使用一个辅助服务来解决您的通讯问题。
下面是一个示例服务:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MessageService {
private messageSource = new Subject<string>();
currentMessage = this.messageSource.asObservable();
constructor() {}
changeMessage(message: string) {
this.messageSource.next(message);
}
}
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'app-sender',
template: `
<button (click)="sendMessage()">Send Message</button>
`
})
export class SenderComponent {
constructor(private messageService: MessageService) {}
sendMessage() {
this.messageService.changeMessage('Hello from Sender Component');
}
}
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'app-receiver',
template: `
<p>{{ message }}</p>
`
})
export class ReceiverComponent {
message: string;
constructor(private messageService: MessageService) {
this.messageService.currentMessage.subscribe(message => {
this.message = message;
});
}
}
英文:
Or even in a more elegant way, you could use a helper service to solve your communication issue.
Below you could find a sample service:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MessageService {
private messageSource = new Subject<string>();
currentMessage = this.messageSource.asObservable();
constructor() {}
changeMessage(message: string) {
this.messageSource.next(message);
}
}
<!-- end snippet -->
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'app-sender',
template: `
<button (click)="sendMessage()">Send Message</button>
`
})
export class SenderComponent {
constructor(private messageService: MessageService) {}
sendMessage() {
this.messageService.changeMessage('Hello from Sender Component');
}
}
<!-- end snippet -->
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'app-receiver',
template: `
<p>{{ message }}</p>
`
})
export class ReceiverComponent {
message: string;
constructor(private messageService: MessageService) {
this.messageService.currentMessage.subscribe(message => {
this.message = message;
});
}
}
<!-- end snippet -->
答案2
得分: 0
由于 Angular 是按引用传递的。您可以利用这一点。当这样做时,甚至无需发出更改的值。
例如,在您的代码中 `Child 1` 处:
与其发出一个本地变量,您可以将值分配给 `@Input`。
这里是一个示例:
@Input existingStudentName: string;
localName: string = existingStudentName;
onUserUpdate(){
existingStudentName = localName;
// 无需发出,因为这里已更新 existingStudentName
// 它将在引用它的父级或其他任何地方更新
}
<input type="text" [(ngModel)]="localName">
<input type="button" (click)="onUserUpdate()">
英文:
Since angular is Pass By reference. You can take advantage of that. when you do that you don't even have to emit the changed value.
For Example, In your code at Child 1
:
Rather than emitting a local variable. All you can do is assign the value to @Input
.
Here is a example:
@Input existingStudentName: string;
localName: string = existingStudentName;
onUserUpdate(){
existingStudentName = localName;
//No need to emmit since existingStudentName is updated here
//It will update in parent or anyone who refer it
}
<input type="text" [(ng-Model)]="localName">
<input type="button" (click)="onUserUpdate()">
答案3
得分: -1
父级 HTML
<section>
<!-- 输入字段,我在其中输入数据 -->
<app-list-form
(newName)="onemitAddNewName($event)"
[student]="student"
(updatedName)="updateThisNameInList($event)"
></app-list-form>
<!-- 渲染我的列表 -->
<ul>
<app-list-item
*ngFor="let studentName of students; let i = index"
[name]="studentName"
[index]="i"
(deleteNameByIndex)="onemitDeleteNameByIndex($event)"
(editNameById)="onemitEditNameById($event)"
></app-list-item>
</ul>
</section>
父级 TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
students = ['huzaifa', 'hunzila', 'waqar', 'sibte', 'shahzeen'];
student = null;
onemitAddNewName(newName: string) {
this.students.push(newName);
}
onemitDeleteNameByIndex(index: number) {
this.students.splice(index, 1);
}
onemitEditNameById(student: any) {
this.student = student;
}
updateThisNameInList(student: any) {
let newName = student.name;
let index = student.index;
this.students.splice(index, 1, newName);
}
}
子级 1 HTML
<input
type="text"
placeholder="输入姓名"
[(ngModel)]="name"
(input)="oninputSetName($event)"
/>
<!-- {{ student?.name ?? "" }}
{{ name }} -->
<button (click)="onclickEmitNewName()">添加</button>
<button (click)="onclickEmitUpdateName()">更新</button>
子级 1 TypeScript
import {
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
} from '@angular/core';
@Component({
selector: 'app-list-form',
templateUrl: './list-form.component.html',
styleUrls: ['./list-form.component.css'],
})
export class ListFormComponent implements OnChanges {
name = '';
@Output() newName = new EventEmitter<string>();
@Input() student: any = null;
@Output() updatedName = new EventEmitter<any>();
oninputSetName(event: any) {
this.name = event.target.value;
}
ngOnChanges(changes: SimpleChanges): void {
console.log('list-form: changes happen ', changes);
this.name = changes['student']?.currentValue?.name ?? '';
}
change(event: any) {
this.name = event.target.value;
}
onclickEmitNewName() {
this.newName.emit(this.name);
this.name = '';
}
onclickEmitUpdateName() {
// if (this.name == '') return;
if (!this.name) return;
this.updatedName.emit({
name: this.name,
index: this.student.index,
});
}
}
子级 2 HTML
<li>
{{ name }} -- {{ index }}
<button (click)="onclickDeleteName()">删除</button>
<button (click)="onclickEditName()">编辑</button>
</li>
子级 2 TypeScript
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-list-item',
templateUrl: './list-item.component.html',
styleUrls: ['./list-item.component.css'],
})
export class ListItemComponent {
@Input() name = '';
@Input() index = 0;
@Output() deleteNameByIndex = new EventEmitter<number>();
@Output() editNameById = new EventEmitter<any>();
onclickDeleteName() {
this.deleteNameByIndex.emit(this.index);
}
onclickEditName() {
let obj = {
index: this.index,
name: this.name,
};
this.editNameById.emit(obj);
}
}
英文:
Parent Html
<section>
<!-- input field where i enter my data -->
<app-list-form
(newName)="onemitAddNewName($event)"
[student]="student"
(updatedName)="updateThisNameInList($event)"
></app-list-form>
<!-- rendering my list -->
<ul>
<app-list-item
*ngFor="let studentName of students; let i = index"
[name]="studentName"
[index]="i"
(deleteNameByIndex)="onemitDeleteNameByIndex($event)"
(editNameById)="onemitEditNameById($event)"
[
></app-list-item>
</ul>
</section>
Parent ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
students = ['huzaifa', 'hunzila', 'waqar', 'sibte', 'shahzeen'];
student = null;
onemitAddNewName(newName: string) {
this.students.push(newName);
}
onemitDeleteNameByIndex(index: number) {
this.students.splice(index, 1);
}
onemitEditNameById(student: any) {
this.student = student;
}
updateThisNameInList(student: any) {
let newName = student.name;
let index = student.index;
this.students.splice(index, 1, newName);
}
}
child 1 html
<input
type="text"
placeholder="enter name"
[(ngModel)]="name"
(input)="oninputSetName($event)"
/>
<!-- {{ student?.name ?? "" }}
{{ name }} -->
<button (click)="onclickEmitNewName()">Add</button>
<button (click)="onclickEmitUpdateName()">Update</button>
child 1 ts
import {
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
} from '@angular/core';
@Component({
selector: 'app-list-form',
templateUrl: './list-form.component.html',
styleUrls: ['./list-form.component.css'],
})
export class ListFormComponent implements OnChanges {
name = '';
@Output() newName = new EventEmitter<string>();
@Input() student: any = null;
@Output() updatedName = new EventEmitter<any>();
oninputSetName(event: any) {
this.name = event.target.value;
}
ngOnChanges(changes: SimpleChanges): void {
console.log('list-form: changes happen ', changes);
this.name = changes['student']?.currentValue?.name ?? '';
}
change(event: any) {
this.name = event.target.value;
}
onclickEmitNewName() {
this.newName.emit(this.name);
this.name = '';
}
onclickEmitUpdateName() {
// if (this.name == '') return;
if (!this.name) return;
this.updatedName.emit({
name: this.name,
index: this.student.index,
});
}
}
child 2 html
<li>
{{ name }} -- {{ index }}
<button (click)="onclickDeleteName()">delete</button>
<button (click)="onclickEditName()">edit</button>
</li>
child 2 ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-list-item',
templateUrl: './list-item.component.html',
styleUrls: ['./list-item.component.css'],
})
export class ListItemComponent {
@Input() name = '';
@Input() index = 0;
@Output() deleteNameByIndex = new EventEmitter<number>();
@Output() editNameById = new EventEmitter<any>();
onclickDeleteName() {
this.deleteNameByIndex.emit(this.index);
}
onclickEditName() {
let obj = {
index: this.index,
name: this.name,
};
this.editNameById.emit(obj);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论