4

In my Angular 2 app, I change styles based on browser window width. Here is a sample (SCSS):

.content{
    /*styles for narrow screens*/
    @media (max-width: 750px){
        background-color:beige;
    }
    /*styles for medium screens*/
    @media (min-width: 751px) and (max-width: 1200px) {
        background-color:red;
    }
    /*styles for wide screens*/
    @media (min-width: 1201px) {
        background-color:brown;
    }   
}

This makes my UI responsive. I'd like my Angular components to know which width interval is current:

/* Returns which of the CSS width intervals is current*/
getWidthRange(){
    let pixelWidth = ...; //what goes here?

    if(pixelWidth < 251) return "small";
    if(pixelWidth < 451) return "medium";
    return "large"; 
}   

A component would call this function and adjust its behavior based on width. For instance, the template below will show more content on wider screens:

<div>
    {{getWidthRange()==='small'? shortText : longText}}
</div>

Even better, I would setup an Observable that emits when the browser transitions from one range to the next:

widthRangeChanges = Observable.create( observer => 
    {       
        // ? how to detect when width changes
        let oldRange = '...';
        let newRange = '...';
        if(newRange!==oldRange) observer.next(newRange);
    }
).share(); //all subscribers share same output channel

The component could then subscribe to widthRangeChanges and update model values when a new range is received. How can I get hold of this info in Angular 2?

Angular 2 rc-6, typescript 2.0.2, rxjs 5 beta 11

BeetleJuice
  • 39,516
  • 19
  • 105
  • 165

3 Answers3

13

You can use fromEvent operator of RxJS:

 const $resizeEvent = Observable.fromEvent(window, 'resize')
   .map(() => {
     return document.documentElement.clientWidth;
   })
   .debounceTime(200)

   $resizeEvent.subscribe(data => {
     this.width = data;
   });

Plunker Example

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • Thanks for the tip. I didn't know about `fromEvent`. Are these events proprietary to RxJS, or can I turn any JS event into an Observable this way? – BeetleJuice Sep 17 '16 at 19:09
  • I guess it is only for DOM events – yurzui Sep 17 '16 at 19:14
  • That's a great tip, and the Plunker as well. I will try it out. Here is a link to make the answer more helpful: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-fromEvent – BeetleJuice Sep 17 '16 at 19:16
  • 1
    I used your solution. There is no need to use `map` though. `fromEvent` can take a third argument, a function that returns what you want the Observable to emit. Please see https://plnkr.co/edit/lgkRt8nNMScPOH7QmrBS?p=preview – BeetleJuice Sep 17 '16 at 19:57
  • Yes, of course. It looks better. I just changed my previous answer. http://stackoverflow.com/questions/39546698/the-properties-target-and-length-doesnt-seem-to-exist-on-type-in-angul/39547185#39547185 – yurzui Sep 17 '16 at 20:01
  • 1
    Thank you, very elegant solution!. Just one thing: In modern angular versions you should import fromEvent, map and debounceTime using this approach: https://stackoverflow.com/questions/50571550/this-property-fromevent-does-not-exist-on-type-typeof-observable-angular-6 – Miguel Lara Apr 15 '19 at 10:33
4

Template

<div (window:resize)="onResize($event)"></div>

export class AppComponent {            
      onResize(event) {
        console.log(event);
        console.log("width:" + event.target.innerWidth);
        console.log("height:" + event.target.innerHeight);

        this.pixelWidth = event.target.innerWidth;
      }

      getWidthRange(){
         if(this.pixelWidth < 251) return "small";
         if(this.pixelWidth < 451) return "medium";
         return "large"; 
      }
}
micronyks
  • 54,797
  • 15
  • 112
  • 146
  • I've never seen this `(window:resize)` event binding notation. Is this standard `Angular 2`? (any link to official docs would be helpful) – BeetleJuice Sep 17 '16 at 19:07
  • I had read it somewhere for one of beta versions(right now I don't remember reference). Later implemented in my project. I guess docs are not yet available. – micronyks Sep 17 '16 at 19:28
0
getWidth() {
    return Math.max(
      document.body.scrollWidth,
      document.documentElement.scrollWidth,
      document.body.offsetWidth,
      document.documentElement.offsetWidth,
      document.documentElement.clientWidth
    );
}
  • 5
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Nov 29 '20 at 17:23