2017-01-19 5 views
8

私はサーバーにリクエストし、受信した値を画面上にレンダリングするオートコンプリートコンポーネントを作りたいと思っています。 portaloverlayの仕組みを理解しようとしています。今のところこれはオートコンプリート角2材質 - オーバーレイとポータルはどのように機能しますか?

import { 
    Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewChild, ViewContainerRef, 
    ElementRef, Optional 
} from '@angular/core'; 
import { ControlValueAccessor } from '@angular/forms'; 
import { MdOption, ConnectedOverlayDirective, Dir, transformPlaceholder, transformPanel, fadeInContent } from '@angular/material'; 

import { Subscription } from 'rxjs/Subscription'; 
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 
import { Subject } from 'rxjs/Subject'; 

import { AutocompleteConfiguration } from './autocomplete-config.model'; 
import { SearchState, SearchingService, IBackend } from './../../services/searching.service'; 
import { ISearchConfig } from './../../models/iSearch-config'; 
import { IHint } from './../generic-form/generic-form.service'; 
import { getValueAccessorProviders } from './../../models/custom-value-accessor.builder'; 

@Component({ 
    selector: 'autocomplete', 
    templateUrl: './autocomplete.html', 

    providers: [ 
     SearchingService, 
     getValueAccessorProviders(AutocompleteComponent) 
    ], 
    animations: [ 
     transformPlaceholder, transformPanel, fadeInContent 
    ] 
}) 
export class AutocompleteComponent implements OnInit, OnDestroy, ControlValueAccessor { 
    /** Placeholder to be shown if no value has been selected. */ 
    @Input() 
    get placeholder() { return this._placeholder; } 
    set placeholder(value: string) { 
     this._placeholder = value; 

     // Must wait to record the trigger width to ensure placeholder width is included. 
     Promise.resolve(null).then(() => this._triggerWidth = this._getWidth()); 
    } 
    @Input() hint: IHint = null; 
    @Input() iconPosition: string = ''; // 'prefix', 'suffix' or 'placeholder-prefix', 'placeholder-suffix' 
    @Input() autocompleteConfigurtation: AutocompleteConfiguration; 
    @Input() backend: IBackend; 
    @ViewChild(ConnectedOverlayDirective) overlayDir: ConnectedOverlayDirective; 
    /** Trigger that opens the select. */ 
    @ViewChild('triggerRef', { read: ElementRef }) trigger: ElementRef; 

    @Output() blur: EventEmitter<FocusEvent> = new EventEmitter<FocusEvent>(); 
    @Output() focus: EventEmitter<FocusEvent> = new EventEmitter<FocusEvent>(); 

    get value() { 
     return this._inputValue; 
    } 
    set value(value: any) { 
     if (String(value) !== String(this._inputValue)) { 
      this._inputValue = String(value); 
     } 
    } 

    /** Whether or not the overlay panel is open. */ 
    private _panelOpen = false; 
    /** The currently selected option. */ 
    private _selected: MdOption; 
    private _placeholder: string; 
    /** 
    * The width of the trigger. Must be saved to set the min width of the overlay panel 
    * and the width of the selected value. 
    */ 
    private _triggerWidth: number; 

    private _inputValue: string = ''; 
    private _focused: boolean = false; 
    private _disabled: boolean = false; 

    private onSearchStateChange: BehaviorSubject<SearchState>; 
    private onModelChangeSubject: Subject<any> = new Subject<any>(); 
    private subscriptions: Subscription[] = []; 

    private searchState: SearchState = null; 

    /** 
    * The x-offset of the overlay panel in relation to the trigger's top start corner. 
    * This must be adjusted to align the selected option text over the trigger text when 
    * the panel opens. Will change based on LTR or RTL text direction. 
    */ 
    _offsetX = 0; 

    /** 
    * The y-offset of the overlay panel in relation to the trigger's top start corner. 
    * This must be adjusted to align the selected option text over the trigger text. 
    * when the panel opens. Will change based on the y-position of the selected option. 
    */ 
    _offsetY = 0; 

    /** The value of the select panel's transform-origin property. */ 
    _transformOrigin: string = 'top'; 

    /** The animation state of the placeholder. */ 
    _placeholderState = ''; 

    /** 
    * This position config ensures that the top "start" corner of the overlay 
    * is aligned with with the top "start" of the origin by default (overlapping 
    * the trigger completely). If the panel cannot fit below the trigger, it 
    * will fall back to a position above the trigger. 
    */ 
    _positions = [ 
     { 
      originX: 'start', 
      originY: 'top', 
      overlayX: 'start', 
      overlayY: 'top', 
     }, 
     { 
      originX: 'start', 
      originY: 'bottom', 
      overlayX: 'start', 
      overlayY: 'bottom', 
     }, 
    ]; 
    /** The scroll position of the overlay panel, calculated to center the selected option. */ 
    private _scrollTop = 0; 
    constructor(
     private searchBuilder: SearchingService, 
     @Optional() private _dir: Dir 
    ) { } 

    ngOnInit() { 
     this.onSearchStateChange = this.searchBuilder 
      .createSearchObservable(this.onModelChangeSubject, this.autocompleteConfigurtation.searchConfig, this.backend); 
     this.setSearchStateChangeSubscription(); 
    } 

    setSearchStateChangeSubscription() { 
     this.subscriptions.push(
      this.onSearchStateChange.subscribe(newState => { 
       debugger 
       this.searchState = newState; 
       // this._calculateOverlayPosition(); 
       this._placeholderState = this._isRtl() ? 'floating-rtl' : 'floating-ltr'; 
       this._panelOpen = newState && newState.responseObject && newState.responseObject.length > 0; 
      }) 
     ); 
    } 

