2016-08-22 10 views
12

いくつかの類似したスレッドがありますが、私のニーズに合わせて適切な答え を見つけることができませんでした。だから直接DOMアクセスは厳密に回避する必要があります私はちょうどこれのためのベストプラクティスを疑問に思っています。Angular2の(DOM)要素の幅を取得する方法

私が達成しようとしているのは、現在の幅に基づいた要素のサイズ変更です。

workitemresize.component.ts

import { Directive, ElementRef, HostListener, Renderer, Input } from '@angular/core'; 

@Directive({ 
    selector: '[workItemResize]' 
}) 

export class WorkItemResizeDirective implements ngAfterViewInit { 

    private el: HTMLElement; 
    private renderer: Renderer; 

    constructor(el: ElementRef, public renderer: Renderer) 
    { 
    this.el = el.nativeElement; 
    this.renderer = renderer; 
    } 


    @HostListener('window:resize', ['$event.target']) 
    onResize() 
    { 
    this.resizeWorks(); 
    } 

    ngAfterViewInit() { 
    this.resizeWorks(); 
    } 

    private resizeWorks(): void { 
    this.renderer.setElementStyle(this.el, 'height', this.el.width); // <-- doesn't work I kow that this.el.width doesn't exist but just for demonstration purpose 
    this.renderer.setElementStyle(this.el, 'height', '500'); // <-- works 
    } 

} 

<div class="posts row"> 
     <div class="work-item col-xs-12 col-sm-6 col-no-padding" workItemResize *ngFor="let post of posts"> 

       <!-- show some fancy image --> 
       <div class="img" [ngStyle]="{'background-image':'url('+post.better_featured_image.source_url+')'}"></div> 

     </div> 
</div> 

関連projects.template.html:私は取得する方法を知らない https://github.com/angular/angular/issues/6515

+0

エンドレスループのような音で現在のサイズに基づいてサイズを変更します。 –

+0

initビューの直後で、window.resizeで - これはうまくいくはずです – kkern

答えて

10

0123にアクセスせずにホスト要素からの幅あなたは、これはすべて(ただし、INIT後)をで直接DOMにアクセスせずに動作します

<div style="width: 100%;" #div (window:resize)="elHeight = div.getBoundingClientRect()"> 
    <!-- your template here --> 
</div> 

のようなあなたのコンポーネントテンプレート内の要素を追加することができた場合

@HostListener('window:resize', ['$event.target']) 
onResize() { 
    this.resizeWorks(); 
} 

@HostBinding('style.height.px') 
elHeight:number; 

private resizeWorks(): void { 
    this.elHeight = this.el.nativeElement.width; 
} 

:が、設定は次のように行うことができます。

+0

@HostBindingとRendererのアプローチには大きな違いはありますか?私は両方のバージョンが良いと思う? ああ、this.el.nativeElement.widthは常にnullです...私もこれで苦労していました。何について:this.renderer.setElementStyle(this.el、 'height'、this.el.clientWidth + 'px');それは動作しますが、私には奇妙に見えます... – kkern

+0

レンダラーのアプローチも同様です。私は 'HostBinding'アプローチを読みやすくしています。あなたの質問には 'this.el.nativeElement.width'の代わりに' this.el.width'があります。 'resizeWorks'は、コンポーネントが完全にレンダリングされる前に呼び出されるか、そうでなければ' getBoundingClientRect()。width'を試していると仮定します。 –

+1

this.elはel.nativeElementを参照します(コンストラクタを参照)。私はgetBoundingClientRect()に固執しています。ありがとうございました! 最終コード行: this.renderer.setElementStyle(this.el、 'height'、this.el.getBoundingClientRect()。width + "px"); – kkern

8

私は@GünterZöchbauerソリューションを試してみました。 divの境界を取得するためにHostListenerは必要ありません。 'click'や他のイベント(event)= "function()"と同様に、この関数を起動します。私は誰かがこれが役に立つと思うことを願っている

<div #div (window:resize)="onResize(div.getBoundingClientRect())"> 
    <!-- your template here --> 
</div> 


onResize() { 
    this.resizeWorks(); 
} 

@HostBinding('style.height.px') elHeight:number; 

private resizeWorks(): void { 
    this.elHeight = this.el.nativeElement.width; 
} 

(#div) - これは測定対象を取得するために必要な変数です。要素と同じ名前である必要はなく、任意の名前を使用できます。

さらに、要素の寸法を取得するもう1つの方法は、角度コアからElementRefクラスを使用することですが、幅と高さのプロパティを持つ子要素を見つける必要があります。私はAngular 2 Mapsでこれを使ってコンテナの幅と高さを取得しましたが、このメソッドを使って、これらのプロパティを持つ要素ツリー要素で見つけなければならず、ルート要素の2番目の子でした​​。それはもっと面倒です。 ElementDimensions - これらのプロパティを含めるために作成した高さと幅を持つクラスです。

<div (window:resize)="onResize()"> 
    <!-- your template here --> 
</div> 

private getContainerDimensions(): ElementDimensions{ 
    var rootElement = this.elementRef.nativeElement; 
    var childElement = rootElement.firstElementChild; 
    var contentElement = childElement.firstElementChild; 

    return { 
     height:contentElement.clientHeight, 
     width: contentElement.clientWidth 
    }; 
} 
+0

また素敵な解決策! – kkern

0

表示プロパティが定義されている場合は、コンポーネント自体の幅を取得できます(下の例では「ブロック」など)。あなたは(DOMシャドウイングを使用して)このスタイルを定義することができる必要があることに注意してください:

:host { 
    display:block; 
} 

あなたはシャドーイングDOM(イオン2-3)を使用していない場合:ここでは

my-component { 
    display:block; 
} 

は、コントローラ(さらすことです観測可能な幅):

import {AfterViewInit, Component, ElementRef, HostListener, Input} from '@angular/core'; 
import {Subject} from 'rxjs/Subject'; 

@Component({ 
    selector: 'my-component', 
    template: '{{$width|async}}', 
    style: 'my-component {display: block;}' 
}) 
export class MyComponent implements AfterViewInit { 
    @Input() public gridWidth: number; 
    private $width: Subject<number> = new Subject(); 

    constructor(private elementRef: ElementRef) { 
    } 

    public ngAfterViewInit(): void { 
     this.emitWidth(); 
    } 

    @HostListener('window:resize', ['$event.target']) 
    public onResize(): void { 
     this.emitWidth(); 
    } 

    private emitWidth(): void { 
     this.$width.next(this.getWidth()); 
    } 

    private getWidth(): number { 
     return this.getNativeElement().clientWidth; 
    } 

    private getNativeElement(): HTMLElement { 
     return this.elementRef.nativeElement; 
    } 
} 
関連する問題