[Angular] Refactor Angular Component State Logic into Directives

本文介绍如何将Angular中的Toggle组件从一个简单的组件转换为一个指令,并引入ToggleProvider指令来管理多个Toggle指令的状态,实现状态共享。文章详细展示了代码修改过程,包括如何使用@Input和@Output装饰器,以及如何在模板中应用这些更改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Allow the base toggle to be a tag (<toggle>) or attribute (<div toggle>). The <toggle> component has become less opinionated about the view, but has now taken on some responsibilities managing state. We’ll decouple the state management piece by moving it into the toggleProvider directive. The toggleProvider directive provides state for all the <toggle-off>, <toggle-on> and <toggle-button> components inside it.

 

For toggle component we made in previous post

@Component({
  selector: 'toggle',
  template: '<ng-content></ng-content>',
})

As you can see, it use 'ng-content' inside template which means that it doesn't actually needs a template, we can consider ToggleComponent as a directive.

 

So we can modifiy ToggleComponet to ToggleDirective:

import { Directive, Input, Output, EventEmitter } from '@angular/core';

@Directive({
  selector: 'toggle, [toggle]'
})
export class ToggleDirective {
  @Input() on: boolean;
  @Output() toggle: EventEmitter<boolean> = new EventEmitter();

  setOnState(on: boolean) {
    this.on = on;
    this.toggle.emit(this.on);
  }
}

So we can change the usage in app.component.html:

<div toggle (toggle)="onToggle($event)">
  <toggle-on>On</toggle-on>
  <toggle-off>Off</toggle-off>
  <toggle-off>Off</toggle-off>
  <other-component></other-component>
  <toggle-button></toggle-button>
</div>

Then change all the dependencies injection for toggle-on/off/button component, the application should still works.

 

One problem for the current directive implementations is that each toggle directives are isolated:

 

Most of times, isolated directives are OK, but in some cases, if you want to share the state between two or more directives. You have to do some extra works.

 

Write ToggleProviderDirective for reference ToggleDirective.

state <-- ToggleDirective <-- ToggleProviderDirective

So ToggleDirective is managing the state, if we want to share the state, we create ToggleProviderDirective, it takes ToggleDirective as input, so that we can share one ToggleDirective thoughts multi directives.

import { Directive, Input, Output, Host, OnChanges, SimpleChanges, Optional } from '@angular/core';
import {ToggleDirective} from './toggle.directive';

@Directive({
  exportAs: 'toggleProvider',
  selector: 'toggle, [toggle], [toggleProvider]',
})
export class ToggleProviderDirective implements OnChanges {

  @Input() toggleProvider: ToggleDirective;

  toggle: ToggleDirective = this.toggleDirective;

  constructor(
    // Reference the toggle directive on the same host element
    @Host() @Optional() private toggleDirective: ToggleDirective
  ) {
    
  }

  ngOnChanges(changes: SimpleChanges) {
    const {toggleProvider} = changes;
    if (toggleProvider) {
      this.toggle = this.toggleProvider || this.toggleDirective;
    }
  }
}

 

Also need to change the reference for toggle-on/off/button:

import { Component } from '@angular/core';

import { ToggleProviderDirective } from './toggle.toggleProvider.directive';

@Component({
  selector: 'toggle-button',
  template: '<switch [on]="toggleProvider.toggle.on" (click)="onClick()" ></switch>',
})
export class ToggleButtonComponent  {
  constructor(public toggleProvider: ToggleProviderDirective) {}

  onClick() {
    this.toggleProvider.toggle.setOnState(!this.toggleProvider.toggle.on);
  }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值