Enviando evento quando AngularJS terminar de carregar

114

Queria saber qual é a melhor maneira de detectar o término do carregamento / bootstrapping da página, quando todas as diretivas terminam de compilar / vincular.

Algum evento já está aí? Devo sobrecarregar a função de bootstrap?

Lior
fonte

Respostas:

204

Apenas um palpite: por que não ver como a diretiva ngCloak faz isso? Claramente, a diretiva ngCloak consegue mostrar o conteúdo depois que as coisas são carregadas. Aposto que olhar para o ngCloak levará à resposta exata ...

EDITAR 1 hora depois: Ok, bem, olhei para o ngCloak e ele é muito curto. O que isso obviamente implica é que a função de compilação não será executada até que as expressões {{template}} tenham sido avaliadas (isto é, o template que ele carregou), portanto, a boa funcionalidade da diretiva ngCloak.

Meu palpite seria apenas fazer uma diretiva com a mesma simplicidade do ngCloak e, em seguida, em sua função de compilação, fazer o que quiser. :) Coloque a diretiva no elemento raiz do seu aplicativo. Você pode chamar a diretiva de algo como myOnload e usá-la como um atributo my-onload. A função de compilação será executada assim que o modelo for compilado (expressões avaliadas e sub-modelos carregados).

EDITAR, 23 horas depois: Ok, então fiz algumas pesquisas e também fiz minha própria pergunta . A pergunta que fiz estava indiretamente relacionada a esta pergunta, mas coincidentemente me levou à resposta que resolve essa pergunta.

A resposta é que você pode criar uma diretiva simples e colocar seu código na função de link da diretiva, que (para a maioria dos casos de uso, explicados abaixo) será executada quando seu elemento estiver pronto / carregado. Com base na descrição de Josh da ordem em que as funções de compilação e link são executadas ,

se você tiver esta marcação:

<div directive1>
  <div directive2>
    <!-- ... -->
  </div>
</div>

Em seguida, o AngularJS criará as diretivas executando funções de diretiva em uma determinada ordem:

directive1: compile
  directive2: compile
directive1: controller
directive1: pre-link
  directive2: controller
  directive2: pre-link
  directive2: post-link
directive1: post-link

Por padrão, uma função de "link" direta é um post-link, então a função de link da sua diretiva externa1 não será executada até que a função de link da diretiva interna2 seja executada. É por isso que dizemos que só é seguro fazer manipulação de DOM no post-link. Portanto, em relação à pergunta original, não deve haver nenhum problema ao acessar o html interno da diretiva filho a partir da função de link da diretiva externa, embora o conteúdo inserido dinamicamente deva ser compilado, como dito acima.

Disto podemos concluir que podemos simplesmente fazer uma diretiva para executar nosso código quando tudo estiver pronto / compilado / vinculado / carregado:

    app.directive('ngElementReady', [function() {
        return {
            priority: -1000, // a low number so this directive loads after all other directives have loaded. 
            restrict: "A", // attribute only
            link: function($scope, $element, $attributes) {
                console.log(" -- Element ready!");
                // do what you want here.
            }
        };
    }]);

Agora o que você pode fazer é colocar a diretiva ngElementReady no elemento raiz do aplicativo e o console.logserá acionado quando for carregado:

<body data-ng-app="MyApp" data-ng-element-ready="">
   ...
   ...
</body>

É simples assim! Basta fazer uma diretiva simples e usá-la. ;)

Você pode personalizá-lo ainda mais para que possa executar uma expressão (ou seja, uma função) adicionando $scope.$eval($attributes.ngElementReady);a ele:

    app.directive('ngElementReady', [function() {
        return {
            priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
            restrict: "A",
            link: function($scope, $element, $attributes) {
                $scope.$eval($attributes.ngElementReady); // execute the expression in the attribute.
            }
        };
    }]);

Então você pode usá-lo em qualquer elemento:

<body data-ng-app="MyApp" data-ng-controller="BodyCtrl" data-ng-element-ready="bodyIsReady()">
    ...
    <div data-ng-element-ready="divIsReady()">...<div>
</body>

Apenas certifique-se de ter suas funções (por exemplo, bodyIsReady e divIsReady) definidas no escopo (no controlador) sob o qual seu elemento vive.

