AngularJS実行コントローラーを2回実行する


532

AngularJSはいくつかのコードを2回、場合によってはさらに多く、たとえば$watchイベントのように実行し、モデルの状態を常にチェックすることを理解しています。

しかし私のコード:

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);
});

//...

2回実行され、2つのレコードがDBに挿入されます。私は何年もの間これに頭をぶつけてきたので、私はまだまだ学んでいます!


104
コントローラーが2回実行されている場合は、Angularアプリを2回初期化していないことを確認してください(ng-app手動ブートストラップを使用して自動で初期化することにより)。また、コントローラーを複数の要素に接続しているかどうかも確認してください(ng-controllerを使用)。
Stewie

7
「および手動ブートストラップ」の意味を説明できますか?
スポーツ


2
ロギングに関する問題をトラブルシューティングし、コンソールログが2回起動するのを確認したところ、継承したアプリでコントローラーの動作が重複していることに気付きました。最初のログファイアには値がありましたが、2番目のログファイアは未定義でした。コントローラーのHTML ng-controllerディレクティブを削除した後、未定義であった2番目のコンソールログの発生はなくなりました。
Daniel Nalbach、2015

2
angular.jsが2回追加されると、これも発生する可能性があります
Mohit

回答:


1050

アプリルーターは、ナビゲーションを次のMyControllerように指定しました。

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

しかし、私はこれも持っていましたhome.html

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

これにより、コントローラーが2回消化されました。data-ng-controllerHTMLから属性を削除することで問題は解決しました。または、controller:ルーティングディレクティブからプロパティを削除した可能性もあります。

この問題は、タブ付きナビゲーションを使用する場合にも発生します。たとえば、次のものapp.jsが含まれる場合があります。

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

対応するレポートタブのHTMLは次のようになります。

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

これにより、コントローラーが2回実行されます。


4
これは、どのように私に聞かないでください、私のコードをコーミングの多くの時間後にこれを残すのに最適な場所を、と思われるが、私は変更されたとき<div ng-view>...<div class="ng-view">...、この問題は私のために停止しました。私はこれまでにこの動作に遭遇したことはありませんが、多分誰かがこれも持っています。
Phix

5
ngControllerのドキュメント、docs.angularjs.org / api
Charles

1
ルートでコントローラーを宣言し、次にHTMLページ自体で別のコントローラーを宣言する方法はありますか?両方が機能し、競合がないことを確認するにはどうすればよいですか?それともこれは不要ですか?
思想家

1
それはおそらく不要です、代わりにいくつかのディレクティブを使用しますか?
グレッグ

2
@JoshをHTMLに残すと、柔軟性が低下します。テンプレートを1つのコントローラーに直接結び付けます。ルーティングでは構文としてctrlを使用できます。
グレッグ

127

AngularJS docs-ngController
$ routeサービスを介してルート定義で宣言することにより、DOMにコントローラーをアタッチすることもできます。よくある間違いは、テンプレート自体でng-controllerを使用してコントローラを再度宣言することです。これにより、コントローラーが接続され、2回実行されます。

ng-viewディレクティブでngRouteを使用すると、コントローラーはデフォルトでそのdom要素(またはui-routerを使用する場合はui-view)にアタッチされます。そのため、テンプレートに再度添付する必要はありません。


アンサーが重複しています。著者はすでに同じことを言って答えました。ページの最後までスクロールダウンしてください。
イアゴ2015

4
著者がそれをサイドノートとして置いているのは紛らわしいことに気づきましたが、それが明らかに正しい方法です。ドキュメントからの引用は質問に明確に答えます。そして、多くの人がドキュメントへのリンクを参考にすると思います。
shxfee 2015

これにより、コントローラーが2回実行されるという私の問題が解決しました。私が行ったのは、テンプレートからng-controllerを削除することだけで、今では1回だけ実行されています。
torbenrudgaard 2017年

70

私はこれを経験しましたが、問題は受け入れられた回答とは異なりました。この問題を解決するために実行した手順を含めるために、これを将来の自分のためにここに残します。

  1. 冗長なコントローラー宣言を削除する
  2. ルートの末尾のスラッシュを確認する
  3. 確認する ng-ifs
  4. 不要なラッピングng-view呼び出しがないか確認します(ng-view実際のをラップしていたを誤って残しましたng-view。その結果、コントローラーが3回呼び出されました)。
  5. Railsを使用している場合は、turbolinksgemをapplication.jsファイルから削除する必要があります。私はそれを発見するために丸一日を無駄にしました。ここで答えが見つかりまし
  6. ng-appとブートストラップでアプリを2回初期化します。AngularJS実行コントローラーを2回実行する
  7. 独自のコントローラーも定義され、ng-clickなどを介してテンプレートでこのコントローラーのコールバックを使用するディレクティブの「リンク」関数の要素全体で$ compileを使用する場合、ここで答えが見つかります

