Jak wykonać funkcję kontrolera AngularJS przy ładowaniu strony?


359

Obecnie mam stronę Angular.js, która umożliwia wyszukiwanie i wyświetlanie wyników. Użytkownik klika wynik wyszukiwania, a następnie klika przycisk Wstecz. Chcę, aby wyniki wyszukiwania były ponownie wyświetlane, ale nie mogę ustalić, jak uruchomić wyszukiwanie. Oto szczegół:

  • Moja strona Angular.js to strona wyszukiwania z polem wyszukiwania i przyciskiem wyszukiwania. Użytkownik może ręcznie wpisać zapytanie i nacisnąć przycisk. Zostanie uruchomione zapytanie ajax, a wyniki zostaną wyświetlone. Aktualizuję adres URL za pomocą wyszukiwanego hasła. To wszystko działa dobrze.
  • Użytkownik klika wynik wyszukiwania i zostaje przeniesiony na inną stronę - to też działa dobrze.
  • Użytkownik klika przycisk Wstecz i wraca do mojej kątowej strony wyszukiwania. Wyświetlany jest prawidłowy adres URL, w tym wyszukiwane hasło. Wszystko działa dobrze.
  • Powiązałem wartość pola wyszukiwania z wyszukiwanym terminem w adresie URL, więc zawiera on oczekiwany termin wyszukiwania. Wszystko działa dobrze.

Jak sprawić, by funkcja wyszukiwania uruchomiła się ponownie bez konieczności naciskania przez użytkownika przycisku wyszukiwania? Gdyby to była jquery, uruchomiłbym funkcję w funkcji tworzenia dokumentów. Nie widzę odpowiednika Angular.js.


używasz $routepProvider? Użyj go, aby połączyć się z usługą w aplikacji, która zapewnia dane dla wyników wyszukiwania. Nie myśl w document.readykategoriach jQuery. Trudno wiele pomóc, nie widząc sposobu, w jaki obecnie przeprowadziłeś wyszukiwanie
charlietfl

Odpowiedzi:


430

Z jednej strony, jak powiedział @ Mark-Rajcok, możesz po prostu uciec od prywatnej funkcji wewnętrznej:

// at the bottom of your controller
var init = function () {
   // check if there is query in url
   // and fire search in case its value is not empty
};
// and fire it after definition
init();

Możesz także zapoznać się z dyrektywą ng-init . Realizacja będzie podobna do:

// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>

// in controller
$scope.init = function () {
    // check if there is query in url
    // and fire search in case its value is not empty
};

Ale uważaj na to, ponieważ dokumentacja kątowa sugeruje (od wersji 1.2), aby NIE używać ng-initdo tego celu. Jednak imo zależy od architektury Twojej aplikacji.

Użyłem, ng-initgdy chciałem przekazać wartość z zaplecza do aplikacji kątowej:

<div data-ng-controller="myCtrl" data-ng-init="init('%some_backend_value%')"></div>

6
@Duke, czy nie możesz po prostu umieścić zawartości funkcji init () na dole kontrolera? To znaczy, dlaczego musisz używać ng-init i mieć funkcję init ()? Gdy użytkownik naciśnie przycisk Wstecz, zakładam, że zmieniasz widoki, dlatego myCtrltworzony jest nowy kontroler i uruchamiany.
Mark Rajcok

24
Chociaż to rozwiązanie działa, przegłosowałem, ponieważ dokumentacja ng-init odradza to. W szczególności: „Jedyne właściwe użycie ngInit do aliasingu specjalnych właściwości ngRepeat, jak pokazano w poniższej wersji demonstracyjnej. Poza tym przypadkiem, należy użyć kontrolerów zamiast ngInit, aby zainicjować wartości w zakresie”.
Jason Capriotti,

1
Kontroler jest tworzony po tym, jak html jest na swoim miejscu.
Dmitrij Evseev

3
Co się stanie, jeśli kontroler zostanie ponownie użyty na innych stronach, ale po prostu chcesz go uruchomić na określonej stronie?
Roberto Linares

3
@RobertoLinares Osobiście uważam, że dyrektywy są lepszym miejscem dla funkcjonalności wielokrotnego użytku. Można mieć dyrektywy z parametrem init: <div smth on-init="doWhatever()">. Oczywiście zależy to od konkretnego przypadku użycia.
Dmitrij Evseev

135

Spróbuj tego?

