我正在嘗試使用按鈕組件和下拉組件爲Bootstrap拆分式下拉按鈕創建一個包裝。我需要從ng-content
(這是一個<button perf-btn>
)click
和document:click
發出輸出到父母DropdownComponent
。將ng內容的輸出發送給父項
有幾個類似的問題,但似乎沒有適合我的用例。
使用(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, Input, 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], a[perf-btn], input[perf-btn],
div[perf-btn], perf-btn`,
host: {
'[class.btn]': 'true'
}
})
export class BtnDirective {}
你不能 「通過」 發射輸出事件''因爲父母不能聽這個事件。 –
AngularChef
@AngularFrance,我明白了......這讓事情變得更加複雜。 :/ – user2706191
您始終可以在需要通信的所有組件中注入相同的服務。這樣,不需要輸出。 – AngularChef