2016-04-23 16 views
6

Làm thế nào để gọi hàm của thành phần gốc khi thành phần con quan sát đầu vào thay đổi?Làm thế nào để quan sát các thay đổi phần tử đầu vào trong ng-content

Dưới đây là cấu trúc HTML.

# app.comopnent.html 
<form> 
    <textbox> 
    <input type="text"> 
    </textbox> 
</form> 

# textbox.component.html 
<div class="textbox-wrapper"> 
    <ng-content> 
</div> 

Hạn chế như sau.

  • TextboxComponent có ng-content và cần phải chiếu thành phần input vào đó.
  • Phát ra sự kiện trong TextboxComponent khi phần tử input được nhập vào nội dung nào đó.
  • Không muốn tạo thành phần input để có nhiều thuộc tính hơn, ví dụ: <input type="text" (input)="event()">.

tôi đang viết mã, nhưng không thể tìm thấy một giải pháp ...

# input.directive.ts 
@Directive({ selector: 'input', ... }) 
export class InputDirective { 
    ngOnChanges(): void { 
    // ngOnChanges() can observe only properties defined from @Input Decorator... 
    } 
} 

# textbox.component.ts 
@Component({ selector: 'textbox', ... }) 
export class TextboxComponent { 
    @ContentChildren(InputDirective) inputs: QueryList<InputDirective>; 
    ngAfterContentInit(): void { 
    this.inputs.changes.subscribe((): void => { 
     // QueryList has a changes property, it can observe changes when the component add/remove. 
     // But cannot observe input changes... 
    }); 
    } 
} 
+0

Tại sao bạn không muốn sử dụng một sản lượng ràng buộc, như ? Làm thế nào bạn có thể chắc chắn rằng các nhà phát triển khác (hoặc thậm chí bạn) chỉ thêm các yếu tố đầu vào vào đánh dấu của TextboxComponent? – rrjohnson85

+0

Bởi vì tôi nên nối thêm đầu ra vào phần tử 'input' và nó sẽ tiết nếu tôi muốn sử dụng nó. Nhưng tôi có thể sử dụng thuộc tính 'host: {(input): 'event()'}' trong InputDirective. Vấn đề lớn nhất là TextboxComponent sử dụng 'ng-content' có thể phát hiện khi InputDirective được nhập vào bất cứ thứ gì. –

Trả lời

5

Sự kiện input đang sủi bọt và có thể được lắng nghe trên thành phần cha mẹ

<div class="textbox-wrapper" (input)="inputChanged($event)"> 
    <ng-content></ng-content> 
</div> 

Plunker example

+0

Oh! Tôi không biết ... Tôi có thể nhận được hành vi mong đợi !! Cảm ơn bạn!! –

1

Bạn có thể sử dụng các tình huống sau, mà đã hostbinding tài sản trên thị đầu vào

input.directive.ts

import {Directive, HostBinding} from 'angular2/core'; 
import {Observer} from 'rxjs/Observer'; 
import {Observable} from 'rxjs/Observable'; 

@Directive({ 
    selector: 'input', 
    host: {'(input)': 'onInput($event)'} 
}) 
export class InputDirective { 
    inputChange$: Observable<string>; 
    private _observer: Observer<any>; 
    constructor() { 
    this.inputChange$ = new Observable(observer => this._observer = observer); 
    } 
    onInput(event) { 
    this._observer.next(event.target.value); 
    } 
} 

Và sau đó TextBoxComponent của bạn sẽ đăng ký trên Quan sát đối tượng được định nghĩa ở trên trong lớp InputDirective.

textbox.component.ts

import {Component, ContentChildren,QueryList} from 'angular2/core'; 
import {InputDirective} from './input.directive'; 
@Component({ 
    selector: 'textbox', 
    template: ` 
    <div class="textbox-wrapper"> 
     <ng-content></ng-content> 
     <div *ngFor="#change of changes"> 
     {{change}} 
     </div> 
    </div> 
    ` 
}) 
export class TextboxComponent { 
    private changes: Array<string> = []; 
    @ContentChildren(InputDirective) inputs: QueryList<InputDirective>; 

    onChange(value, index) { 
    this.changes.push(`input${index}: ${value}`); 
    } 