$scope.$on('$viewContentLoaded', function() {
    //call it here
});

5
Dzięki za odpowiedź, ale odpowiedź Dmitry'ego była dokładnie zgodna z tym, czego szukam. Dalsze badania wydawały się odradzać przeciwko $ viewContentLoaded
Duke Dougal

7
Przypadki użycia są po prostu inne. Cały czas używam metody Marka.
zasada holograficzna

W moim przypadku było to idealne rozwiązanie. Musieliśmy automatycznie wybrać tekst, aby zachęcić użytkownika do jego skopiowania. Strona może być ponownie ładowana / odwiedzana wiele razy, więc $ viewContentLoaded było dokładnym dopasowaniem. Dzięki!
Olga Gnatenko

Czy to możliwe, że jest to wykonywane kilka razy? Dostaję zachowanie, które wydaje się naśladować, że ...
MadPhysicist,

1
Ten nie działał dla mnie, ale $ scope. $ Watch działał. Jaka jest główna różnica?
Burak Tokak

59

Nigdy nie mógłbym dostać się $viewContentLoadeddo pracy i ng-initpowinienem być używany tylko w ng-repeat(zgodnie z dokumentacją), a także wywołanie funkcji bezpośrednio w kontrolerze może powodować błędy, jeśli kod opiera się na elemencie, który nie został jeszcze zdefiniowany .

Oto co robię i działa dla mnie:

$scope.$on('$routeChangeSuccess', function () {
  // do something
});

Chyba że używasz ui-router. To jest:

$scope.$on('$stateChangeSuccess', function () {
  // do something
});

1
Jesteś niesamowity, przyjacielu.
taco

Dokładnie to, czego potrzebowałem. Dosłownie szukałem tego przez dwa dni!
hellojebus