Advertências: Eu disse que isso funcionará na maioria dos casos. Tenha cuidado ao usar certas diretivas como ngRepeat e ngIf. Eles criam seu próprio escopo e sua diretiva não pode disparar. Por exemplo, se você colocar nossa nova diretiva ngElementReady em um elemento que também tem ngIf, e a condição do ngIf for avaliada como falsa, então nossa diretiva ngElementReady não será carregada. Ou, por exemplo, se você colocar nossa nova diretiva ngElementReady em um elemento que também tem uma diretiva ngInclude, nossa diretiva não será carregada se o modelo para o ngInclude não existir. Você pode contornar alguns desses problemas certificando-se de aninhar as diretivas em vez de colocá-las todas no mesmo elemento. Por exemplo, fazendo isso:

<div data-ng-element-ready="divIsReady()">
    <div data-ng-include="non-existent-template.html"></div>
<div>

em vez disso:

<div data-ng-element-ready="divIsReady()" data-ng-include="non-existent-template.html"></div>

A diretiva ngElementReady será compilada no último exemplo, mas sua função de link não será executada. Nota: as diretivas são sempre compiladas, mas suas funções de link nem sempre são executadas, dependendo de certos cenários como o acima.

EDITAR, alguns minutos depois:

Ah, e para responder totalmente à pergunta, você pode agora $emitou $broadcastseu evento a partir da expressão ou função que é executada no ng-element-readyatributo. :) Por exemplo:

<div data-ng-element-ready="$emit('someEvent')">
    ...
<div>

EDITAR, ainda mais alguns minutos depois:

A resposta de @satchmorun também funciona, mas apenas para o carregamento inicial. Aqui está uma pergunta SO muito útil que descreve a ordem em que as coisas são executadas, incluindo funções de link app.run, e outros. Portanto, dependendo do seu caso de uso, app.runpode ser bom, mas não para elementos específicos; nesse caso, as funções de link são melhores.

EDITAR, cinco meses depois, 17 de outubro às 8:11 PST:

Isso não funciona com parciais que são carregados de forma assíncrona. Você precisará adicionar contabilidade em seus parciais (por exemplo, uma maneira é fazer com que cada parcial mantenha o controle de quando seu conteúdo é carregado e, em seguida, emita um evento para que o escopo pai possa contar quantas parciais foram carregadas e finalmente fazer o que precisa fazer depois que todas as parciais forem carregadas).

EDITAR, 23 de outubro às 22h52 PST:

Fiz uma diretiva simples para disparar algum código quando uma imagem é carregada:

/*
 * This img directive makes it so that if you put a loaded="" attribute on any
 * img element in your app, the expression of that attribute will be evaluated
 * after the images has finished loading. Use this to, for example, remove
 * loading animations after images have finished loading.
 */
  app.directive('img', function() {
    return {
      restrict: 'E',
      link: function($scope, $element, $attributes) {
        $element.bind('load', function() {
          if ($attributes.loaded) {
            $scope.$eval($attributes.loaded);
          }
        });
      }
    };
  });

EDITAR, 24 de outubro às 12h48 PST:

Eu melhorei minha ngElementReadydiretiva original e a renomei para whenReady.

/*
 * The whenReady directive allows you to execute the content of a when-ready
 * attribute after the element is ready (i.e. done loading all sub directives and DOM
 * content except for things that load asynchronously like partials and images).
 *
 * Execute multiple expressions by delimiting them with a semi-colon. If there
 * is more than one expression, and the last expression evaluates to true, then
 * all expressions prior will be evaluated after all text nodes in the element
 * have been interpolated (i.e. {{placeholders}} replaced with actual values). 
 *
 * Caveats: if other directives exists on the same element as this directive
 * and destroy the element thus preventing other directives from loading, using
 * this directive won't work. The optimal way to use this is to put this
 * directive on an outer element.
 */
app.directive('whenReady', ['$interpolate', function($interpolate) {
  return {
    restrict: 'A',
    priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
    link: function($scope, $element, $attributes) {
      var expressions = $attributes.whenReady.split(';');
      var waitForInterpolation = false;

      function evalExpressions(expressions) {
        expressions.forEach(function(expression) {
          $scope.$eval(expression);
        });
      }

      if ($attributes.whenReady.trim().length == 0) { return; }

      if (expressions.length > 1) {
        if ($scope.$eval(expressions.pop())) {
          waitForInterpolation = true;
        }
      }

      if (waitForInterpolation) {
        requestAnimationFrame(function checkIfInterpolated() {
          if ($element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
            requestAnimationFrame(checkIfInterpolated);
          }
          else {
            evalExpressions(expressions);
          }
        });
      }
      else {
        evalExpressions(expressions);
      }
    }
  }
}]);

