如何让组件在单击按钮时以角度删除自身

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 我确实“动态地”添加它。我用我的解决方案编辑我的帖子以动态添加它。 您可以轻松地放置一个标志来显示或隐藏组件。例如 这意味着您的选择器组件不会显示在屏幕上。 是的,我知道,但我想彻底删除它。 这是一个非常广泛的问题。我可以想出十几种方法来处理这个问题。您在寻找什么样的答案? 【参考方案1】:

正如@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,允许消费者观察应用程序状态的变化。这样做的好处是 stateexternal 服务拥有管理。 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);
  

【讨论】:

以上是关于如何让组件在单击按钮时以角度删除自身的主要内容,如果未能解决你的问题,请参考以下文章

如何在角度6的按下按钮更改事件?

如何在角度中禁用matchip

从角度 2 中的历史记录中删除一个组件

如何在使用混合路由时以角度使用 ActivatedRoute?

在每个按钮单击角度后加载组件

单击按钮重新加载角度组件