Angular - ng-if - как вызвать обратный вызов после создания шаблона ng-if

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

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

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

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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 в функции ссылок и добавить к своей функции $emit, чтобы идентифицировать этот конкретный DIV, который будет отображаться.

Отвечает ли это на ваш вопрос?