angular – 从ng-content向父级发送输出
发布时间:2020-12-17 17:09:08 所属栏目:安全 来源:网络整理
导读:我正在尝试使用按钮组件和下拉组件为Bootstrap拆分式下拉按钮创建一个包装器.我需要在点击和文档上发出输出:从ng-content(这是一个 button perf-btn)单击到父DropdownComponent. 有几个类似的问题,但似乎没有一个适合我的用例. 用法(app.component.html) pe
我正在尝试使用按钮组件和下拉组件为Bootstrap拆分式下拉按钮创建一个包装器.我需要在点击和文档上发出输出:从ng-content(这是一个< button perf-btn>)单击到父DropdownComponent.
有几个类似的问题,但似乎没有一个适合我的用例. 用法(app.component.html) <perf-drop [data]="items"> <button perf-btn>Default Dropdown Button</button> // click doesn't open dropdown <button perf-btn dropdown="true"></button> // click opens dropdown </perf-drop> dropdown.component.html <ng-content select="[perf-btn]" (notify)='onNotify($event)')></ng-content> <ul class="dropdown-menu"> <template ngFor let-item [ngForOf]="data"> <li *ngIf="item.separator" role="separator" class="divider"></li> <li *ngIf="!item.separator" [class.disabled]="item.disabled"> <a [routerLink]="item.path" [ngClass]="getItemColor(item.color)"> {{item.label}} </a> </li> </template> </ul> dropdown.component.ts import { Component,Input,ElementRef} from '@angular/core'; @Component({ selector: 'perf-drop',host: { '[attr.disabled]': 'disabled','[class.open]': 'isOpen' },templateUrl: 'dropdown.component.html',styleUrls: ['dropdown.component.scss'] }) export class DropdownComponent { private _data: any[] = []; private _isOpen: boolean = false; @Input() get isOpen() { return this._isOpen; } set isOpen(value: boolean) { this._isOpen = value ? true : null; } @Input() get data(): any[] { return this._data; } set data(value: any[]) { this._data = value; } constructor(private _elementRef: ElementRef) { } private toggle(): void { this._isOpen = !this._isOpen; } private close(event): void { if (!this._elementRef.nativeElement.contains(event.target) && this._isOpen) this._isOpen = false; } private getItemColor(color) { if (color) return `text--${color}`; } } btn.component.ts import { Component,ViewEncapsulation,HostBinding,ChangeDetectionStrategy,ElementRef,Renderer,EventEmitter,Output } from '@angular/core'; @Component({ selector: 'button[perf-btn],input[perf-btn],a[perf-btn],div[perf-btn],perf-btn',host: { [snip conditional classes],"(click)": "_toggle()","(document:click)": "_close($event)" },templateUrl: './btn.component.html',styleUrls: ['./btn.component.scss'] }) export class BtnComponent { [snip irrelevant fields] private _dropdown: boolean; private _state: boolean = false; @Input() get dropdown() { return this._dropdown; } set dropdown(value: boolean) { this._dropdown = value ? true : null; } get state() { return this._state; } set state(value: boolean) { this._state = value ? true : null; } [snip irrelevant getters/setters] @Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>(); constructor(private _elementRef: ElementRef,private _renderer: Renderer) { } _toggle() { console.log("notifying " + this._state); this._state = !this._state; this.notify.emit(this._state); } _close(event) { if (!this._elementRef.nativeElement.contains(event.target) && this._state) { this._state = false; this.notify.emit(this._state); } } [snip irrelevant functions] } btn.component.html <ng-content></ng-content> <span class="caret" *ngIf="dropdown"></span> dropdown.directive.ts import { Directive } from '@angular/core'; import { BtnDirective } from './btn.directive'; @Directive({ selector: `button[perf-drop],button[perf-drop],a[perf-drop],input[perf-drop],div[perf-drop],perf-drop`,host: { '[class.btn-group]': 'true','[attr.disabled]': '[disabled]' } }) export class DropdownDirective extends BtnDirective {} btn.directive.ts import { Directive } from '@angular/core'; @Directive({ selector: `button[perf-btn],button[perf-btn],perf-btn`,host: { '[class.btn]': 'true' } }) export class BtnDirective {} 解决方法
感谢@AngularFrance,我了解到ng-content无法发出.但是,服务可以在父组件和子ng内容之间进行通信.
请参阅//注释我添加到原始组件的内容,以使它们与服务一起使用. 另见Bidirectional Communication食谱食谱. btn.service.ts import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/Subject'; import { Observable } from 'rxjs/Observable'; @Injectable() export class BtnService { private _stateSource: Subject<boolean> = new Subject<boolean>(); public state$: Observable<Subject<boolean>> = this._stateSource.asObservable(); public toggle(state: boolean): void { console.log("toggling"); this._stateSource.next(state); } public close(): void { this._stateSource.next(false); } public open(): void { this._stateSource.next(true); } } dropdown.component.ts import { Component,OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs/Subscription'; // import subscription import { BtnService } from './btn.service'; // import service @Component({ selector: 'perf-drop','[class.open]': '_isOpen' },styleUrls: ['dropdown.component.scss'],providers: [BtnService] // add service as provider to parent }) export class DropdownComponent implements OnDestroy { private _data: any[] = []; private _isOpen: boolean = false; private _subscription: Subscription; get isOpen() { return this._isOpen; } set isOpen(value: boolean) { this._isOpen = value ? true : null; } @Input() get data(): any[] { return this._data; } set data(value: any[]) { this._data = value; } constructor(private _elementRef: ElementRef,private _service: BtnService) { // add to constructor this._subscription = _service.state$.subscribe( // subscribe to service state => { this._isOpen = state; }) } ngOnDestroy() { // prevent memory leak when component destroyed this._subscription.unsubscribe(); } } btn.component.ts import { Component,EventEmitter } from '@angular/core'; import { BtnService } from './btn.service'; // import service @Component({ selector: 'button[perf-btn],host: { "(click)": "_dropdown && _toggle()","(document:click)": "_dropdown && _close()" },styleUrls: ['./btn.component.scss'] }) export class BtnComponent { private _dropdown: boolean; private _state: boolean; @Input() get dropdown() { return this._dropdown; } set dropdown(value: boolean) { this._dropdown = value ? true : null; } @Input() get state() { return this._state; } set state(value: boolean) { this._state = value; } constructor(private _elementRef: ElementRef,private _renderer: Renderer,private _service: BtnService) { // add service to constructor } _toggle() { this._state = !this._state; this._service.toggle(this._state); // call service } _close() { if (!this._elementRef.nativeElement.contains(event.target) && this._state) { this._state = false; this._service.close(); // call service } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- Bootstrap WPF Style
- 在angular2中插入相对路径的图像
- 如何在bash中从特定应用程序数据库文件创建日志文件?
- CXF WebService 7 - Spring整合CXF,发布RSETful 风格WebSe
- Kubernetes-kubectl exec bash-会话拖放和行宽
- twitter-bootstrap – 输入组 – 两个输入彼此接近
- unix – POSIX线程:pthreads_cond_wait()和其他系统调用?
- RxJS - Observables, observers 和 operators 简介
- Angular 2按字符串名称获取服务
- AngularJS四大核心特性