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

时间:2019-01-09 14:44:30

标签: angular typescript frontend

我无法使组件以角度删除自身。

我目前正在学习角度游戏,并开始了一个小型问候项目。该应用程序应如何工作:

  1. 输入您的姓名
  2. 已创建问候您的子组件。
  3. 子组件包含用于删除自身的按钮

目前,我已完成前两个步骤,并且一切正常。但是我不知道如何使子组件删除自身。来自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”中的每个“推”创建一个组件。

3 个答案:

答案 0 :(得分:4)

正如@cgTag所评论的那样,有很多方法可以处理此问题。一种方法是在您的@Query("select new my.package.MyDto(" + "entity.status, " + "month(entity.date), " + "count(entity.status)) from MyEntity entity" + "where month(entity) = 12 " + "group by entity.status, month(entity.date) ") List<MyDto> findGroupedByStatusInDecember(); 中添加一个@Output,它将发射到父组件。

然后在您WasGreetedComponent中,您可以在数组中找到该元素并将其删除(请记住,您的数组应该是不可变的,因此您想创建该数组的新实例),这将导致{{1 }}重新评估和更新视图

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>

就像我说的那样,这只是给猫加皮的许多方法之一。希望这会有所帮助。

答案 1 :(得分:1)

  

我无法使组件以角度删除自身。

比方说,呈现的HTML表示应用程序的 current 状态。有一个组件存在的状态,然后有一个不存在的状态。不要以为它是 delete 的行为,但是 state 发生了变化,此后该组件不再呈现。

  
      
  1. 输入您的姓名
  2.   

状态没有任何问候。

  
      
  1. 已创建问候您的子组件。
  2.   

状态至少有一个。

  
      
  1. 子组件包含用于删除自身的按钮
  2.   

状态返回没有任何问候。

  

目前,我已完成前两个步骤,并且一切正常。但是我不知道如何使子组件删除自身。来自React,我知道可以通过某种生命周期方法删除“组件”。

如果您强制删除该组件,则页面上的组件将不再代表该应用程序的当前状态。拥有 microstates 的地方很好,例如,像是模式对话框。对话框本身具有其自己的状态,并且对话框的显示具有相对于该微状态的生命周期。

在您的示例中,我认为情况并非如此。

currentUsers: any[] = [];

以上是您的 state 变量。该 array 的值表示将在HTML中呈现的内容。您可以提出一些问题,答案可以帮助您。

  1. 谁拥有国家?
  2. 谁可以改变该状态?
  3. 我如何要求国家所有者进行更改?

让我们回答这些问题

  
      
  1. 谁拥有国家?
  2.   

GreeterServiceComponent组件是状态的所有者,在这种情况下,状态表示为数组。在Web组件中,我们将此称为组件的状态。这是组件的内部问题。

  
      
  1. 谁可以改变该状态?
  2.   

我们只希望GreeterServiceComponent对此状态进行更改。类之外的源代码不应直接访问它并对其进行突变。我们可以说该组件负责处理此内部状态的存储和生命周期。

  
      
  1. 我如何要求国家所有者进行更改?
  2.   

这是我们介绍Angular细节的地方。在Angular中,我们有多种方式在组件之间进行通信。在这种情况下,我们希望 child 组件与 parent 组件进行通信,以使其应更改其内部状态。我们要告诉父母不要再打招呼了。解决此问题的每种方法都有其优点和缺点,由您决定哪种方法适合您。

@Output()绑定

Angular中的组件可以具有一个@Output(),该WasGreetedComponent在父组件的模板中执行表达式。这与将回调函数传递给React组件的属性相同。

@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> 模板中,您将更改:

ChangeDetectorRef

父母注射

Angular中的子组件可以通过构造函数注入自己的父组件,然后您可以直接通知父组件。

此方法绕过了模板,对父级所做的任何更改都可能需要更新视图。因此,建议父母使用GreeterServiceComponent将其视图标记为“ dity”。

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); } 中,您将添加:

 @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)));
      }
 }

通过反应式编程的全局状态

最后一种方法是使用反应式编程,其中使用 observables 来允许消费者监视应用程序状态的变化。这样做的好处是,状态外部服务拥有并由管理。诸如Redux / NGRX / NGXS之类的流行服务在Angular / React / Vue框架中大量使用。使用状态存储有很多优点,但是要掌握它们是困难的框架,对于一个小型项目而言,这通常是过大的。一旦开始使用它们,就很难退出使用。

我们可以创建自己的小版本作为演示。

您将添加代表您的应用程序状态的服务。

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组件将使用@Component({...}) export class WasGreetedComponent implements OnInit { constructor(public state: StateService) {} deleteMe() { this.state.removeUser(this.user); } 更改当前的状态。该组件不关心其父组件。您可以在应用程序中移动该组件,它仍然可以正常运行。这是一个重要的好处,因为上述其他方法取决于DOM本身的结构。因此,移动组件将需要在其他位置进行更改以保持组件正常工作。

{{1}}

答案 2 :(得分:0)

让组件具有一个@Output参数,父组件会监听该@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>