Por exemplo, use-o assim para disparar someFunctionquando um elemento for carregado e {{placeholders}}ainda não substituído:

<div when-ready="someFunction()">
  <span ng-repeat="item in items">{{item.property}}</span>
</div>

someFunctionserá chamado antes que todos os item.propertymarcadores sejam substituídos.

Avalie quantas expressões quiser e faça a última expressão truea aguardar para {{placeholders}}ser avaliada assim:

<div when-ready="someFunction(); anotherFunction(); true">
  <span ng-repeat="item in items">{{item.property}}</span>
</div>

someFunctione anotherFunctionserá demitido após {{placeholders}}ter sido substituído.

Isso só funciona na primeira vez que um elemento é carregado, não em alterações futuras. Pode não funcionar como desejado se um $digestcontinuar ocorrendo após os marcadores terem sido substituídos inicialmente (um $ digest pode acontecer até 10 vezes até que os dados parem de mudar). Será adequado para a grande maioria dos casos de uso.

EDIT, 31 de outubro às 19h26 PST:

Tudo bem, esta é provavelmente minha última e última atualização. Isso provavelmente funcionará para 99,999 dos casos de uso por aí:

/*
 * The whenReady directive allows you to execute the content of a when-ready
 * attribute after the element is ready (i.e. when it's done loading all sub directives and DOM
 * content). See: /programming/14968690/sending-event-when-angular-js-finished-loading
 *
 * Execute multiple expressions in the when-ready attribute by delimiting them
 * with a semi-colon. when-ready="doThis(); doThat()"
 *
 * Optional: If the value of a wait-for-interpolation attribute on the
 * element evaluates to true, then the expressions in when-ready will be
 * evaluated after all text nodes in the element have been interpolated (i.e.
 * {{placeholders}} have been replaced with actual values).
 *
 * Optional: Use a ready-check attribute to write an expression that
 * specifies what condition is true at any given moment in time when the
 * element is ready. The expression will be evaluated repeatedly until the
 * condition is finally true. The expression is executed with
 * requestAnimationFrame so that it fires at a moment when it is least likely
 * to block rendering of the page.
 *
 * If wait-for-interpolation and ready-check are both supplied, then the
 * when-ready expressions will fire after interpolation is done *and* after
 * the ready-check condition evaluates to true.
 *
 * Caveats: if other directives exists on the same element as this directive
 * and destroy the element thus preventing other directives from loading, using
 * this directive won't work. The optimal way to use this is to put this
 * directive on an outer element.
 */
app.directive('whenReady', ['$interpolate', function($interpolate) {
  return {
    restrict: 'A',
    priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
    link: function($scope, $element, $attributes) {
      var expressions = $attributes.whenReady.split(';');
      var waitForInterpolation = false;
      var hasReadyCheckExpression = false;

      function evalExpressions(expressions) {
        expressions.forEach(function(expression) {
          $scope.$eval(expression);
        });
      }

      if ($attributes.whenReady.trim().length === 0) { return; }

    if ($attributes.waitForInterpolation && $scope.$eval($attributes.waitForInterpolation)) {
        waitForInterpolation = true;
    }

      if ($attributes.readyCheck) {
        hasReadyCheckExpression = true;
      }

      if (waitForInterpolation || hasReadyCheckExpression) {
        requestAnimationFrame(function checkIfReady() {
          var isInterpolated = false;
          var isReadyCheckTrue = false;

          if (waitForInterpolation && $element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
            isInterpolated = false;
          }
          else {
            isInterpolated = true;
          }

          if (hasReadyCheckExpression && !$scope.$eval($attributes.readyCheck)) { // if the ready check expression returns false
            isReadyCheckTrue = false;
          }
          else {
            isReadyCheckTrue = true;
          }

          if (isInterpolated && isReadyCheckTrue) { evalExpressions(expressions); }
          else { requestAnimationFrame(checkIfReady); }

        });
      }
      else {
        evalExpressions(expressions);
      }
    }
  };
}]);

Use assim

<div when-ready="isReady()" ready-check="checkIfReady()" wait-for-interpolation="true">
   isReady will fire when this {{placeholder}} has been evaluated
   and when checkIfReady finally returns true. checkIfReady might
   contain code like `$('.some-element').length`.
</div>

Claro, provavelmente pode ser otimizado, mas vou deixar por isso mesmo. requestAnimationFrame é bom.