    ngAfterContentInit(): void { 
    this.inputs.toArray().forEach((input, index) => { 
     input.inputChange$.subscribe(value => this.onChange(value, index + 1)); 
    }); 
    } 
} 

Dưới đây là plunker sample

+0

Cảm ơn bạn. Lúc đầu, tôi nghĩ rằng tôi cần phải sử dụng RxJS nhưng nó rất phức tạp ... –

0

Bạn có thể thêm một ngControl trên yếu tố đầu vào của bạn.

<form> 
    <textbox> 
    <input ngControl="test"/> 
    </textbox> 
</form> 

Bằng cách này bạn có thể sử dụng NgControl trong ContentChild. Nó truy cập vào thuộc tính valueChanges mà bạn có thể đăng ký để được thông báo về các bản cập nhật.

@Component({ selector: 'textbox', ... }) 
export class TextboxComponent { 
    @ContentChild(NgControl) input: NgControl; 
    ngAfterContentInit(): void { 
    this.input.control.valueChanges.subscribe((): void => { 
     (...) 
    }); 
    } 
} 
+0

Cảm ơn bạn. Tôi không thể mong đợi vì sử dụng 'ngAfterContentInit'. Tôi đã nhận được sự kiện phát ra khi sử dụng 'ngAfterViewChecked', nhưng nó được thực thi nhiều lần ... –

4

Trong ngAfterViewInit(), tìm các phần tử (s) quan tâm, sau đó phải nhất thiết thêm sự kiện người nghe (S). Đoạn code dưới đây giả định chỉ có một đầu vào:

@Component({ 
    selector: 'textbox', 
    template: `<h3>textbox value: {{inputValue}}</h3> 
     <div class="textbox-wrapper"> 
     <ng-content></ng-content> 
     </div>`, 
}) 
export class TextboxComp { 
    inputValue:string; 
    removeListenerFunc: Function; 
    constructor(private _elRef:ElementRef, private _renderer:Renderer) {} 
    ngAfterContentInit() { 
    let inputElement = this._elRef.nativeElement.querySelector('input'); 
    this.removeListenerFunc = this._renderer.listen(
     inputElement, 'input', 
     event => this.inputValue = event.target.value) 
    } 
    ngOnDestroy() { 
    this.removeListenerFunc(); 
    } 
} 

Plunker

Câu trả lời này thực chất là một cách tiếp cận bắt buộc, trái ngược với cách tiếp cận declarative Günter của. Cách tiếp cận này có thể dễ dàng mở rộng hơn nếu bạn có nhiều đầu vào.


Có vẻ như không phải là một cách để sử dụng @ContentChild() (hoặc @ContentChildren()) để tìm phần tử DOM trong người dùng cung cấp mẫu (ví dụ, nội dung ng-content) ... cái gì đó như @ContentChild(input) doesn' t dường như tồn tại. Do đó lý do tôi sử dụng querySelector().

Trong bài viết trên blog này, http://angularjs.blogspot.co.at/2016/04/5-rookie-mistakes-to-avoid-with-angular.html, Kara đề nghị xác định một Chỉ thị (nói InputItem) với một selector input và sau đó sử dụng @ContentChildren(InputItem) inputs: QueryList<InputItem>;. Sau đó, chúng tôi không cần phải sử dụng querySelector(). Tuy nhiên, tôi không đặc biệt thích cách tiếp cận này vì người dùng TextboxComponent phải bằng cách nào đó cũng bao gồm InputItem trong mảng directives (tôi đoán một số tài liệu thành phần có thể giải quyết được vấn đề, nhưng tôi vẫn không phải là người hâm mộ). Đây là một số plunker cho phương pháp này.

+0

oh, cảm ơn bạn! Tôi sẽ sử dụng nó để tham khảo. –

0

Bạn có thể sử dụng các quan sát viên CDK góc https://material.angular.io/cdk/observers/api

nhập module này trong module của bạn

import { ObserversModule } from '@angular/cdk/observers'; 

sau đó sử dụng trong tố ng-content's mẹ

<div class="projected-content-wrapper (cdkObserveContent)="contentChanged()"> 
<ng-content></ng-content> 
</div> 
Các vấn đề liên quan