AngularJS wird zweimal ausgeführt


532

Ich verstehe, dass AngularJS einen Code zweimal durchläuft, manchmal sogar mehr, wie $watchEreignisse, ständige Überprüfung der Modellzustände usw.

Allerdings mein Code:

function MyController($scope, User, local) {

var $scope.User = local.get(); // Get locally save user data

User.get({ id: $scope.User._id.$oid }, function(user) {
  $scope.User = new User(user);
  local.save($scope.User);
});

//...

Wird zweimal ausgeführt und fügt 2 Datensätze in meine Datenbank ein. Ich lerne offensichtlich immer noch, da ich schon seit Ewigkeiten meinen Kopf dagegen stoße!


104
Wenn Ihr Controller zweimal ausgeführt wird, überprüfen Sie, ob Sie Ihre Angular-App nicht zweimal initialisieren (indem Sie sie automatisch mit ng-appund mit manuellem Bootstrap initialisieren lassen ). Überprüfen Sie auch, ob Sie Ihren Controller an mehrere Elemente angeschlossen haben (mit ng-controller).
Stewie

7
Kannst du erklären, was du mit "und mit manuellem Bootstrap" meinst?
Sport


2
Ich habe das doppelte Controller-Verhalten in einer App festgestellt, die ich geerbt habe, als ich ein Problem mit der Protokollierung behoben und die Konsolenprotokolle zweimal ausgelöst habe. Das erste Holzfeuer hatte einen Wert, das zweite war undefiniert. Nach dem Entfernen der HTML-Anweisung ng-controller für den Controller wurde das zweite undefinierte Konsolenprotokollfeuer gelöscht.
Daniel Nalbach

2
Wenn angular.js zweimal hinzugefügt wird, kann dies auch passieren
Mohit

Antworten:


1050

Der App-Router hat die Navigation MyControllerso angegeben:

$routeProvider.when('/',
                   { templateUrl: 'pages/home.html',
                     controller: MyController });

Aber ich hatte das auch in home.html:

<div data-ng-controller="MyController">

Dadurch wurde der Controller zweimal verdaut. Durch Entfernen des data-ng-controllerAttributs aus dem HTML-Code wurde das Problem behoben. Alternativ controller:könnte die Eigenschaft aus der Routing-Direktive entfernt worden sein.

Dieses Problem tritt auch bei Verwendung der Navigation mit Registerkarten auf. Zum Beispiel app.jskönnte enthalten:

  .state('tab.reports', {
    url: '/reports',
    views: {
      'tab-reports': {
        templateUrl: 'templates/tab-reports.html',
        controller: 'ReportsCtrl'
      }
    }
  })

Der HTML-Code auf der entsprechenden Registerkarte "Berichte" ähnelt möglicherweise:

<ion-view view-title="Reports">
  <ion-content ng-controller="ReportsCtrl">

Dies führt auch dazu, dass der Controller zweimal ausgeführt wird.


4
Dies scheint der beste Ort zu sein, um dies zu verlassen. Nach vielen Stunden des Kämmens meines Codes fragen Sie mich nicht, wie, aber als ich <div ng-view>...zu wechselte <div class="ng-view">..., hörte dieses Problem für mich auf. Ich bin noch nie auf dieses Verhalten gestoßen, aber vielleicht hat es auch jemand anderes.
Phix

5
Es gibt eine gute Erklärung dafür in den Dokumenten für ngController, docs.angularjs.org/api/ng/directive/ngController
Charles

1
Gibt es Möglichkeiten, einen Controller in der Route und dann einen anderen Controller auf der HTML-Seite selbst zu deklarieren? Wie kann sichergestellt werden, dass beide funktionieren und keine Konflikte auftreten? Oder ist das unnötig?
Denker

1
Es ist wahrscheinlich unnötig, vielleicht ein paar Anweisungen stattdessen zu verwenden?
Greg

2
@Josh, der es im HTML belässt, verringert die Flexibilität. Sie binden Ihre Vorlage direkt an einen Controller. Sie können Strg als Syntax für das Routing verwenden.
Greg

127

AngularJS docs - ngController
Beachten Sie, dass Sie Controller auch an das DOM anhängen können, indem Sie es in einer Routendefinition über den Dienst $ route deklarieren. Ein häufiger Fehler besteht darin, den Controller erneut mit ng-controller in der Vorlage selbst zu deklarieren. Dadurch wird der Controller zweimal angeschlossen und ausgeführt.

Wenn Sie ngRoute mit der ng-viewDirektive verwenden, wird der Controller standardmäßig an dieses dom-Element angehängt (oder ui-view, wenn Sie ui-router verwenden). Sie müssen es also nicht erneut in die Vorlage einfügen.


Doppelte Antwort. Der Autor antwortete bereits und sagte dasselbe. Scrollen Sie einfach bis zum Ende der Seite.
Iago

4
Ich fand es verwirrend, dass der Autor es als Randnotiz formulierte, während es offensichtlich der richtige Weg ist, es zu tun. Das Zitat aus den Dokumenten beantwortet die Frage klar. Und ich bin mir sicher, dass viele den Link zum Dokument hilfreich finden würden.
Shxfee

Dies löste mein Problem, dass der Controller zweimal ausgeführt wurde. Ich habe nur den ng-Controller in der Vorlage entfernt und jetzt nur noch einmal ausgeführt.
Torbenrudgaard

70

Ich habe das gerade durchgearbeitet, aber das Problem war anders als die akzeptierte Antwort. Ich lasse das wirklich hier für mein zukünftiges Ich, um die Schritte einzuschließen, die ich durchlaufen habe, um es zu reparieren.

  1. Entfernen Sie redundante Controller-Deklarationen
  2. Überprüfen Sie nachgestellte Schrägstriche in Routen
  3. Prüfen Auf ng-ifs
  4. Suchen Sie nach unnötigen Wrapping- ng-viewAnrufen (ich hatte versehentlich einen ng-viewAnruf hinterlassen , der meinen tatsächlichen Wrapping-Vorgang abwickelte ng-view. Dies führte zu drei Anrufen bei meinen Controllern.)
  5. Wenn Sie sich auf Rails befinden, sollten Sie den turbolinksEdelstein aus Ihrer application.jsDatei entfernen . Ich habe einen ganzen Tag damit verbracht, das zu entdecken. Antwort hier gefunden .
  6. Initialisierung der App zweimal mit ng-app und mit Bootstrap. AngularJS wird zweimal ausgeführt
  7. Bei Verwendung von $ compile für das gesamte Element in der 'Link'-Funktion der Direktive, für die auch ein eigener Controller definiert ist und Rückrufe dieses Controllers in der Vorlage per ng-click usw. verwendet werden . Hier finden Sie eine Antwort .

5. Wenn Sie sich auf Rails befinden, sollten Sie turbolinksgem aus Ihrer application.jsDatei entfernen . Das machte mich verrückt und verschwendete den ganzen Tag damit, das zu entdecken. Echter Schmerz. Antwort hier gefunden
18augst

6. Initialisieren Sie die App zweimal mit ng-app und mit bootstrap. stackoverflow.com/questions/15535336/…
thadeuszlay

1
Vielen Dank . Für mich war das, was funktionierte, einen Schrägstrich am Ende der Route zu setzen
Pramod Sharma

Vielen Dank, ich habe mir darüber den Kopf gebrochen. endete Nummer 7! (immer der letzte ...).
Rabbi Shuki Gur

Wow, ob Sie es glauben oder nicht, ich habe alles auf Ihrer Liste durchgesehen und habe immer noch das Problem.
Jacob Stamm

14

Ich möchte nur einen weiteren Fall hinzufügen, wenn der Controller zweimal initiieren kann (dies gilt für angle.js 1.3.1):

<div ng-if="loading">Loading...</div>
<div ng-if="!loading">
    <div ng-view></div>
</div>

In diesem Fall ist $ route.current bereits festgelegt, wenn ng-view gestartet wird. Dies führt zu einer doppelten Initialisierung.

Um das Problem zu beheben, ändern Sie einfach ng-if in ng-show / ng-hide und alles wird gut funktionieren.


Es hat mir geholfen, ich habe ng-show / ng-hide anstelle von ng-if verwendet, ich hatte zwei ng-view, es ist kein Problem, aber ng-if deaktivieren, während ng-show / ng-hide nicht
Dimitri Kopriwa

Danke vielmals. Dieser Ansatz löste mein Problem. Rief ui-viewzweimal dasselbe an, was den Controller zweimal anrief .
Curlyreggie

7

Möchte als Referenz hinzufügen:

Die Ausführung von Doppelcontroller-Code kann auch durch Verweisen auf den Controller in einer Direktive verursacht werden, die auch auf der Seite ausgeführt wird.

z.B

return {

            restrict: 'A',
            controller: 'myController',
            link: function ($scope) { ....

Wenn Sie auch ng-controller = "myController" in Ihrem HTML haben


Was ist die Lösung dafür?
Sagar Bhosale

1
Verwenden Sie nur den einen oder anderen.
gb2d

7

Bei Verwendung des Angular-UI -Routers mit Angular 1.3+ gab es ein Problem beim zweimaligen Rendern von Ansichten beim Routenübergang . Dies führte auch dazu, dass Controller zweimal ausgeführt wurden. Keine der vorgeschlagenen Lösungen hat bei mir funktioniert.

Das Aktualisieren angular-ui-routervon 0.2.11 auf 0.2.13 löste jedoch das Problem für mich.


6

Ich habe meine App und alle ihre Abhängigkeiten in Bezug auf dieses Problem in Stücke gerissen (Details hier: AngularJS-App wird zweimal gestartet (habe die üblichen Lösungen ausprobiert ..) )

Und am Ende war alles die Schuld des Batarang Chrome Plugins.

Lösung in dieser Antwort :

Ich würde dringend empfehlen, dass das erste, was auf einer Liste steht, darin besteht, es per Post zu deaktivieren, bevor der Code geändert wird.


Das war mein Problem. Das Plugin führt eine Doppelinstanz Ihrer Angular-App aus, damit es Bereichsinformationen bereitstellen kann (ich weiß nicht, warum es nicht einfach die ursprüngliche Instanz verwenden kann).
Rgdigital

Ich bin froh, dass es geholfen hat. Ich habe lange gebraucht, um das herauszufinden.
Lewis

5

Wenn Sie wissen, dass Ihr Controller mehrmals unbeabsichtigt ausgeführt wird, durchsuchen Sie Ihre Dateien nach dem Namen des fehlerhaften Controllers, z. B.: Search: MyController durchsucht alle Dateien. Wahrscheinlich wurde es in eine andere HTML / JS-Datei kopiert und Sie haben vergessen, es zu ändern, als Sie diese Partials / Controller entwickeln oder verwenden mussten. Quelle: Ich habe diesen Fehler gemacht


5

Ich hatte das gleiche Problem in einer einfachen App (ohne Routing und mit einer einfachen ng-Controller-Referenz) und der Konstruktor meines Controllers wurde zweimal ausgeführt. Schließlich stellte ich fest, dass mein Problem die folgende Deklaration zum automatischen Bootstrap meiner AngularJS-Anwendung in meiner Razor-Ansicht war

<html ng-app="mTest1">

Ich habe es auch manuell mit angle.bootstrap gebootet, dh

angular.bootstrap(document, [this.app.name]);

Als ich einen von ihnen entfernte, funktionierte es für mich.


4

In einigen Fällen wird Ihre Direktive zweimal ausgeführt, wenn Sie das Schließen Ihrer Direktive einfach nicht wie folgt korrigieren:

<my-directive>Some content<my-directive>

Dadurch wird Ihre Direktive zweimal ausgeführt. Es gibt auch einen anderen Fall, in dem Ihre Direktive häufig ausgeführt wird:

Stellen Sie sicher, dass Sie Ihre Richtlinie nicht in Ihre index.html ZWEIMAL aufnehmen !


Auch wenn Sie UI-Router verwenden, scheint die Angabe des Direktivennamens für die UI-Ansicht innerhalb einer Klasse zu einer doppelten Ausführung zu führen. Durch Ändern in E oder <ui-view> </ ui-view> wird das Problem der doppelten Ausführung behoben.
SteveGSD

2

Ich habe mir über dieses Problem mit AngularJS 1.4 rc den Kopf gekratzt und dann festgestellt, dass keine der oben genannten Antworten zutreffend war, da sie zum Zeitpunkt des Schreibens aus der neuen Router-Bibliothek für Angular 1.4 und Angular 2 stammte . Daher schreibe ich hier eine Notiz für alle, die möglicherweise die neue Angular-Routenbibliothek verwenden.

Wenn eine HTML-Seite eine ng-viewportAnweisung zum Laden von Teilen Ihrer App enthält, wird durch Klicken auf einen in angegebenen Hyperlink der Zielcontroller ng-linkder zugeordneten Komponente zweimal geladen. Der subtile Unterschied besteht darin, dass, wenn der Browser den Ziel-Controller bereits geladen hat, durch erneutes Klicken auf denselben Hyperlink der Controller nur einmal aufgerufen wird.

Ich habe noch keine praktikable Problemumgehung gefunden, obwohl ich glaube, dass dieses Verhalten mit der Beobachtung von Shaunxu übereinstimmt , und hoffentlich wird dieses Problem beim zukünftigen Aufbau einer neuen Routenbibliothek und zusammen mit AngularJS 1.4-Versionen behoben.


2

In meinem Fall habe ich zwei Ansichten mit demselben Controller gefunden.

$stateProvider.state('app', {
  url: '',
  views: {
    "viewOne@app": {
      controller: 'CtrlOne as CtrlOne',
      templateUrl: 'main/one.tpl.html'
    },
    "viewTwo@app": {
      controller: 'CtrlOne as CtrlOne',
      templateUrl: 'main/two.tpl.html'
    }
  }
});

2

Das Problem, auf das ich stoße, mag tangential sein, aber da mich das Googeln zu dieser Frage gebracht hat, könnte dies angemessen sein. Das Problem ist für mich bei der Verwendung des UI-Routers hässlich, aber nur, wenn ich versuche, die Seite mit der Schaltfläche zum Aktualisieren des Browsers zu aktualisieren. Die App verwendet den UI-Router mit einem übergeordneten abstrakten Status und den untergeordneten Status des übergeordneten Status. In der App- run()Funktion gibt es einen $state.go('...child-state...')Befehl. Der übergeordnete Status verwendet a resolve, und zuerst dachte ich, dass ein untergeordneter Controller möglicherweise zweimal ausgeführt wird.

Alles ist in Ordnung, bevor an die URL der Hash angehängt wurde.
www.someoldwebaddress.org

Sobald die URL vom UI-Router geändert wurde,
www.someoldwebaddress.org#/childstate

... und wenn ich dann die Seite mit der Schaltfläche zum Aktualisieren des Browsers aktualisiere , wird die Seite $stateChangeStartzweimal ausgelöst und zeigt jedes Mal auf die childstate.

Der resolveStatus "Übergeordnet" wird zweimal ausgelöst.

Vielleicht ist das ein Kludge; Unabhängig davon scheint dies das Problem für mich zu beseitigen: Überprüfen Sie im Bereich des Codes, in dem $stateProviderzuerst aufgerufen wird, zunächst , ob die Datei window.location.hash eine leere Zeichenfolge ist. Wenn ja, ist alles gut; Ist dies nicht der Fall , setzen Sie die Datei window.location.hash auf eine leere Zeichenfolge. Dann scheint es der $stateeinzige Versuch zu sein, einmal statt zweimal irgendwohin zu gehen.

Wenn Sie sich nicht auf die Standardeinstellungen der App verlassen möchten runund können state.go(...), können Sie versuchen, den Hash-Wert zu erfassen und anhand des Hash-Werts den untergeordneten Status zu bestimmen, in dem Sie sich kurz vor der Seitenaktualisierung befanden, und dem Bereich in Ihrer App eine Bedingung hinzufügen Code, in dem Sie die state.go(...).


1

In meinem Fall lag es an dem von mir verwendeten URL-Muster

Meine URL war wie / ui / project /: parameter1 /: parameter2.

Ich brauchte paramerter2 nicht in allen Fällen von Zustandsänderungen. In Fällen, in denen ich den zweiten Parameter nicht benötigte, würde meine URL / ui / project /: parameter1 / lauten. Wenn ich also einen Statuswechsel hatte, wird mein Controller zweimal aktualisiert.

Die Lösung bestand darin, Parameter2 als leere Zeichenfolge festzulegen und den Status zu ändern.


1

Ich habe diese doppelte Initialisierung aus einem anderen Grund durchführen lassen. Für einige Routenübergänge in meiner Anwendung wollte ich das Scrollen bis zum oberen Rand der Seite erzwingen (z. B. in paginierten Suchergebnissen ... Wenn Sie auf Weiter klicken, gelangen Sie zum Anfang von Seite 2).

Ich habe dazu einen Listener hinzugefügt, der $rootScope $on $viewContentLoaded(basierend auf bestimmten Bedingungen) ausgeführt wurde

$location.hash('top');

Dies führte versehentlich dazu, dass meine Routen neu bewertet und die Controller neu initialisiert wurden



1

In meinem Fall hat das Umbenennen des Controllers in einen anderen Namen das Problem gelöst.

Es gab einen Konflikt von Controllernamen mit dem Modul " Angular-UI -Tree ": Ich habe meinen Controller von "CatalogerTreeController" in " TreeController " umbenannt, und dann wird dieser Controller auf der Seite, auf der die Direktive " UI -Tree " verwendet wird, zweimal initiiert Diese Anweisung verwendet einen Controller mit dem Namen " TreeController ".


1

Wenn Sie die ControllerAs-Syntax verwenden, deklarieren Sie einfach die Controller-Bezeichnung im $ routeprovider wie folgt:

$routeprovider
        .when('/link', {
            templateUrl: 'templateUrl',
            controller: 'UploadsController as ctrl'
        })

oder

$routeprovider
        .when('/link', {
            templateUrl: 'templateUrl',
            controller: 'UploadsController'
            controllerAs: 'ctrl'
        })

Geben Sie den Controller nach dem Deklarieren des $ routeproviders nicht wie in der Ansicht angegeben an. Verwenden Sie stattdessen die Beschriftung in der Ansicht.


0

Ich hatte das gleiche Problem und nachdem ich alle Antworten ausprobiert hatte, stellte ich schließlich fest, dass ich aus meiner Sicht eine Direktive hatte, die an denselben Controller gebunden war.

APP.directive('MyDirective', function() {
  return {
    restrict: 'AE',
    scope: {},
    templateUrl: '../views/quiz.html',
    controller: 'ShowClassController'
}
});

Nach dem Entfernen der Direktive wurde der Controller nicht mehr zweimal aufgerufen. Meine Frage ist nun, wie kann diese an den Controller-Bereich gebundene Direktive ohne dieses Problem verwendet werden?


0

Ich habe gerade meine gelöst, was eigentlich ziemlich enttäuschend war. Es ist eine ionische Hybrid-App, ich habe UI-Router v0.2.13 verwendet. In meinem Fall gibt es einen Epub-Reader (mit epub.js), der kontinuierlich "Kein Dokument gefunden" meldet, sobald ich zu meiner Buchbibliothek navigiere und ein anderes Buch auswähle. Beim erneuten Laden wurde das Browserbuch perfekt gerendert, aber als ich ein anderes Buch auswählte, trat das gleiche Problem erneut auf.

Meine Lösung war sehr einfach. Ich entfernte gerade reload:trueaus $state.go("app.reader", { fileName: fn, reload: true });in meinemLibraryController


0

Ich habe das gleiche Problem in angular-route@1.6.7, und es, weil der zusätzliche Schrägstrich am Ende der Regex-Route:

.when('/goods/publish/:classId/', option)

zu

.when('/goods/publish/:classId', option)

und es funktioniert richtig.


0

Füge hier auch meinen Fall hinzu:

Ich habe Angular-UI-Router mit verwendet$state.go('new_state', {foo: "foo@bar"})

Nachdem ich dem Parameter encodeURIComponent hinzugefügt hatte , war das Problem behoben : $state.go('new_state', {foo: encodeURIComponent("foo@bar")}).

Was ist passiert? Das Zeichen "@" im Parameterwert ist in URLs nicht zulässig. Infolgedessen hat der Angular-UI-Router meinen Controller zweimal erstellt: Bei der ersten Erstellung wurde die ursprüngliche "foo @ bar" übergeben, bei der zweiten Erstellung wurde die codierte Version "foo% 40bar" übergeben. Nachdem ich den Parameter wie oben gezeigt explizit codiert hatte, verschwand das Problem.


-1

Ich habe herausgefunden, dass meine Methode zweimal aufgerufen wird, weil ich die Methode zweimal von meinem HTML-Code aus aufgerufen habe.

`<form class="form-horizontal" name="x" ng-submit="findX() novalidate >
 <input type="text"....>
 <input type="text"....>
 <input type="text"....>
 <button type="submit" class="btn btn-sm btn-primary" ng-click="findX()"
</form>`

Der hervorgehobene Abschnitt führte dazu, dass findX () zweimal aufgerufen wurde. Hoffe es hilft jemandem.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.