it-swarm.com.ru

angular - ng-if - как сделать обратный вызов после того, как шаблон ng-if был отображен

в Angular мне нужно вызывать функцию после загрузки элемента с определенным классом. Отображение элемента контролируется через ng-if = 'expr'. Значение $ scope.expr устанавливается после ответа на некоторый вызов ajax.

Теперь, если я попытаюсь поместить $ watch в expr или использовать $ evalAsync. это не работает. возможно, причина в том, что эти события запускаются до того, как на самом деле запускается часть шаблона.

Вот пример кода: http://jsbin.com/kuyas/1/edit Здесь мне нужно что-то вроде обратного вызова в ng-if, который выполняется после рендеринга шаблона.

16
Charanjeet Kaur

Проблема заключалась в том, что не было способа узнать, выполняется ли angular с циклом дайджеста, гарантируя, что все элементы были отрисованы.

Чтобы решить эту проблему, было два варианта

  1. Оберните вашу функцию обратного вызова в директиву. включите эту директиву в ng-if. и делайте это выражение истинным только тогда, когда вы хотите, чтобы ваш обратный вызов был выполнен.
  2. Вызовите функцию обратного вызова внутри, setTimeOut(function(){ ... }, 0);, так как браузеры по умолчанию сохраняют все события в очереди, поэтому, когда выполняется цикл дайджеста, ваша функция обратного вызова войдет в очередь и будет выполнена, как только цикл дайджеста закончится.
16
Charanjeet Kaur

Один из возможных ответов - создать директиву, которая делает все, что вы хотите. Если вы затем используете эту директиву только в разделе HTML, контролируемом ng-if, то директива будет бездействующей до тех пор, пока выражение ng-if не станет истинным.

Будет ли это делать то, что вы хотите?

26
John Munsch

Самое простое решение, на мой взгляд, заключается в следующем:

<div ng-if="sectionActivated">
    <div ng-init="callBack()"></div>
</div>

Ваш обратный вызов будет вызван только тогда, когда будет обработано то, на что влияет ng-if.

2
aBertrand

Директива может выглядеть примерно так:

import * as angular from 'angular';

class OnFinishRenderDirective implements angular.IDirective {

  public restrict = 'A';
  public replace = false;

  public link = (
    scope: any,
    // scope:        angular.IScope,
    element: angular.IAugmentedJQuery,
    attr: any,
    modelCtrl: any,
    link: angular.ITemplateLinkingFunction ) => {

    if ( scope.$last === true ) {
      this.$timeout(() => {
        scope.$emit( 'elementRendered' );
      } );
    }

  }

  constructor( private $timeout: angular.ITimeoutService ) { }

}

export function onFinishRenderFactory(): angular.IDirectiveFactory {

  var directive = ( $timeout: angular.ITimeoutService ) => new OnFinishRenderDirective( $timeout );
  directive.$inject = [ '$timeout' ];
  return directive;
}

Вы должны импортировать его и добавить в свой модуль

import { onFinishRenderFactory } from './onFinishRender/onFinishRender.directive';

angular.module( 'yourModule', [] )
.directive( 'onFinishRender', onFinishRenderFactory() )

Затем вы можете использовать директиву где-нибудь в вашей разметке, чтобы выдать событие, когда директива будет отрисована.

<div onFinishRender>I am rendered</div>

Вы могли бы даже добавить дополнительный атрибут в директиву DIV, который затем можно извлечь из объекта ATTR в функции link и добавить в вашу функцию $ emit, чтобы идентифицировать этот конкретный DIV, который будет отображаться.

Это отвечает на ваш вопрос? 

1
Mattijs