1

I am using Angular 5. What I am trying to do is a responsive side navigation bar. When the window width changes I need some events to apply (css, content etc). In my example I want to change the inner Html - text, when the window width is below of 1080 pixels.

I tried three ways. By javascript and ng-model but nothing.

Html:

<div id="nav-left">
    <mat-list>
     <mat-list-item><a id="elp1" [routerLink]="['/']" fragment="intro-text" ng-model="innerHtml"> Welcome </a></mat-list-item>
     <mat-list-item><a id="elp2" [routerLink]="['/']" fragment="introduction"> Introduction </a></mat-list-item>
     ...
    </mat-list>
</div> 

Component (first way):

@HostListener('window:resize', ['$event'])
    onResize(event?) {      
      this.screenWidth = window.innerWidth;
      let bgScreen = true;
      let smScreen = true;
      if(this.screenWidth < 1080 && smScreen){
        document.getElementById("elp1").innerHTML = "New";

        smScreen = false; 
        bgScreen = true;

      }else if(this.screenWidth >= 1080 && bgScreen){
        document.getElementById("elp1").innerHTML = " Welcome ";

        bgScreen = false;
        smScreen = true;        
      }else{
        console.log('problem');
      }
    }

In this case I get a console error:

Uncaught (in promise): TypeError: Cannot set property 'innerHTML' of null

Component (second way):

@HostListener('window:resize', ['$event'])
        onResize(event?) {      
          this.screenWidth = window.innerWidth;

          if(this.screenWidth < 1080){
            let element = <HTMLInputElement>document.getElementById("elp1");
            element.value = "New";

          }else if(this.screenWidth >= 1080){
            let element = <HTMLInputElement>document.getElementById("elp1");
            element.value = "Welcome";      
          }else{
            console.log('problem');
          }
        }

With the error:

Uncaught (in promise): TypeError: Cannot set property 'value' of null

Component (third way & ng-model):

@HostListener('window:resize', ['$event'])
            onResize(event?) {      
              this.screenWidth = window.innerWidth;

              if(this.screenWidth < 1080){
                let innerHtml :string = "New";

              }else if(this.screenWidth >= 1080){
                let innerHtml :string = "Welcome";      
              }else{
                console.log('problem');
              }
            }

With no errors but it doesn't work.

1) The first problem are the above errors. 2) and secondly as you see in the "first way" example I tried to add flags trigger effects and realized that didn't worked either. Variables "bgScreen" and "smScreen" are always true. I put those for a better coding flow.

I don't want to use jQuery. Only typescript or with angular (ng-model) way. Any suggestions?

Vasilis Greece
  • 861
  • 1
  • 18
  • 38

2 Answers2

1

I recommend using data binding to set the content of the link:

<div id="nav-left">
  <mat-list>
    <mat-list-item><a [routerLink]="['/']" fragment="intro-text"> {{introText}} </a></mat-list-item>
     ...
  </mat-list>
</div>

The public property introText can be modified when the window is resized:

introText = "Welcome";

@HostListener("window:resize", ["$event"])
onResize(event) {      
  this.introText = window.innerWidth < 1080 ? "New" : "Welcome";
}

or, as an alternative, you could define introText as a getter (not handling the resize event):

get introText(): string {
  return window.innerWidth < 1080 ? "New" : "Welcome";
}
ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
  • Which is the best option the first or the second for performance? – Vasilis Greece May 05 '18 at 10:25
  • 1
    For performance, I would prefer the first one. The call to `window.innerWidth` probably takes more time than simply accessing the `introText` variable. – ConnorsFan May 05 '18 at 12:11
  • By the way, I saw your [new question](https://stackoverflow.com/q/50189242/1009922): you don't need to set `[innerHTML]` if you use interpolation. Choose one or the other, not both. After checking again: use `[innerHTML]` because interpolation does not accept HTML markup (unless you sanitize it). – ConnorsFan May 05 '18 at 12:28
0

To get element instead of using document.getElementById("elp1") try ViewChild of angular if child element of component, or ElementRef for component itself. As here it looks child element of Component you could use ViewChild

You will get the access to element in angular component.

so now your HTML would be

<mat-list-item><a #elp1 [routerLink]="['/']" fragment="intro-text"> Welcome </a></mat-list-item>

and in @component

import { ViewChild} from '@angular/core';
.
.
@ViewChild('elp1') link;

//And assign values like below now.
this.link.nativeElement.innerHTML = "New";

Hope this helps.

ngChaitanya
  • 435
  • 2
  • 8