5. Railsを使用している場合は、turbolinksgemをapplication.jsファイルから削除する必要があります。それは私を夢中にさせ、それを発見するために一日中無駄になりました。本当の痛み。ここで
2015

6. ng-appとブートストラップでアプリを2回初期化します。stackoverflow.com/questions/15535336/...
thadeuszlay

1
感謝します。私にとって、機能したのはルートの最後にスラッシュを付けることでした
Pramod Sharma

100万人に感謝します。これに頭を悩ませていました。結局7番になりました!(常に最後のもの...)。
Rabbi Shuki Gur 2016

うわー、信じられないかもしれませんが、リストのすべて調べましたが、まだ問題は解決していません。
Jacob Stamm

14

コントローラーが2回初期化できる場合は、もう1つケースを追加したいだけです(これは、angular.js 1.3.1の実際のものです)。

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

この場合、ng-viewが初期化されるときに$ route.currentはすでに設定されています。これにより、二重の初期化が発生します。

これを修正するには、ng-ifをng-show / ng-hideに変更するだけで、すべてがうまく機能します。


それは私を助けました、私はng-ifの代わりにng-show / ng-hideを使用していました、私は2つのng-viewを持っていました、それは問題ではありませんがng-show / ng-hideがそうでない間はng-if無効化
Dimitriコプリワ

トンありがとう。このアプローチは私の問題を解決しました。ui-viewコントローラを2回呼び出したのと同じ2回呼び出していました。
curlyreggie、2015

7

参考のために追加したい:

ページ上でも実行されるディレクティブでコントローラーを参照することにより、コントローラーのコードが二重に実行されることもあります。

例えば

