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.

Książę Dougal
źródło
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>
Dmitrij Evseev
źródło
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
});
zasada holograficzna
źródło
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
});
adam0101
źródło
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

});
Carlos Trujillo
źródło
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.

guico
źródło
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
 });
CodeOverRide
źródło
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
}
McGraw
źródło
3

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

(function(){
    //code to run
}());
Chipe
źródło
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
 }
}
Leo Lanese
źródło
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

Kailas
źródło
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

                    });
Ginko Balboa
źródło
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();
}
Heshan
źródło
0

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

(function initController() {

    // do your initialize here

})();
Uditha Prasad
źródło