    onModelChange(inputValue) { 
     this.value = inputValue; 
     this._onChangeCallback(this._inputValue); 
     this._onTouchedCallback(); 
     this._activateSearch(this.value); 
    } 

    // From ControlValueAccessor interface 
    // the ngModel init or form write value 
    writeValue(value: any) { 
     this.value = value; 
    } 

    // From ControlValueAccessor interface 
    registerOnChange(fn: any) { 
     this._onChangeCallback = fn; 
    } 

    // From ControlValueAccessor interface 
    registerOnTouched(fn: any) { 
     this._onTouchedCallback = fn; 
    } 

    setDisabledState(isDisabled: boolean) { 
     this._disabled = isDisabled; 
    } 

    close() { 

    } 

    ngOnDestroy() { 
     this.subscriptions.forEach(val => val.unsubscribe()); 
     this.subscriptions = []; 
     this.onModelChangeSubject.unsubscribe(); 
    } 

    /** 
    * Sets the scroll position of the scroll container. This must be called after 
    * the overlay pane is attached or the scroll container element will not yet be 
    * present in the DOM. 
    */ 
    _setScrollTop(): void { 
     const scrollContainer = 
      this.overlayDir.overlayRef.overlayElement.querySelector('.md-select-panel'); 
     scrollContainer.scrollTop = this._scrollTop; 
    } 
    /** The width of the trigger element. This is necessary to match 
     * the overlay width to the trigger width. 
     */ 
    _getWidth(): number { 
     return this._getTriggerRect().width; 
    } 

    _isRtl(): boolean { 
     return this._dir ? this._dir.value === 'rtl' : false; 
    } 

    _onPanelDone($event) { 
     console.log($event); 
    } 

    private _getTriggerRect(): ClientRect { 
     return this.trigger.nativeElement.getBoundingClientRect(); 
    } 

    private _activateSearch(value) { 
     if (this._disabled || !this.focus) { 
      return; 
     } 

     this.onModelChangeSubject.next(value); 
    } 

    private _handleFocus($event) { 
     this._focused = true; 

     if (this.autocompleteConfigurtation.activateOnFocus) { 
      this._activateSearch(this.value); 
     } 
     this.focus.emit($event); 
    } 

    private _handleBlur($event) { 
     this._focused = false; 
     this._onTouchedCallback(); 
     this.blur.emit($event); 
    } 

    private _onChangeCallback(_: any) { } 
    private _onTouchedCallback() { } 
} 

のための私のコンポーネントであり、これは、HTML

<md-input type="text" 
    #triggerRef 
    #origin="cdkOverlayOrigin" 
    cdk-overlay-origin 
    [disabled]="_disabled" 
    [(ngModel)]="value" 
    (blur)="_handleBlur($event)"  
    (focus)="_handleFocus($event)" 
    (ngModelChange)="onModelChange($event)"> 

    <md-placeholder *ngIf="placeholder || iconPosition.indexOf('placeholder') !== -1"> 
     <i *ngIf="iconPosition === 'placeholder-prefix'" class="material-icons app-input-icon">{{field.icon}}</i> 
     {{placeholder}} 
     <i *ngIf="iconPosition === 'placeholder-suffix'" class="material-icons app-input-icon">{{field.icon}}</i> 
    </md-placeholder> 
    <span md-prefix> 
     <md-icon *ngIf="iconPosition === 'prefix'">field.icon</md-icon> 
    </span> 
    <span md-suffix> 
     <md-icon *ngIf="iconPosition === 'suffix'">field.icon</md-icon> 
    </span> 
    <md-hint *ngIf="hint" [align]="hint.align"> 
     {{hint.value}} 
    </md-hint> 
</md-input> 
<template 
    cdk-connected-overlay 
    hasBackdrop 
    backdropClass="cdk-overlay-transparent-backdrop" 
    [origin]="origin" 
    [open]="_panelOpen" 
    [positions]="_positions" 
    [minWidth]="_triggerWidth" 
    [offsetY]="_offsetY" 
    [offsetX]="_offsetX" 
    (backdropClick)="close()" 
    (attach)="_setScrollTop()"> 
    <div class="md-select-panel" 
     [@transformPanel]="'showing'" 
     [style.transformOrigin]="_transformOrigin" 
     [class.md-select-panel-done-animating]="_panelDoneAnimating" 
     (@transformPanel.done)="_onPanelDone()" 
     (keydown)="log($event)"> 
     <div class="md-select-content" [@fadeInContent]="'showing'"> 
      <md-option *ngFor="let option of searchState?.responseObject" 
         [value]="option.value"> 
         {{ option?.text }} 
      </md-option> 
     </div> 
    </div> 
</template> 

コンポーネント作品であり、それはそれが必要としてオーバーレイをレンダリングします。オーバーレイコンテナはオプションをレンダリングします。唯一の問題は幅です。 私はポータルとオーバーレイのコアコンセプトを読みましたが、どのように実際に角度をもって動作するかを理解したいと思います。

誰でも少し動作を説明できますか?少なくとも、私はそれが幅をどのように制御するのですか?

答えて

0

私は誰があなた は、私はそれがうまくいくと思うか に関するコメントを追加しようと見hereを持ってしようとすることができる例を望んでいる場合は、オーバーレイコンポーネントを使用することができました。また、それについてのいくつかのドキュメントとそれを使用する方法 は、@角度/材料からより歓迎されるでしょう。私は隠されたオーバーフローの問題を持っているか、CDKのドキュメントも cdk docs hereリリースされた

translate3dないように ドームツリーでレンダリングする必要がサードパーティのコンポーネントを作成することは非常に 使用可能だと思うことは便利なガイドでありますオーバーレイのために。

関連する問題