web-dev-qa-db-fra.com

Evénement de redimensionnement de fenêtre angulaire

J'aimerais effectuer certaines tâches en fonction de l'événement de redimensionnement de la fenêtre (en charge et de manière dynamique).

Actuellement, j'ai mon DOM comme suit:

<div id="Harbour">
    <div id="Port" (window:resize)="onResize($event)" >
        <router-outlet></router-outlet>
    </div>
</div>

L'événement se déclenche correctement

export class AppComponent {
   onResize(event) {
        console.log(event);
    }
}

Comment récupérer la largeur et la hauteur de cet objet événement?

Merci.

147
DanAbdn
<div (window:resize)="onResize($event)"
onResize(event) {
  event.target.innerWidth;
}

ou

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

Les cibles globales prises en charge sont window, document et body.

Jusqu'à ce que https://github.com/angular/angular/issues/13248 soit implémenté dans Angular, il est préférable pour les performances de s'abonner impérativement aux événements DOM et d'utiliser RXJS pour réduire le nombre d'événements indiqué dans autres réponses.

364
Günter Zöchbauer

@ La réponse de Günter est correcte. Je voulais juste proposer encore une autre méthode. 

Vous pouvez également ajouter la liaison hôte à l'intérieur de la @Component()- décorator. Vous pouvez placer l'événement et l'appel de fonction souhaité dans la propriété Host-metadata-property de la manière suivante:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  Host: {
    '(window:resize)': 'onResize($event)'
  }
})
export class AppComponent{
   onResize(event){
     event.target.innerWidth; // window width
   }
}
50
John

Pour ce faire, utilisez la classe EventManager pour lier l'événement. Cela permet à votre code de fonctionner sur d'autres plates-formes, par exemple le rendu côté serveur avec Angular Universal.

import { EventManager } from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Injectable } from '@angular/core';

@Injectable()
export class ResizeService {

  get onResize$(): Observable<Window> {
    return this.resizeSubject.asObservable();
  }

  private resizeSubject: Subject<Window>;

  constructor(private eventManager: EventManager) {
    this.resizeSubject = new Subject();
    this.eventManager.addGlobalEventListener('window', 'resize', this.onResize.bind(this));
  }

  private onResize(event: UIEvent) {
    this.resizeSubject.next(<Window>event.target);
  }
}

L'utilisation dans un composant est aussi simple que d'ajouter ce service en tant que fournisseur à votre app.module, puis de l'importer dans le constructeur d'un composant.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-component',
  template: ``,
  styles: [``]
})
export class MyComponent implements OnInit {

  private resizeSubscription: Subscription;

  constructor(private resizeService: ResizeService) { }

  ngOnInit() {
    this.resizeSubscription = this.resizeService.onResize$
      .subscribe(size => console.log(size));
  }

  ngOnDestroy() {
    if (this.resizeSubscription) {
      this.resizeSubscription.unsubscribe();
    }
  }
}
28
cgatian

Voici une meilleure façon de le faire. Basé sur Birowsky's answer.

Étape 1: Créez un angular service avec RxJS Observables .

import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';

@Injectable()
export class WindowService {
    height$: Observable<number>;
    //create more Observables as and when needed for various properties
    hello: string = "Hello";
    constructor() {
        let windowSize$ = new BehaviorSubject(getWindowSize());

        this.height$ = (windowSize$.pluck('height') as Observable<number>).distinctUntilChanged();

        Observable.fromEvent(window, 'resize')
            .map(getWindowSize)
            .subscribe(windowSize$);
    }

}

function getWindowSize() {
    return {
        height: window.innerHeight
        //you can sense other parameters here
    };
};

Étape 2: Injectez la service ci-dessus et abonnez-vous à l'une des Observables créées dans le service, où que vous souhaitiez recevoir l'événement de redimensionnement de la fenêtre.

import { Component } from '@angular/core';
//import service
import { WindowService } from '../Services/window.service';

@Component({
    selector: 'pm-app',
    templateUrl: './componentTemplates/app.component.html',
    providers: [WindowService]
})
export class AppComponent { 

    constructor(private windowService: WindowService) {

        //subscribe to the window resize event
        windowService.height$.subscribe((value:any) => {
            //Do whatever you want with the value.
            //You can also subscribe to other observables of the service
        });
    }

}

Une bonne compréhension de la programmation réactive aidera toujours à surmonter des problèmes difficiles. J'espère que ça aide quelqu'un.

24
Giridhar Karnik

Je sais que cela a été demandé il y a longtemps, mais il existe un meilleur moyen de le faire maintenant! Je ne suis pas sûr si quelqu'un verra cette réponse cependant. Évidemment vos importations:

import { fromEvent } from "rxjs/observable/fromEvent";
import { Observable } from "rxjs/Observable";
import { Subscription } from "rxjs/Subscription";

Puis dans votre composant:

resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

ngOnInit() {
    this.resizeObservable$ = fromEvent(window, 'resize')
    this.resizeSubscription$ = this.resizeObservable$.subscribe( evt => {
      console.log('event: ', evt)
    })
}