Trusktr
fonte
3
Muito chato com todos aqueles prefixos de "dados". Estou feliz por não os usar eu mesmo.
stolsvik
1
@stolsvik heh, sim, nos navegadores mais modernos eles não são necessários.
trusktr
49
Merece voto pela quantidade de tempo e esforço dedicados a esta resposta. Bom trabalho!
GordyD de
8
Boa resposta, mas considere remover todas as linhas "Editar" e reestruturar um pouco sua resposta. O histórico de edições está disponível através do link "editado ..." na parte inferior de sua resposta e distrai durante a leitura.
user247702
2
O código-fonte seria muito útil. E se você puder torná-lo público no npm, seria PERFEITO. Uma resposta muito boa, muito bem explicada, +1 pela quantidade de esforço despendido nisso.
tfrascaroli
38

Na documentação deangular.Module , há uma entrada que descreve a runfunção:

Use este método para registrar o trabalho que deve ser executado quando o injetor terminar de carregar todos os módulos.

Portanto, se você tiver algum módulo que seja seu aplicativo:

var app = angular.module('app', [/* module dependencies */]);

Você pode executar coisas depois que os módulos forem carregados com:

app.run(function() {
  // Do post-load initialization stuff here
});

EDIT: Inicialização manual para o resgate

Portanto, foi apontado que o runnão é chamado quando o DOM está pronto e vinculado. Ele é chamado quando $injectorfor o módulo referenciado por ng-appcarrega todas as suas dependências, que são separadas da etapa de compilação do DOM.

Dei outra olhada na inicialização manual e parece que isso deve funcionar.

Fiz um violino para ilustrar .

O HTML é simples:

<html>
    <body>
        <test-directive>This is a test</test-directive>
    </body>
</html>

Observe a falta de um ng-app. E eu tenho uma diretiva que fará alguma manipulação do DOM, para que possamos ter certeza da ordem e do tempo das coisas.

Como de costume, um módulo é criado:

var app = angular.module('app', []);

E aqui está a diretiva:

app.directive('testDirective', function() {
    return {
        restrict: 'E',
        template: '<div class="test-directive"><h1><div ng-transclude></div></h1></div>',
        replace: true,
        transclude: true,
        compile: function() {
            console.log("Compiling test-directive");
            return {
                pre: function() { console.log("Prelink"); },
                post: function() { console.log("Postlink"); }
            };
        }
    };
});

Vamos substituir a test-directivetag por um divof class test-directivee envolver seu conteúdo em um h1.

Eu adicionei uma função de compilação que retorna funções de pré e pós-link para que possamos ver quando essas coisas são executadas.

Aqui está o resto do código:

// The bootstrapping process

var body = document.getElementsByTagName('body')[0];

// Check that our directive hasn't been compiled

function howmany(classname) {
    return document.getElementsByClassName(classname).length;
}

Antes de fazermos qualquer coisa, não deve haver elementos com uma classe de test-directiveno DOM e, depois de terminarmos, deve haver 1.

console.log('before (should be 0):', howmany('test-directive'));

angular.element(document).ready(function() {
    // Bootstrap the body, which loades the specified modules
    // and compiled the DOM.
    angular.bootstrap(body, ['app']);

    // Our app is loaded and the DOM is compiled
    console.log('after (should be 1):', howmany('test-directive'));
});

É muito simples. Quando o documento estiver pronto, chame angular.bootstrapcom o elemento raiz do seu aplicativo e uma matriz de nomes de módulos.

Na verdade, se você anexar uma runfunção ao appmódulo , verá que ela é executada antes de qualquer compilação.

Se você executar o violino e assistir o console, verá o seguinte:

before (should be 0): 0 
Compiling test-directive 
Prelink
Postlink
after (should be 1): 1 <--- success!
satchmorun
fonte
2
obrigado @satchmorun! mas run () é executado antes do final da parte de vinculação - apenas verifiquei com alguns console.logs.
Lior
estava curioso ... Eu tenho uma diretiva que é acionada para implementar alguns plug-ins do jQuery DOM run, é
acionada
@charlietfl - Eu pesquisei um pouco sobre a inicialização manual e, na verdade, é uma maneira bem fácil de obter o que a pergunta está procurando. Eu adicionei uma edição bem longa à minha resposta original.
satchmorun de
5
descobri que usando $timeout( initMyPlugins,0)funciona dentro da minha diretiva, todo o html que preciso está lá
charlietfl
@satchmorun, veja este acompanhamento: stackoverflow.com/questions/14989161/…
Lior
16

