Angular 2:如何让指令订阅服务Observable实现自动更新
让Angular指令订阅服务Observable实现自动视图更新
这种场景我太熟了——想让权限指令完全自主响应服务的权限变化,不用组件每次手动传值,确实是解耦的好思路。下面一步步给你实现:
1. 先搭建你的权限服务
首先得有一个能推送权限更新的服务,这里用BehaviorSubject最合适,因为它能保存当前值,新订阅的观察者也能拿到最新的权限状态:
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class PermissionService { // 私有Subject,内部用来更新权限 private _currentPermissions$ = new BehaviorSubject<string[]>([]); // 公开的Observable,供外部订阅(只能读,不能写) public currentPermissions$: Observable<string[]> = this._currentPermissions$.asObservable(); // 更新权限的方法,在任意组件/服务里调用这个方法就能推送新权限 updatePermissions(permissions: string[]) { this._currentPermissions$.next(permissions); } }
2. 实现权限指令
接下来写指令,核心就是注入权限服务,订阅它的currentPermissions$流,每次收到新权限就更新视图:
import { Directive, ElementRef, OnInit, OnDestroy } from '@angular/core'; import { PermissionService } from './permission.service'; import { Subscription } from 'rxjs'; @Directive({ selector: '[appPermission]', // 可以接收需要校验的权限,比如 <div appPermission="edit">...</div> inputs: ['requiredPermission: appPermission'] }) export class PermissionDirective implements OnInit, OnDestroy { requiredPermission: string; private permissionSubscription: Subscription; constructor( private el: ElementRef, private permissionService: PermissionService ) {} ngOnInit() { // 订阅权限变化流 this.permissionSubscription = this.permissionService.currentPermissions$.subscribe(permissions => { this.updateElementVisibility(permissions); }); } private updateElementVisibility(permissions: string[]) { // 判断当前元素是否拥有所需权限,控制显示/隐藏 const hasPermission = permissions.includes(this.requiredPermission); this.el.nativeElement.style.display = hasPermission ? 'block' : 'none'; // 也可以添加/移除CSS类,比如: // if (hasPermission) { // this.el.nativeElement.classList.remove('hidden'); // } else { // this.el.nativeElement.classList.add('hidden'); // } } ngOnDestroy() { // 一定要取消订阅,防止内存泄漏! if (this.permissionSubscription) { this.permissionSubscription.unsubscribe(); } } }
3. 怎么用?
在模板里直接用指令,不用传动态输入(除非你需要指定单个权限):
<!-- 需要edit权限才显示 --> <button appPermission="edit">编辑</button> <!-- 需要delete权限才显示 --> <button appPermission="delete">删除</button>
然后在任意地方调用服务的updatePermissions方法,比如登录后获取权限:
import { Component } from '@angular/core'; import { PermissionService } from './permission.service'; @Component({ selector: 'app-login', template: '<button (click)="login()">登录</button>' }) export class LoginComponent { constructor(private permissionService: PermissionService) {} login() { // 模拟登录后获取权限 const userPermissions = ['edit', 'view']; this.permissionService.updatePermissions(userPermissions); // 此时所有带appPermission指令的元素都会自动更新! } }
额外优化:用async pipe简化订阅(可选)
如果你的指令是结构型的,也可以用async pipe自动处理订阅和取消订阅,避免手动管理Subscription:
// 结构型指令版本 import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; import { PermissionService } from './permission.service'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Directive({ selector: '[appPermission]' }) export class PermissionStructuralDirective { @Input() set appPermission(requiredPermission: string) { const hasPermission$: Observable<boolean> = this.permissionService.currentPermissions$.pipe( map(permissions => permissions.includes(requiredPermission)) ); hasPermission$.subscribe(hasPermission => { if (hasPermission) { this.vcRef.createEmbeddedView(this.templateRef); } else { this.vcRef.clear(); } }); } constructor( private templateRef: TemplateRef<any>, private vcRef: ViewContainerRef, private permissionService: PermissionService ) {} }
用的时候像这样:
<div *appPermission="'edit'">只有拥有edit权限才会显示这个区块</div>
这样一来,权限服务更新时,所有使用该指令的视图都会自动同步,完全不需要组件手动传递数据,指令自己就会“监听”服务的变化并做出响应。
内容的提问来源于stack exchange,提问作者Chris Cooley
相关产品推荐
相关产品推荐

