【问题标题】:How to let a component delete itself on a button click with in angular如何让组件在单击按钮时以角度删除自身
【发布时间】:2019-06-04 09:01:58
【问题描述】:

我无法使用 Angular 使组件自行删除。

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

  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”中的每一次“推送”,都会创建一个组件。

【问题讨论】:

  • 您是动态添加组件吗?如果是这样,只需在 viewcontainerRef 上调用 clear 就很容易了。见documentation
  • 我确实“动态地”添加它。我用我的解决方案编辑我的帖子以动态添加它。
  • 您可以轻松地放置一个标志来显示或隐藏组件。例如 这意味着您的选择器组件不会显示在屏幕上。
  • 是的,我知道,但我想彻底删除它。
  • 这是一个非常广泛的问题。我可以想出十几种方法来处理这个问题。您在寻找什么样的答案?

标签: angular typescript frontend


【解决方案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 表示应用程序的 当前 状态。存在组件存在的状态,然后存在不存在的状态。不要将其视为删除的行为,而是状态发生了变化,之后组件不再呈现。

      1. 输入您的姓名

      状态没有任何问候。

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

      状态至少有一个getting。

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

      状态恢复到没有任何问候。

      目前我完成了前两个步骤,一切正常。但我不知道如何让子组件自行删除。来自 React 我知道,有可能以某种方式使用生命周期方法删除“组件”。

      如果您强行删除该组件,则页面上的组件将不再代表应用程序的当前状态。这很好,你有 microstates 和一个例子就像一个模态对话框。对话框本身有自己的状态,并且对话框的显示具有相对于该微观状态的生命周期。

      根据你的例子,我认为情况并非如此。

      currentUsers: any[] = [];
      

      上面是你的 state 变量。该 array 的值表示将在 HTML 中呈现的内容。您可以提出一些问题,答案会为您提供指导。

      1. 谁拥有国家?
      2. 谁能改变那个状态?
      3. 如何要求国有企业改?

      让我们回答这些问题

      1. 谁拥有国家?

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

      1. 谁能改变那个状态?

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

      1. 如何要求国有企业改?

      这是我们了解 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);
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多