如何在Angular中让一个组件在按钮点击时删除自身
如何在Angular中让一个组件在按钮点击时删除自身
我无法让一个组件在Angular中自我删除。
我目前正在学习Angular,并为开始时启动了一个小的问候项目。应用程序的工作原理如下:
- 输入你的名字
- 创建一个向你问候的子组件。
- 子组件包含一个删除自身的按钮。
目前,我已经完成了前两个步骤,一切正常运行。但是我不知道如何让子组件删除自身。作为来自React的开发者,我知道在React中可以通过生命周期方法来删除一个"组件"。在Angular中是否有类似的方法呢?目前我找不到它,但我找到了一个名为"OnDestroy()"的方法,在一个组件被销毁之前调用。但是如何正确地销毁它呢?
父组件:
import { Component, OnInit, ViewChild, Input } from '@angular/core'; @Component({ selector: 'app-greeter-service', templateUrl: './greeter-service.component.html' }) export class GreeterServiceComponent implements OnInit { title = ''; currentUser = ''; isVisible = false; currentUsers: any[] = []; @ViewChild('newUser') inputField; constructor() {} greetingFunc(newUser : string) { if(newUser) { this.currentUsers.push(newUser); console.log(this.currentUsers); this.inputField.nativeElement.value=''; } } ngOnInit() { this.title = 'Welcome to the Greeter!'; } }
子组件:
import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-was-greeted', templateUrl: './was-greeted.component.html', styleUrls: ['./was-greeted.component.scss'] }) export class WasGreetedComponent implements OnInit { @Input() user: string; constructor() { } deleteMe() { console.log("在这里应该有一个动作"); } ngOnInit() { } }
如何“动态”地将一个组件添加到应用程序中:
因此,对于数组"currentUsers"中的每个"push",都会创建一个组件。
如何让一个Angular组件在按钮点击时删除自身
问题的出现原因:
目前已经完成了前两个步骤,一切都运行正常。但是我不知道如何让子组件删除自身。从React的经验来看,我知道可以通过生命周期方法删除“组件”。
解决方法:
1. 使用()绑定:在Angular中,组件可以具有一个在父组件模板中执行表达式的()绑定。这与将回调函数传递给React组件的属性相同。在WasGreetedComponent组件中,添加以下代码:
public closed: Subject() = new Subject(); deleteMe() { this.closed.next(); }
在GreeterServiceComponent模板中,更改以下代码:
u!==user)">
2. 父组件注入:在Angular中,子组件可以通过构造函数注入自己的父组件,并直接通知父组件。这种方法绕过了模板,父组件中的任何更改都可能需要更新视图。因此,建议父组件使用ChangeDetectorRef将其视图标记为脏。
在GreeterServiceComponent中添加以下代码:
public deleteUser(user: any) { this.currentUsers = this.currentUsers.filter(u=>u !== user); this.changeDetectorRef.markForCheck(); }
在WasGreetedComponent中添加以下代码:
constructor(parent: GreeterServiceComponent) {} deleteMe() { this.parent.deleteUser(this.user); }
3. 通过响应式编程实现全局状态:最后一种方法使用了响应式编程,其中使用可观察对象来允许消费者观察应用程序状态的变化。这样做的优点是状态由外部服务“拥有”和“管理”。在Angular/React/Vue框架中广泛使用的流行服务(如Redux/NGRX/NGXS)非常强大。使用状态存储有很多优点,但对于小型项目来说,它往往过于复杂。一旦开始使用它们,很难停止使用。
我们可以创建自己的小型版本作为演示。首先,添加一个表示应用程序状态的服务。
({provideIn: 'root'}) export class StateService { public users: BehaviorSubject= new BehaviorSubject([]); public addUser(user: any) { this.users .pipe(first()) .subscribe(users => this.users.next([...users, user])); } public removeUser(user: any) { this.users .pipe(first()) .subscribe(users => this.users.next(users.filter(u=>u !== user))); } }
现在,在GreeterServiceComponent中,它将不再是状态的“所有者”。我们将注入上述服务,并允许该服务来管理它。
({...}) export class GreeterServiceComponent implements OnInit { constructor(public state: StateService) {} greetingFunc(newUser : string) { if(newUser) { this.state.addUser(newUser); } } }
在GreeterServiceComponent模板中,我们将使用async管道直接从StateService中显示当前用户的状态。我们这样做是因为服务持有有关当前状态的“真相”。GreeterServiceComponent组件不关心如何更改它,因为它不拥有或管理它。
WasGreetedComponent组件将使用StateService来更改当前状态。该组件不关心其父组件。您可以在应用程序中移动此组件,并且它仍将正常工作。这是一个重要的好处,因为上述的其他方法依赖于DOM本身的结构。因此,移动一个组件将需要在其他地方进行更改以使组件正常工作。
({...}) export class WasGreetedComponent implements OnInit { constructor(public state: StateService) {} deleteMe() { this.state.removeUser(this.user); } }
在Angular中,有时候需要在按钮点击时让一个组件自己删除。下面的内容提供了一种实现方法。
首先,在WasGreetedComponent
组件中添加一个delete
属性,并在按钮点击时触发一个事件。然后,在GreeterServiceComponent
组件中通过查找数组中的元素并删除它来处理这个事件(注意,数组应该是不可变的,所以需要创建一个新的数组实例),这会导致ngFor
重新评估并更新视图。
@Component({ selector: 'app-was-greeted', templateUrl: './was-greeted.component.html', styleUrls: ['./was-greeted.component.scss'] }) export class WasGreetedComponent implements OnInit { @Input() user: string; @Output() delete: EventEmitter= new EventEmitter(); constructor() { } deleteMe() { console.log("here should be the action"); this.delete.emit(user); } }
在父组件的模板中,订阅这个事件的触发。
然后,在父组件中处理deleteUser
回调,并从数组中删除用户。
@Component({ selector: 'app-greeter-service', templateUrl: './greeter-service.component.html' }) export class GreeterServiceComponent implements OnInit { title = ''; currentUser = ''; isVisible = false; currentUsers: any[] = []; @ViewChild('newUser') inputField; constructor() {} ... deleteUser(user: string) { this.currentUsers = this.currentUsers.filter(x => x !== user); } }
总之,这只是许多解决方法中的一种。希望对你有帮助。