如何让组件在单击按钮时以角度删除自身
Posted
技术标签:
【中文标题】如何让组件在单击按钮时以角度删除自身【英文标题】:How to let a component delete itself on a button click with in angular 【发布时间】:2019-06-04 09:01:58 【问题描述】:我无法使用 Angular 使组件自行删除。
我目前正在学习 Angular,并开始了一个小型问候项目。应用程序应该如何工作:
-
输入您的姓名
创建问候您的子组件。
子组件包含删除自身的按钮
目前我完成了前两个步骤,一切正常。但我不知道如何让子组件自行删除。来自 React 我知道,有可能以某种方式使用生命周期方法删除“组件”。角度有类似的东西吗?目前我找不到它,但我找到了在组件被销毁之前调用的方法“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("here should be the action");
ngOnInit()
我如何“动态地”将组件添加到应用程序:
<div class="column" *ngFor="let user of currentUsers">
<app-was-greeted [user]="user"></app-was-greeted>
</div>
因此,对于数组“currentUsers”中的每一次“推送”,都会创建一个组件。
【问题讨论】:
您是动态添加组件吗?如果是这样,只需在 viewcontainerRef 上调用 clear 就很容易了。见documentation 我确实“动态地”添加它。我用我的解决方案编辑我的帖子以动态添加它。 您可以轻松地放置一个标志来显示或隐藏组件。例如正如@cgTag 评论的那样,有很多方法可以处理这个问题。一种方法是将@Output
添加到您的WasGreetedComponent
中,该WasGreetedComponent
将发射到父组件。
然后在 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<string> = new EventEmitter();
constructor()
deleteMe()
console.log("here should be the action");
this.delete.emit(user);
然后您的父组件模板将订阅此发射器
<div class="column" *ngFor="let user of currentUsers">
<app-was-greeted [user]="user" (delete)="deleteUser($event)"></app-was-greeted>
</div>
组件将需要处理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);
就像我说的,这只是给猫剥皮的众多方法之一。希望这会有所帮助。
【讨论】:
【参考方案2】:让组件有一个父级监听的@Output 参数并将其从currentUsers 中移除,或者为*ngFor 添加额外的逻辑以在循环中绘制元素时忽略它。像这样的东西?
<div class="column" *ngFor="let user of currentUsers; let i = index">
<app-was-greeted *ngIf="shouldDisplay(i)" (buttonClick)="removeMe(i)" [user]="user">
</app-was-greeted>
</div>
【讨论】:
【参考方案3】:我无法使用 angular 使组件自行删除。
假设呈现的 HTML 表示应用程序的 当前 状态。存在组件存在的状态,然后存在不存在的状态。不要将其视为删除的行为,而是状态发生了变化,之后组件不再呈现。
输入您的姓名
状态没有任何问候。
创建问候您的子组件。
状态至少有一个getting。
子组件包含删除自身的按钮
状态恢复到没有任何问候。
目前我完成了前两个步骤,一切正常。但我不知道如何让子组件自行删除。来自 React 我知道,有可能以某种方式使用生命周期方法删除“组件”。
如果您强行删除该组件,则页面上的组件将不再代表应用程序的当前状态。这很好,你有 microstates 和一个例子就像一个模态对话框。对话框本身有自己的状态,并且对话框的显示具有相对于该微观状态的生命周期。
根据你的例子,我认为情况并非如此。
currentUsers: any[] = [];
上面是你的 state 变量。该 array 的值表示将在 HTML 中呈现的内容。您可以提出一些问题,答案会为您提供指导。
-
谁拥有国家?
谁能改变那个状态?
如何要求国有企业改?
让我们回答这些问题
谁拥有国家?
GreeterServiceComponent
组件是状态的所有者,在这种情况下,状态表示为一个数组。在 Web 组件中,我们将此称为组件的状态。它是组件内部的东西。
谁能改变那个状态?
我们只希望GreeterServiceComponent
对此状态进行更改。类之外的源代码不应直接访问它并对其进行变异。我们可以说组件处理了这个内部状态的存储和生命周期。
如何要求国有企业改?
这是我们了解 Angular 细节的地方。在 Angular 中,我们有多种方式在组件之间进行通信。在这种情况下,我们希望 child 组件与 parent 组件通信,它应该更改它的内部状态。我们想告诉父母不要再显示问候语了。解决此问题的每种方法都有其优点和缺点,由您决定哪种方法适合您。
@Output() 绑定
Angular 中的组件可以有一个@Output()
,它在父组件的模板中执行一个表达式。这与将 callback 函数传递给 React 组件的属性相同。
在WasGreetedComponent
中添加:
@Output()
public closed: Subject<void>() = new Subject();
deleteMe() this.closed.next();
在GreeterServiceComponent
模板中你会改变:
<div class="column" *ngFor="let user of currentUsers">
<app-was-greeted [user]="user"
(closed)="currentUsers = currentUsers.filter(u=>u!==user)">
</app-was-greeted>
</div>
父注入
Angular 中的子组件可以通过构造函数注入自己的父组件,然后你可以直接通知父组件。
这种方法会绕过模板,并且在父级中所做的任何更改都可能需要更新视图。因此,建议父级使用ChangeDetectorRef
将其视图标记为dity。
在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);
通过反应式编程实现全局状态
最后一种方法使用反应式编程,其中使用observables,允许消费者观察应用程序状态的变化。这样做的好处是 state 由 external 服务拥有 和管理。 Redux/NGRX/NGXS 等流行服务在 Angular/React/Vue 框架中大量使用。使用状态存储有很多优点,但这些都是难以掌握的框架,对于小型项目来说,这通常是矫枉过正。一旦你开始使用它们,它们就很难停止使用。
我们可以创建自己的小版本作为演示。
您将添加一个服务来表示您的应用程序状态。
@Injectable(provideIn: 'root')
export class StateService
public users: BehaviorSubject<any[]> = new BehaviorSubject([]);
public addUser(user: any)
this.users
.pipe(first())
.subject(users => this.users.next([...users, user]));
public removeUser(user: any)
this.users
.pipe(first())
.subject(users => this.users.next(users.filter(u=>u !== user)));
现在,在您的GreeterServiceComponent
中,它将不再是状态的所有者。我们将注入上述服务并允许该服务对其进行管理。
@Component(...)
export class GreeterServiceComponent implements OnInit
constructor(public state: StateService)
greetingFunc(newUser : string)
if(newUser)
this.state.addUser(newUser);
在GreeterServiceComponent
模板中,我们将使用async
管道直接从StateService
显示用户的当前状态。我们这样做是因为服务持有关于当前状态的真相。 GreeterServiceComponent
组件不会关心它如何更改,因为它不拥有或管理它。
<div class="column" *ngFor="let user of state.users | async">
<app-was-greeted [user]="user"></app-was-greeted>
</div>
WasGreetedComponent
组件将使用StateService
来更改当前状态。该组件不关心它的父组件。您可以在您的应用程序中移动这个组件,它仍然可以正常工作。这是一个重要的好处,因为上述其他方法取决于 DOM 本身的结构。因此,移动组件需要在其他地方进行更改以保持组件正常工作。
@Component(...)
export class WasGreetedComponent implements OnInit
constructor(public state: StateService)
deleteMe()
this.state.removeUser(this.user);
【讨论】:
以上是关于如何让组件在单击按钮时以角度删除自身的主要内容,如果未能解决你的问题,请参考以下文章