3
$scope.$on('$routeChangeSuccess'odpala za każdym razem, gdy zmieniają się parametry w adresie URL ( $locationna przykład przez), dzięki czemu można użyć just $scope.$on('$locationChangeSuccess'. Jeśli potrzebujesz jakiegoś wyzwalacza przy ładowaniu / ładowaniu strony, możesz użyć $scope.$watch('$viewContentLoaded'zgodnie z sugestią tutaj. Nie będzie uruchamiany podczas zmiany parametrów adresu URL.
Neurotransmitter

przy użyciu AngularJS 1.17.2, wewnątrz kontrolera $ routeChangeSuccess działał niesamowicie ... niech żyje adam0101 ...
ArifMustafa

43
angular.element(document).ready(function () {

    // your code here

});

4
Musi to być zaakceptowana odpowiedź, jest to bezpieczniejszy sposób
Marwen Trabelsi

Jest to dobre, jeśli nie pracujemy z, $scopea zamiast tego pracujemy z this.
Akash

Gdzie to musi iść? Mam go w swoim szablonie i nie można go uruchomić.
Dave

Czy nie byłoby najlepiej wstrzyknąć dokumentu $ w tym przypadku? angular.element ($ document) .ready ...
jamie

4
Wyjaśnienie byłoby mile widziane
Hidayt Rahman

32

Rozwiązanie Dimitri / Mark nie działało dla mnie, ale wydaje się, że użycie funkcji $ timeout działa dobrze, aby upewnić się, że kod działa tylko po renderowaniu znaczników.

# Your controller, including $timeout

var $scope.init = function(){
 //your code
}

$timeout($scope.init)

Mam nadzieję, że to pomoże.


3
Wreszcie. To jedyny, który dla mnie działał. Dzięki.
zmirc

1
To działa. Nie zapomnij również wyczyścić limitu czasu za pomocą $ timeout.cancel (timer), gdzie masz var timer = $ timeout ($ scope.init, milisekundy); po zakończeniu inicjalizacji. Ponadto nie sądzę, aby $ scope powinien mieć zmienną „var” w powyższym kodzie
Emmanuel NK

To powinna być zaakceptowana odpowiedź. To był jedyny, który pracował dla mnie (wypróbowałem wszystkie odpowiedzi powyżej). Działa nawet, jeśli czekasz na załadowanie ramki iframe.
hello_fr1end

To działa ! viewcontentLoaded nie działało dla mnie
mroczny rycerz

28

Możesz to zrobić, jeśli chcesz obejrzeć obiekt DOM viewContentLoaded w celu zmiany, a następnie zrobić coś. użycie $ scope. $ on działa również, ale inaczej, szczególnie gdy masz jeden tryb stronicowania na swoim routingu.

 $scope.$watch('$viewContentLoaded', function(){
    // do something
 });

7
W szczególności, jeśli użyjesz $ rootScope. $ Watch zamiast $ rootScope. $ On nie uruchomi się przy zmianie trasy, więc możesz użyć logiki specyficznej dla początkowego ładowania strony.
csahlman

19

Możesz użyć obiektu $ window angulara:

$window.onload = function(e) {
  //your magic here
}


3

Jeszcze jedna alternatywa, jeśli masz kontroler specyficzny dla tej strony:

(function(){
    //code to run
}());

3

Korzystając z $ routeProvider, możesz rozwiązać na .state i uruchomić swoją usługę. Oznacza to, że załadujesz kontroler i widok, dopiero po rozwiązaniu usługi:

trasy-ui

 .state('nn', {
        url: "/nn",
        templateUrl: "views/home/n.html",
        controller: 'nnCtrl',
        resolve: {
          initialised: function (ourBootstrapService, $q) {

            var deferred = $q.defer();

            ourBootstrapService.init().then(function(initialised) {
              deferred.resolve(initialised);
            });
            return deferred.promise;
          }
        }
      })

Usługa

function ourBootstrapService() {

 function init(){ 
    // this is what we need
 }
}

3

Odpowiedź Dmitrija Evseeva była dość przydatna.

Przypadek 1: Używanie samego angularJs:
Aby wykonać metodę przy ładowaniu strony, możesz użyć ng-initw widoku i zadeklarować metodę init w kontrolerze, powiedząc , że użycie cięższej funkcji nie jest zalecane, zgodnie z Angular Docs na ng-init :

Ta dyrektywa może być nadużywana, aby dodać niepotrzebne ilości logiki do twoich szablonów. Istnieje tylko kilka odpowiednich zastosowań ngInit, na przykład do aliasingu specjalnych właściwości ngRepeat, jak pokazano w pokazie poniżej; oraz do wstrzykiwania danych za pomocą skryptów po stronie serwera. Poza tymi kilkoma przypadkami powinieneś używać kontrolerów zamiast ngInit do inicjowania wartości w zakresie.

HTML:

<div ng-controller="searchController()">
    <!-- renaming view code here, including the search box and the buttons -->
</div>

Kontroler:

app.controller('SearchCtrl', function(){

    var doSearch = function(keyword){
        //Search code here
    }

    doSearch($routeParams.searchKeyword);
})

Ostrzeżenie: nie używaj tego kontrolera do innego widoku przeznaczonego dla innej intencji, ponieważ spowoduje to również wykonanie tam metody wyszukiwania.

Przypadek 2: Korzystanie z Ionic:
powyższy kod będzie działał, po prostu upewnij się, że pamięć podręczna widoku jest wyłączona w route.js:

route.js

.state('app', {
    url           : '/search',
    cache         : false, //disable caching of the view here
    templateUrl   : 'templates/search.html'   ,
    controller    : 'SearchCtrl'
  })

Mam nadzieję że to pomoże


1
To było tylko jedno w górę i było na samym dole, cieszę się, że zszedłem na dół, cache: falsezrobiłem to dla mnie - dzięki!
Rani Kheir,

3

Miałem ten sam problem i tylko to rozwiązanie działało dla mnie (uruchamia funkcję po załadowaniu pełnego DOM). Używam tego do przewijania w celu zakotwiczenia po załadowaniu strony:

angular.element(window.document.body).ready(function () {

                        // Your function that runs after all DOM is loaded

                    });

2

Możesz zapisać wyniki wyszukiwania we wspólnej usłudze, z której można korzystać z dowolnego miejsca i nie usuwa się po przejściu do innej strony, a następnie można ustawić wyniki wyszukiwania za pomocą zapisanych danych dla kliknięcia przycisku Wstecz

function search(searchTerm) {
    // retrieve the data here;
    RetrievedData = CallService();
    CommonFunctionalityService.saveSerachResults(RetrievedData);
} 

Dla twojego przycisku

function Backbutton() {
    RetrievedData = CommonFunctionalityService.retrieveResults();
}

0

wywoływać metody początkowe w ramach funkcji samodzielnej inicjalizacji.

(function initController() {

    // do your initialize here

})();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.