O Angular não forneceu uma maneira de sinalizar quando uma página terminou de carregar, talvez porque "concluído" dependa de seu aplicativo . Por exemplo, se você tem uma árvore hierárquica de parciais, uma carregando as outras. "Concluir" significaria que todos eles foram carregados. Qualquer estrutura teria dificuldade em analisar seu código e entender que tudo está feito ou ainda esperado. Para isso, você teria que fornecer uma lógica específica do aplicativo para verificar e determinar isso.

Lior
fonte
14

Eu descobri uma solução que é relativamente precisa para avaliar quando a inicialização angular está completa.

A diretiva é:

.directive('initialisation',['$rootScope',function($rootScope) {
            return {
                restrict: 'A',
                link: function($scope) {
                    var to;
                    var listener = $scope.$watch(function() {
                        clearTimeout(to);
                        to = setTimeout(function () {
                            console.log('initialised');
                            listener();
                            $rootScope.$broadcast('initialised');
                        }, 50);
                    });
                }
            };
        }]);

Isso pode então ser apenas adicionado como um atributo ao bodyelemento e, em seguida, ouvido para usar$scope.$on('initialised', fn)

Ele funciona assumindo que o aplicativo é inicializado quando não há mais ciclos de $ digest. $ watch é chamado a cada ciclo de resumo e, portanto, um cronômetro é iniciado (setTimeout e não $ timeout, portanto, um novo ciclo de resumo não é acionado). Se um ciclo de resumo não ocorrer dentro do tempo limite, presume-se que o aplicativo foi inicializado.

Obviamente, não é tão preciso quanto a solução satchmoruns (já que é possível que um ciclo de resumo demore mais do que o tempo limite), mas minha solução não precisa que você acompanhe os módulos, o que a torna muito mais fácil de gerenciar (especialmente para projetos maiores ) De qualquer forma, parece ser preciso o suficiente para minhas necessidades. Espero que ajude.

Theo
fonte
Excelente solução. Para projetos em que todo o código em um ou dois arquivos compactados funciona muito bem.
merqlove
1
Esta é uma solução fantástica. Caso você tenha muito código no jquery e esteja tentando converter o código para angular passo a passo, isso faz todo o sentido.
Mangesh Pimpalkar
11

Se você estiver usando o Angular UI Router , poderá ouvir o $viewContentLoadedevento.

"$ viewContentLoaded - disparado assim que a visão é carregada, depois que o DOM é renderizado . O '$ escopo' da visão emite o evento." - Link

