skip to Main Content

I’m attempting to use $scope.$apply(); in some function that doesn’t auto update the html (Exactly this but not with timeout).

But when I use it at the end of my function I get Cannot find name '$scope', so I assumed that the $scope would be the binding of my model (Because of this answer) but when I replace $scope for my binding I get Property '$apply' does not exist on type 'string' (my variable that is binded is a string).

So what can I do to update the html (main problem) or fix the $scope.$apply() solution?

Edit:
$scope and $apply() are from AngularJS, not Angular 2+. I’m getting the correct output messages in console, but the UI is not updating and I don’t understand the problem.

<div class="col-sm home_title">
    <div class="home_title_box" id="home_title_box"></div>
    <h2 class="home_item">{{current_title}}</h2>
</div>
import { Component } from '@angular/core';

@Component({
  selector: 'app-index',
  templateUrl: './index.component.html',
  styleUrls: ['./index.component.scss']
})
export class IndexComponent {

  constructor() { }

  titles_array:   string[] = ["Doctor", "Medic", "Player"];
  current_title:  string = "None";
  curr_title_i:   number = 0;

  update_title(el: any){
    const resize_ob = new ResizeObserver((entries) => {
      if(entries !== null){
        if(entries[0].contentRect.width === 0){
          for(this.curr_title_i; this.curr_title_i < this.titles_array.length;){
            this.current_title = this.titles_array[this.curr_title_i];

            console.log(this.curr_title_i); // correct output
            console.log(this.current_title); // correct output

            this.curr_title_i++;
            if(this.curr_title_i >= this.titles_array.length){
              this.curr_title_i = 0;
            }
            break;
          }
        }
      }
    });

    resize_ob.observe(el);
  }

  ngOnInit(){
    const elemTitleBox = document.querySelector("#home_title_box");
    if(elemTitleBox !== null){
      this.update_title(elemTitleBox);
    }
  }
}

3

Answers


  1. Chosen as BEST ANSWER

    https://dev.to/christiankohler/how-to-use-resizeobserver-with-angular-9l5

    If you are following this example you may have tried to bind the width directly to the class property. Unfortunately the template is not rerendered and keeps the initial value.

    The reason is that Angular has monkey-patched most of the events but not (yet) ResizeObserver. This means that this callback runs outside of the zone.

    We can easily fix that by manually running it in the zone.

    import { Component, NgZone } from '@angular/core';
    
    @Component({
      selector: 'app-index',
      templateUrl: './index.component.html',
      styleUrls: ['./index.component.scss']
    })
    export class IndexComponent {
    
      constructor(private zone: NgZone) { }
    
      titles_array:  string[] = ["Doctor", "Medic", "Player"];
      current_title: string = "Nothing";
      curr_title_i:  number = 0;
      second_after:  boolean = true;
      el:            any = undefined;
      resize_ob:     any = undefined;
    
      update_title(): void{
        if(this.el !== null){
          this.resize_ob = new ResizeObserver((entries) => {
            this.zone.run(() => {
              if(entries !== null){
                if(this.el.parentElement !== null){
                  const parentElemWidth = +getComputedStyle(this.el.parentElement).width.slice(0, -2);
                  const elemWidth = +getComputedStyle(this.el).width.slice(0, -2);
    
                  if(Math.round((elemWidth / parentElemWidth) * 100) >= 93){
                    if(this.second_after){
                      this.current_title = this.titles_array[this.curr_title_i];
                      this.curr_title_i++;
                      if(this.curr_title_i >= this.titles_array.length){
                        this.curr_title_i = 0;
                      }
                      this.second_after = false;
                      setTimeout(() => this.second_after = true, 1000);
                    }
                  }
                }
              }
            })
          });
    
          this.resize_ob.observe(this.el);
        }
      }
    
    
      ngOnInit(){
        this.el = document.querySelector("#home_title_box");
        this.update_title();
      }
    
      ngOnDestroy() {
        this.resize_ob.unobserve(this.el);
      }
    }
    

  2. Have you tried manually detecting changes?

    Add the following to your constructor:

    constructor(private cdRef: ChangeDetectorRef) { }

    And fire detect changes after your update_title method.

    if (elemTitleBox !== null) {
      this.update_title(elemTitleBox);
    }
    
    this.cdRef.detectChanges();
    
    Login or Signup to reply.
  3. A bit late for a train, but still. using ngZone is a bit advanced thing, and there is no necessity to use it here.

    First of all: do not use querySelector. well.. you actually can, but thats not an "angulary" way. use ViewChild.

    Second: ngOnInit is called before component dependent DOM is rendered. so youe example was not working because when you called updateTitle method in ngOnInit was undefined. So, I advise you to make a habit to use all the DOM or DOM-dependent manipulations only after ngAfterViewInit hook was fired.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search