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?

2
  • You can use ElementRef and then ElementRef.nativeElement to access the dom element. Commented May 4, 2018 at 9:35
  • Give me an example. Write a solution. Commented May 4, 2018 at 9:47

2 Answers 2

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";
}
Sign up to request clarification or add additional context in comments.

3 Comments

Which is the best option the first or the second for performance?
For performance, I would prefer the first one. The call to window.innerWidth probably takes more time than simply accessing the introText variable.
By the way, I saw your new question: 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).
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.

5 Comments

Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined
Where did you define this @ViewChild('elp1') link; in component ? Any fiddle to have a look ?
Yes inside component. When I put outside under import it shows me other error: ReferenceError: link is not defined. Ok wait for a fiddle.
yes, it should be inside the component. After the Html change and this change, Link must hold the link cmp. Any fiddle please?
jsfiddle.net/weblaravel/b4ef53jb I guess that should work but is not all...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.