$scope.$on('$viewContentLoaded', 
function(event){ ... });
Jordan Skole
fonte
3
$ scope. $ watch ('$ viewContentLoaded', function () fez o truque para mim
Luís XIV
2
voto negativo para 'o que você deveria ser'. E se eu dissesse "se você estiver usando React em vez de Angular (o que deveria ser) ..."? Não é uma atitude muito a ter neste ecossistema IMHO.
Valentin Waeselynck
@ValentinWaeselynck você está absolutamente certo. Editei minha resposta para remover meu preconceito.
Jordan Skole
1
Funcionou para mim! Obrigado. Na verdade, eu o adicionei à minha função de execução e, em seguida, alterei $ scope para $ rootScope.
JDavies
2
Como a Angular University apontou em uma resposta diferente, $ viewContentLoaded pode não estar lá originalmente, mas agora funciona no provedor ngRoute integrado, exatamente da mesma maneira. Com isso em mente, acho que esta é a resposta rápida, simples e legível que muitos (a maioria?) Futuros leitores estarão procurando.
Kevin Crumley
3

observei a manipulação DOM do angular com JQuery e defini um acabamento para meu aplicativo (algum tipo de situação predefinida e satisfatória que preciso para meu aplicativo-resumo) por exemplo, espero que meu repetidor ng produza 7 resultados e aí para i irá definir uma função de observação com a ajuda de setInterval para este propósito.

$(document).ready(function(){

  var interval = setInterval(function(){

  if($("article").size() == 7){
     myFunction();
     clearInterval(interval);
  }

  },50);

});
Hassan Gilak
fonte
3
Eu não faria isso. Usar intervalos para verificar se algo está acontecendo não é uma boa prática, não é escalonável e existem outras maneiras de fazer as coisas acontecerem. Os cronômetros servem para realizar tarefas concretas que precisam acontecer após um determinado período de tempo, não para "adivinhar" quando o conteúdo ou os resultados estão prontos.
dudewad
Sem mencionar que usar um temporizador jquery contra a plataforma angular é contraproducente - angular tem uma classe de tempo limite e você deve usá-la, caso contrário, você está ocupando dois frameworks e se torna confuso muito rapidamente.
dudewad
3

Se você não usa o módulo ngRoute , ou seja, você não tem o evento $ viewContentLoaded .

Você pode usar outro método de diretiva:

    angular.module('someModule')
        .directive('someDirective', someDirective);

    someDirective.$inject = ['$rootScope', '$timeout']; //Inject services

    function someDirective($rootScope, $timeout){
        return {
            restrict: "A",
            priority: Number.MIN_SAFE_INTEGER, //Lowest priority
            link    : function(scope, element, attr){
                $timeout(
                    function(){
                        $rootScope.$emit("Some:event");
                    }
                );
            }
        };
    }

De acordo com a resposta de trusktr, ele tem a prioridade mais baixa. Além disso, $ timeout fará com que o Angular execute um loop de evento inteiro antes da execução do callback.

$ rootScope usado, porque permite colocar diretivas em qualquer escopo da aplicação e notificar apenas os ouvintes necessários.

$ rootScope. $ emit disparará um evento para todos os $ rootScope. $ apenas nos ouvintes. A parte interessante é que $ rootScope. $ Broadcast notificará todos os $ rootScope. $ E também $ scope. $ Nos ouvintes. Fonte

Vadim P.
fonte
2

De acordo com a equipe Angular e este problema no Github :

agora temos eventos $ viewContentLoaded e $ includeContentLoaded que são emitidos em ng-view e ng-include respectivamente. Acho que isso é o mais perto que se pode chegar de saber quando terminarmos a compilação.

Com base nisso, parece que atualmente não é possível fazer de uma forma confiável, caso contrário, o Angular teria fornecido o evento pronto para uso.

A inicialização do aplicativo implica a execução do ciclo de resumo no escopo raiz e também não há um evento de conclusão do ciclo de resumo.

De acordo com os documentos de design do Angular 2 :

Por causa de vários resumos, é impossível determinar e notificar o componente de que o modelo é estável. Isso ocorre porque a notificação pode alterar ainda mais os dados, o que pode reiniciar o processo de vinculação.

De acordo com isso, o fato de isso não ser possível é uma das razões pelas quais foi tomada a decisão de ir para uma reescrita em Angular 2.

Universidade Angular
fonte
2

Eu tinha um fragmento que estava sendo carregado após / pelo parcial principal que veio por meio de roteamento.

Eu precisava executar uma função após o carregamento dessa subparcialidade e não queria escrever uma nova diretiva e descobri que você poderia usar um ngIf

Controlador da parcial parental:

$scope.subIsLoaded = function() { /*do stuff*/; return true; };

HTML de subparcial

<element ng-if="subIsLoaded()"><!-- more html --></element>
Hashbrown
fonte
1

Se você deseja gerar JS com dados do lado do servidor (JSP, PHP), você pode adicionar sua lógica a um serviço, que será carregado automaticamente quando seu controlador for carregado.

Além disso, se você quiser reagir quando todas as diretivas tiverem terminado de compilar / vincular, você pode adicionar as soluções propostas apropriadas acima na lógica de inicialização.

module.factory('YourControllerInitService', function() {

    // add your initialization logic here

    // return empty service, because it will not be used
    return {};
});


module.controller('YourController', function (YourControllerInitService) {
});
Nikolay Georgiev
fonte
0

Todas essas são ótimas soluções. No entanto, se você estiver usando o roteamento, achei essa solução a mais fácil e com a menor quantidade de código necessária. Usar a propriedade 'resolve' para aguardar a conclusão de uma promessa antes de acionar a rota. por exemplo

$routeProvider
.when("/news", {
    templateUrl: "newsView.html",
    controller: "newsController",
    resolve: {
        message: function(messageService){
            return messageService.getMessage();
    }
}

})

Clique aqui para obter os documentos completos - Crédito para K. Scott Allen

Aholtry
fonte
0

pode ser que eu possa te ajudar com este exemplo

Na caixa de fantasia personalizada, mostro o conteúdo com valores interpolados.

no serviço, no método "open" fancybox, eu faço

open: function(html, $compile) {
        var el = angular.element(html);
     var compiledEl = $compile(el);
        $.fancybox.open(el); 
      }

o $ compile retorna dados compilados. você pode verificar os dados compilados

Shailendra Pathak
fonte