Alors, assurez-vous de vous désabonner de destroy!

ngOnDestroy() {
    this.resizeSubscription$.unsubscribe()
}
15
Chris Stanley

En supposant que <600px signifie mobile pour vous, vous pouvez utiliser cet observable et vous y abonner:

Nous avons d’abord besoin de la taille actuelle de la fenêtre. Nous créons donc un observable qui n'émet qu'une seule valeur: la taille de la fenêtre actuelle.

initial$ = Observable.of(window.innerWidth > 599 ? false : true);

Ensuite, nous devons créer une autre observable, afin de savoir quand la taille de la fenêtre a été modifiée. Pour cela, nous pouvons utiliser l'opérateur "fromEvent". Pour en savoir plus sur les opérateurs de rxjs, rendez-vous sur: rxjs

resize$ = Observable.fromEvent(window, 'resize').map((event: any) => {
  return event.target.innerWidth > 599 ? false : true;
 });

Fusion de ces deux flux pour recevoir notre observable:

mobile$ = Observable.merge(this.resize$, this.initial$).distinctUntilChanged();

Maintenant, vous pouvez vous y abonner comme ceci:

mobile$.subscribe((event) => { console.log(event); });

N'oubliez pas de vous désabonner :)

6
Flosut Mözil

Basé sur la solution de @cgatian, je suggérerais la simplification suivante:

import { EventManager } from '@angular/platform-browser';
import { Injectable, EventEmitter } from '@angular/core';

@Injectable()
export class ResizeService {

  public onResize$ = new EventEmitter<{ width: number; height: number; }>();

  constructor(eventManager: EventManager) {
    eventManager.addGlobalEventListener('window', 'resize',
      e => this.onResize$.emit({
        width: e.target.innerWidth,
        height: e.target.innerHeight
      }));
  }
}

Usage:

import { Component } from '@angular/core';
import { ResizeService } from './resize-service';

@Component({
  selector: 'my-component',
  template: `{{ rs.onResize$ | async | json }}`
})
export class MyComponent {
  constructor(private rs: ResizeService) { }
}
3
Johannes Hoppe

Ce n'est pas une réponse exacte à la question, mais cela peut aider quelqu'un qui doit détecter des changements de taille sur n'importe quel élément.

J'ai créé une bibliothèque qui ajoute un événement resized à un élément - Evénement de redimensionnement angulaire.

Il utilise en interne ResizeSensor de CSS Element Queries .

Exemple d'utilisation

HTML

<div (resized)="onResized($event)"></div>

Manuscrit

@Component({...})
class MyComponent {
  width: number;
  height: number;

  onResized(event: ResizedEvent): void {
    this.width = event.newWidth;
    this.height = event.newHeight;
  }
}
2
Martin Volek

J'ai écrit cette bibliothèque pour trouver une fois le changement de taille de composant (redimensionnement) dans Angular, que cela puisse aider d'autres personnes. Vous pouvez le mettre sur le composant racine, fera la même chose que redimensionner une fenêtre.

Etape 1: Importer le module

import { BoundSensorModule } from 'angular-bound-sensor';

@NgModule({
  (...)
  imports: [
    BoundSensorModule,
  ],
})
export class AppModule { }

Étape 2: Ajouter la directive comme ci-dessous

<simple-component boundSensor></simple-component>

Étape 3: Recevez les détails de la taille de la limite

import { HostListener } from '@angular/core';

@Component({
  selector: 'simple-component'
  (...)
})
class SimpleComponent {
  @HostListener('resize', ['$event'])
  onResize(event) {
    console.log(event.detail);
  }
}
1
PRAISER

Sur Angular2 (2.1.0), j'utilise ngZone pour capturer l'événement de changement d'écran.

Regardez l'exemple:

import { Component, NgZone } from '@angular/core';//import ngZone library
...
//capture screen changed inside constructor
constructor(private ngZone: NgZone) {
    window.onresize = (e) =>
    {
        ngZone.run(() => {
            console.log(window.innerWidth);
            console.log(window.innerHeight);
        });
    };
}

J'espère que cette aide!

1
Anh Hoang

Il existe un service ViewportRuler dans angular CDK. Il fonctionne en dehors de la zone et fonctionne également avec le rendu côté serveur.

0
Totati

Le code ci-dessous permet d'observer tout changement de taille pour un div donné en angulaire.

<div #observed-div>
</div>

puis dans le composant:

oldWidth = 0;
oldHeight = 0;

@ViewChild('observed-div') myDiv: ElementRef;
ngAfterViewChecked() {
  const newWidth = this.myDiv.nativeElement.offsetWidth;
  const newHeight = this.myDiv.nativeElement.offsetHeight;
  if (this.oldWidth !== newWidth || this.oldHeight !== newHeight)
    console.log('resized!');

  this.oldWidth = newWidth;
  this.oldHeight = newHeight;
}
0
abedfar