return {

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

HTMLにng-controller = "myController"もある場合


これの解決策は何ですか?
Sagar Bhosale

1
どちらか一方のみを使用してください。
gb2d


6

私は自分のアプリとそのすべての依存関係をこの問題について少し引き裂きました(詳細はこちら:AngularJSアプリが2回起動する(通常の解決策を試しました)

そして結局のところ、それはすべてBatarang Chromeプラグインの責任でした。

この回答の解決策:

コードを変更する前に、投稿ごとに無効にすることを強くお勧めします。


これは私の問題でした。プラグインは、Angularアプリのダブルインスタンスを実行するため、スコープ情報を提供できます(なぜ初期インスタンスを使用できないのかわからないため)。
rgdigital

助けてくれてうれしいです。これを理解するのにかなりの時間がかかりました。
ルイス

5

コントローラーが意図せずに複数回実行されていることがわかっている場合は、問題のコントローラーの名前をファイルで検索してみてください(例:search:MyController through all files)。おそらく他のhtml / jsファイルにコピー貼り付けされており、それらのパーシャル/コントローラーを開発または使用する際に変更するのを忘れていました。出典:私はこの間違いをしました


5

単純なアプリ(ルーティングなしで単純なng-controller参照)でも同じ問題が発生し、コントローラーのコンストラクターが2回実行されました。最後に、私の問題は、RazorビューでAngularJSアプリケーションを自動ブートストラップする次の宣言であることがわかりました

<html ng-app="mTest1">

私もangular.bootstrapを使用して手動でブートストラップしました、すなわち

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

そのうちの1つを削除すると、うまくいきました。


4

次のように単にclose youディレクティブを修正しないと、ディレクティブが2回実行される場合があります。

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

これにより、ディレクティブが2回実行されます。また、ディレクティブが2回実行される場合もよくあります。

index.html TWICEにディレクティブを含めないようにしてください。


また、UI-Routerを使用している場合、クラス内でui-viewのディレクティブ名を指定すると、二重に実行されるように見える。Eまたは<ui-view> </ ui-view>に変更すると、二重実行の問題が修正されます。
SteveGSD、2015

2

AngularJS 1.4 rcビルドでこの問題について頭を悩ませたところ、Angular 1.4とAngular 2の新しいルーターライブラリに由来しているため、上記の回答のどれも適用できないことに気付きました。せたところ、この記事の執筆時点でました。そのため、新しいAngularルートライブラリを使用している可能性のある方のために、ここに一言お願いします。

基本的に、htmlページにng-viewportアプリのパーツをロードするためのディレクティブが含まれている場合、で指定されたハイパーリンクをクリックng-linkすると、関連するコンポーネントのターゲットコントローラーが2回ロードされます。微妙な違いは、ブラウザーが既にターゲットコントローラーを読み込んでいる場合、同じハイパーリンクを再度クリックしても、コントローラーが1回しか呼び出されないことです。

まだ実行可能な回避策は見つかりませんでしたが、この動作はshaunxuによって提起された観察と一致していると思います。うまくいけば、この問題は、新しいルートライブラリの将来のビルドとAngularJS 1.4リリースで解決されるでしょう。


2

私の場合、同じコントローラーを使用する2つのビューを見つけました。

$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

私が遭遇している問題は接線的なものかもしれませんが、グーグルでこの質問が出されたので、これは適切かもしれません。この問題は、UIルーターを使用しているときに醜い頭をもたげますが、ブラウザーの更新ボタンでページを更新しようとしたときだけです。アプリは親の抽象状態でUIルーターを使用し、次に子は親の状態をオフにします。アプリrun()機能には$state.go('...child-state...')コマンドがあります。親州は、resolveおり、最初はおそらく子コントローラーが2回実行されていると思いました。

URLにハッシュが追加される前はすべて問題ありません。
www.someoldwebaddress.org

次に、URLがUIルーターによって変更されると、
www.someoldwebaddress.org#/childstate

...次に、ブラウザの更新ボタンページ更新すると、$stateChangeStart 2回起動され、毎回がを指しchildstateます。

resolve親状態に二回発射されたものです。

おそらくこれはクラッジです。とにかく、これは私にとって問題を解消するようです:$stateProviderが最初に呼び出されるコードの領域で、最初window.location.hashが空の文字列かどうかを確認します。そうであれば、すべて良好です。そうでない場合は、window.location.hashを空の文字列に設定します。次に、$stateどこかへ行ったのは2回ではなく1回だけのようです。

また、アプリのデフォルトrunとに依存したくない場合はstate.go(...)、ハッシュ値をキャプチャし、そのハッシュ値を使用して、ページを更新する直前の子の状態を特定し、条件をを設定するコードstate.go(...)


1

私の場合は、使用したURLパターンが原因でした

私のURLは/ ui / project /:parameter1 /:parameter2のようでした。

状態変化のすべてのケースで、paramerter2は必要ありませんでした。2番目のパラメーターが不要な場合、URLは/ ui / project /:parameter1 /のようになります。したがって、状態が変化するたびに、コントローラーを2回更新します。

解決策は、parameter2を空の文字列として設定し、状態を変更することでした。


1

別の理由で、この二重の初期化が発生しました。私のアプリケーションの一部のルート遷移では、ページ上部近くまで強制的にスクロールしたいと思っていました(たとえば、ページ分割された検索結果で...次をクリックするとページ2の上部に移動するはずです)。

$rootScope $on $viewContentLoaded(特定の条件に基づいて)whichを実行したリスナーにリスナーを追加してこれを行いました

$location.hash('top');

誤ってこれが原因でルートが再評価され、コントローラーが再初期化されました



1

私の場合、コントローラの名前を別の名前に変更すると問題が解決しました。

あったコントローラ名の競合「との角度-UI-ツリー」モジュール:私は「へ「CatalogerTreeController」から私のコントローラの名前を変更しTreeController」とし、このコントローラは、「ページに二度開始することを開始し、UIツリー」ディレクティブがあるために使用しますこのディレクティブは、「TreeController」という名前のコントローラーを使用します。


1

ControllerAs構文を使用する場合は、次のように$ routeproviderでコントローラーラベルを宣言するだけです。

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

または

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

$ routeproviderを宣言した後、ビューのようにコントローラーを指定しないでください。代わりに、ビューでラベルを使用します。


0

私は同じ問題を抱えていて、すべての答えを試した後、同じコントローラーにバインドされている私の見解にディレクティブがあることがわかりました。

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

ディレクティブを削除した後、コントローラーが2回呼び出されるのを停止しました。今私の質問は、この問題なしでコントローラースコープにバインドされたこのディレクティブをどのように使用できるのですか?


0

私はちょうど私を解決しました、それは実際にはかなりがっかりしました。そのイオンハイブリッドアプリ、私はuiルーターv0.2.13を使用しました。私の場合は、epubリーダー(epub.jsを使用)があり、自分の本のライブラリに移動して他の本を選択すると、「ドキュメントが見つかりません」とレポートし続けていました。ブラウザの本をリロードすると完全にレンダリングされていましたが、別の本を選択すると再び同じ問題が発生しました。

私の解決は非常に簡単でした。私はちょうどreload:trueから削除され$state.go("app.reader", { fileName: fn, reload: true });ましたLibraryController


0

私は同じ問題を持っているangular-route@1.6.7ので、その余分なスラッシュ正規表現ルートの最後には:

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

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

そしてそれは正しく動作します。


0

ここにも私のケースを追加するだけです:

angular-ui-routerを使用していた$state.go('new_state', {foo: "foo@bar"})

パラメータにencodeURIComponentを追加すると、問題はなくなりました。$state.go('new_state', {foo: encodeURIComponent("foo@bar")})

どうした?パラメータ値の文字「@」はURLでは使用できません。結果として、angular-ui-routerはコントローラーを2回作成しました。最初の作成時に元の「foo @ bar」を渡し、2番目の作成時にエンコードされたバージョン「foo%40bar」を渡しました。上記のようにパラメーターを明示的にエンコードすると、問題はなくなりました。


-1

私が自分のHTMLからメソッドを2回呼び出していたため、2回呼び出されていることがわかりました。

`<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>`

強調表示されたセクションにより、findX()が2回呼び出されていました。それが誰かを助けることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.