Угловое представление 5 без обновления после таймаута

Я устанавливаю таймаут, чтобы скрыть элемент через некоторое время в Angular 5:

this.showElement = true;
setTimeout(function () {
  console.log('hide');
  this.showElement = false;
}, 2000);

Однако это не обновляет представление. console.log дает мне выход, поэтому тайм-аут определенно работает.

Я обнаружил, что в Angularjs вам нужно было называть $apply, чтобы начать дайджест, поэтому я предполагаю, что мне просто нужно найти эквивалентный способ Angular 5.

Ответ 1

Я думаю, что обратный вызов setTimeout теряет область видимости для переменной "showElement".

this.showElement = true; // this - is in component object context
setTimeout(function () {
   console.log('hide');
   this.showElement = false; // here... this has different context
}, 2000);

Вы должны использовать функцию стрелки:

this.showElement = true;
setTimeout(() => {
  console.log('hide');
  this.showElement = false;
}, 2000);

Или используйте bind:

this.showElement = true;
setTimeout(function() {
  console.log('hide');
  this.showElement = false;
}.bind(this), 2000);

для передачи правильного контекста функции обратного вызова setTimeout.

Ответ 2

Обновлено: Исправлен ответ.

Как правильно ответили другие, причина, по которой изменения не отражаются, связана с неправильной ссылкой на this ссылку.

Обратите внимание, что при использовании обозначения function() {... } ссылка на this - это контекст самой функции. Так

myFunction() {
    this.showElement = true;
    setTimeout(function() {
      console.log(this.showElement); // Will result in undefined;
      this.showElement = false; // Here, this, reference to context of the function wrapper
    }, 2000);
}

Изменив приведенное выше на обозначение стрелки ES6, измените контекст this ссылки на родительский контекст. Так

myFunction() {
    this.showElement = true;
    setTimeout(() => {
      console.log(this.showElement); // Will result in true;
      this.showElement = false; // Here, value is updated
    }, 2000);
}

Подробнее о lexical this читайте здесь.

Ответ 3

когда вы используете стиль функции, эта "ссылка" не работает, как это выглядит, и ваш пример будет работать правильно

this.showElement = true;
setTimeout(() => {
    console.log('hide');
    this.showElement = false;
}, 2000);

Ответ 4

Я столкнулся с той же проблемой в моем приложении Angular 7. Мне пришлось изменить источник заголовка и значок в кнопке:

<button class="btn btn--outline-red text-uppercase font-weight-normal product-action-btn mt-3"
              (click)="addToCart()">
              {{addToCartProps.title}}
              <img style="width:15px; height:15px;" [src]="addToCartProps.src">
            </button>

.......

  addToCartProps = { title: 'Add to Cart', src: '' }

  addToCart() {

    this.addToCartProps.title = 'Adding';
    this.addToCartProps.src = 'assets/images/preloader-white.svg';

    setTimeout(() => {
      this.addToCartProps.title = 'Added';
      this.addToCartProps.src = 'assets/images/checked-icon-white.svg';
      this.cd.markForCheck();
      console.log('timeout 1 ', this.addToCartProps);
    }, 1000);

    setTimeout(() => {
      this.addToCartProps.title = 'Add to cart';
      this.addToCartProps.src = '';
      this.cd.markForCheck();
      console.log('timeout 2 ', this.addToCartProps);
    }, 1500);

  }

Добавление this.cd.markForCheck() в функцию тайм-аута решило проблему в моем случае.

Ранее это также прокомментировал @artemisian в Angular2, представление не обновляется после изменений переменных в settimeout

Ответ 5

В своем конструкторе добавьте детектор изменений:

constructor(private cd: ChangeDetectorRef) {}

А затем в вашем setTimeout:

setTimeout(() => {
  console.log('hide');
  this.showElement = false;
  this.cd.detectChanges();
}, 2000);