Memerangi pengontrol pelaksana AngularJS dua kali

532

Saya mengerti AngularJS menjalankan beberapa kode dua kali, kadang-kadang bahkan lebih, seperti $watchacara, terus-menerus memeriksa status model dll.

Namun kode saya:

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

//...

Dieksekusi dua kali, memasukkan 2 catatan ke dalam DB saya. Aku jelas masih belajar karena aku telah membenturkan kepalaku melawan ini sejak lama!

Greg
sumber
104
Jika pengontrol Anda berjalan dua kali, periksa apakah Anda tidak menginisialisasi aplikasi Angular Anda dua kali (dengan menginisialisasi secara otomatis dengan ng-appdan dengan bootstrap manual). Juga periksa apakah Anda telah memasang controller Anda ke beberapa elemen (dengan ng-controller).
Stewie
7
dapatkah Anda menjelaskan apa yang Anda maksud dengan "dan dengan bootstrap manual"?
Olahraga
2
Saya perhatikan perilaku pengontrol duplikat di aplikasi yang saya warisi ketika memecahkan masalah dengan logging dan melihat konsol log menyala dua kali. Log api pertama memiliki nilai, tetapi yang kedua tidak terdefinisi. Setelah menghapus direktif pengontrol-ng HTML untuk controller, log konsol kedua yang tidak terdefinisi hilang.
Daniel Nalbach
2
jika angular.js ditambahkan dua kali, maka ini juga bisa terjadi
Mohit

Jawaban:

1050

Router aplikasi menentukan navigasi agar MyControllerseperti ini:

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

Tapi saya juga punya ini di home.html:

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

Ini mencerna pengontrol dua kali. Menghapus data-ng-controlleratribut dari HTML menyelesaikan masalah. Atau, controller:properti mungkin telah dihapus dari arahan perutean.

Masalah ini juga muncul saat menggunakan navigasi tab. Misalnya, app.jsmungkin mengandung:

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

HTML laporan tab yang sesuai mungkin menyerupai:

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

Ini juga akan menghasilkan menjalankan pengontrol dua kali.

Greg
sumber
4
Ini sepertinya tempat terbaik untuk meninggalkan ini, setelah berjam-jam menyisir kode saya, jangan tanya saya bagaimana, tetapi ketika saya beralih <div ng-view>...ke <div class="ng-view">..., masalah ini berhenti untuk saya. Saya belum pernah menemukan perilaku ini sebelumnya, tetapi mungkin orang lain juga memiliki ini.
Phix
5
Ada penjelasan yang bagus tentang hal ini dalam dokumen untuk ngController, docs.angularjs.org/api/ng/directive/ngController
Charles
1
Apakah ada cara untuk mendeklarasikan controller di rute, dan kemudian controller lain di halaman html itu sendiri? Bagaimana memastikan keduanya berfungsi dan tidak ada konflik? Atau ini tidak perlu?
Thinkerer
1
Mungkin tidak perlu, mungkin menggunakan beberapa arahan?
Greg
2
@Josh meninggalkannya di HTML mengurangi fleksibilitas. Anda mengikat templat Anda langsung ke satu pengontrol. Anda dapat menggunakan ctrl sebagai sintaks dengan perutean.
Greg
127

AngularJS docs - ngController
Perhatikan bahwa Anda juga dapat melampirkan pengontrol ke DOM dengan mendeklarasikannya dalam definisi rute melalui layanan $ route. Kesalahan umum adalah mendeklarasikan controller lagi menggunakan ng-controller dalam template itu sendiri. Ini akan menyebabkan pengontrol terpasang dan dieksekusi dua kali.

Ketika Anda menggunakan ngRoute dengan ng-viewdirektif, controller akan terpasang ke elemen dom secara default (atau ui-view jika Anda menggunakan ui-router). Jadi Anda tidak perlu melampirkannya lagi di templat.

shxfee
sumber
Server duplikat. Penulis sudah menjawab mengatakan hal yang sama. Gulirkan ke bawah sampai akhir halaman.
Iago
4
Saya menemukan itu membingungkan bahwa penulis meletakkannya sebagai catatan sementara itu jelas cara yang tepat untuk melakukannya. Kutipan dari dokumen menjawab pertanyaan dengan jelas. Dan saya yakin banyak yang akan menemukan tautan ke dokumen bermanfaat.
shxfee
Ini memecahkan masalah saya dari pengontrol yang dieksekusi dua kali. Yang saya lakukan adalah menghapus ng-controller di template dan sekarang hanya mengeksekusi sekali.
torbenrudgaard
70

Saya baru saja membahas ini, tetapi masalahnya berbeda dari jawaban yang diterima. Saya benar-benar meninggalkan ini di sini untuk masa depan saya sendiri, untuk memasukkan langkah-langkah yang saya lalui untuk memperbaikinya.

  1. Hapus deklarasi pengontrol yang berlebihan
  2. Periksa garis miring pada rute
  3. Cek untuk ng-ifs
  4. Periksa apakah ada ng-viewpanggilan pembungkus yang tidak perlu (saya tidak sengaja meninggalkan panggilan ng-viewyang sebenarnya ng-view. Ini menghasilkan tiga panggilan ke pengontrol saya.)
  5. Jika Anda menggunakan Rails, Anda harus menghapus turbolinkspermata dari application.jsfile Anda . Saya menghabiskan sepanjang hari untuk menemukan itu. Ditemukan jawabannya di sini .
  6. Menginisialisasi aplikasi dua kali dengan ng-app dan dengan bootstrap. Memerangi pengontrol pelaksana AngularJS dua kali
  7. Ketika menggunakan $ compile pada seluruh elemen dalam fungsi 'link' dari direktif yang juga memiliki controller sendiri yang ditentukan dan menggunakan callback dari controller ini dalam template melalui ng-klik dll. Ditemukan jawaban di sini .
JesseBuesking
sumber
5. jika Anda menggunakan Rails, Anda harus menghapus turbolinksgem dari application.jsfile Anda . Itu membuatku gila, terbuang seharian untuk menemukan itu. Rasa sakit yang nyata. Ditemukan jawaban di sini
815
6. Menginisialisasi aplikasi dua kali dengan ng-app dan dengan bootstrap. stackoverflow.com/questions/15535336/…
thadeuszlay
1
Terima kasih. Bagi saya, hal yang berhasil adalah menebas di ujung rute
Pramod Sharma
Terima kasih satu juta, telah mematahkan kepalaku untuk ini. akhirnya menjadi nomor 7! (selalu yang terakhir ...).
Rabi Shuki Gur
Wow, percaya atau tidak, saya telah memeriksa semua yang ada di daftar Anda, dan saya masih memiliki masalah.
Jacob Stamm
14

Hanya ingin menambahkan satu case lagi ketika controller dapat init dua kali (ini sebenarnya untuk angular.js 1.3.1):

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

Dalam hal ini $ route.current akan ditetapkan ketika ng-view akan init. Itu menyebabkan inisialisasi ganda.

Untuk memperbaikinya ubah saja ng-jika ke ng-show / ng-hide dan semua akan bekerja dengan baik.

DontRelaX
sumber
Ini membantu saya, saya menggunakan ng-show / ng-hide alih-alih ng-if, saya punya dua ng-view, ini bukan masalah tapi ng-jika non-aktifkan sementara ng-show / ng-hide tidak
Dimitri Kopriwa
Terima kasih banyak. Pendekatan ini memecahkan masalah saya. Sedang menelepon sama ui-viewdua kali yang disebut controller dua kali.
curlyreggie
7

Ingin menambahkan referensi:

Eksekusi kode pengontrol ganda juga dapat disebabkan oleh referensi pengontrol dalam arahan yang juga berjalan di halaman.

misalnya

return {

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

Ketika Anda juga memiliki ng-controller = "myController" di HTML Anda

gb2d
sumber
apa solusi untuk ini?
Sagar Bhosale
1
Gunakan hanya satu atau yang lain.
gb2d
7

Saat menggunakan angular-ui-router dengan Angular 1.3+, ada masalah tentang tampilan Rendering dua kali pada transisi rute . Ini menghasilkan pengontrol dua kali juga. Tak satu pun dari solusi yang diusulkan bekerja untuk saya.

Namun, memperbarui angular-ui-routerdari 0,2,11 menjadi 0,2,13 memecahkan masalah bagi saya.

fracz
sumber
6

Saya merobek aplikasi saya dan semua ketergantungannya untuk mengatasi masalah ini (detailnya di sini: Aplikasi AngularJS memulai dua kali (mencoba solusi yang biasa ..) )

Dan pada akhirnya, itu semua adalah kesalahan plugin Chrome Batarang.

Resolusi dalam jawaban ini :

Saya sangat merekomendasikan hal pertama pada daftar siapa pun adalah untuk menonaktifkannya per posting sebelum mengubah kode.

Lewis
sumber
Ini masalah saya. Plugin ini menjalankan instance ganda aplikasi Angular Anda sehingga dapat memberikan informasi ruang lingkup (tidak tahu mengapa ia tidak bisa hanya menggunakan instance awal).
rgdigital
Aku senang itu membantu, butuh waktu loooong untuk memikirkan hal ini.
Lewis
5

Jika Anda tahu pengontrol Anda secara tidak sengaja mengeksekusi lebih dari satu kali, coba cari melalui file Anda untuk nama controller yang menyinggung, mis: cari: MyController melalui semua file. Kemungkinan itu disalin dari beberapa file html / js lainnya dan Anda lupa untuk mengubahnya ketika Anda mengembangkan atau menggunakan parsial / pengendali tersebut. Sumber: Saya membuat kesalahan ini

pengguna3901016
sumber
5

Saya memiliki masalah yang sama, dalam aplikasi sederhana (tanpa routing dan referensi ng-controller sederhana) dan konstruktor pengendali saya berjalan dua kali. Akhirnya, saya menemukan bahwa masalah saya adalah deklarasi berikut untuk auto-bootstrap aplikasi AngularJS saya di tampilan Razor saya

<html ng-app="mTest1">

Saya juga telah secara manual bootstrap menggunakan angular.bootstrap yaitu

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

jadi menghapus salah satu dari mereka, itu berhasil untuk saya.

athina.bikaki
sumber
4

Dalam beberapa kasus, arahan Anda berjalan dua kali ketika Anda tidak benar-benar menutup arahan Anda seperti ini:

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

Ini akan menjalankan arahan Anda dua kali. Juga ada kasus lain yang sering terjadi ketika arahan Anda berjalan dua kali:

pastikan Anda tidak memasukkan arahan Anda dalam index.html DUA KALI Anda !

pleerock
sumber
Juga jika Anda menggunakan UI-Router, menentukan nama direktif untuk ui-view di dalam kelas tampaknya menghasilkan eksekusi ganda. Mengubahnya menjadi E atau <ui-view> </ui-view> memperbaiki masalah eksekusi ganda.
SteveGSD
2

Telah menggaruk-garuk kepala saya atas masalah ini dengan AngularJS 1.4 rc build, kemudian menyadari bahwa tidak ada jawaban di atas yang berlaku karena berasal dari perpustakaan router baru untuk Angular 1.4 dan Angular 2 pada saat penulisan ini. Oleh karena itu, saya menjatuhkan catatan di sini untuk siapa saja yang mungkin menggunakan perpustakaan rute Angular baru.

Pada dasarnya jika halaman html berisi ng-viewportarahan untuk memuat bagian dari aplikasi Anda, dengan mengklik hyperlink yang ditentukan dengan ng-linkakan menyebabkan pengontrol target komponen terkait dimuat dua kali. Perbedaannya adalah, jika browser telah memuat pengontrol target, dengan mengklik kembali hyperlink yang sama hanya akan memanggil pengontrol satu kali.

Belum menemukan solusi yang layak, meskipun saya percaya perilaku ini konsisten dengan pengamatan yang diangkat oleh shaunxu , dan mudah-mudahan masalah ini akan diselesaikan di masa depan membangun perpustakaan rute baru dan bersama dengan rilis AngularJS 1.4.

codeful.element
sumber
2

Dalam kasus saya, saya menemukan dua tampilan menggunakan pengontrol yang sama.

$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'
    }
  }
});
Luke Eller
sumber
2

Masalah yang saya temui mungkin bersifat tangensial, tetapi karena googling membawa saya ke pertanyaan ini, ini mungkin tepat. Masalahnya adalah kepalanya yang jelek bagi saya ketika menggunakan Router UI, tetapi hanya ketika saya mencoba untuk me-refresh halaman dengan tombol refresh browser. Aplikasi ini menggunakan Router UI dengan keadaan abstrak induk, dan kemudian anak menyatakan dari induknya. Pada run()fungsi aplikasi , ada $state.go('...child-state...')perintah. Status induk menggunakan a resolve, dan pada awalnya saya pikir mungkin pengendali anak mengeksekusi dua kali.

Semuanya baik-baik saja sebelum URL memiliki hash yang ditambahkan.
www.someoldwebaddress.org

Kemudian setelah url telah dimodifikasi oleh UI Router,
www.someoldwebaddress.org#/childstate

... dan kemudian ketika saya me-refresh halaman dengan tombol refresh browser , $stateChangeStartapi dua kali, dan setiap kali menunjuk ke childstate.

Pada resolvestatus induk adalah apa yang menembak dua kali.

Mungkin ini adalah kludge; bagaimanapun, hal ini tampaknya menghilangkan masalah bagi saya: di area kode di mana $stateProviderpertama kali dipanggil, periksa terlebih dahulu untuk melihat apakah window.location.hash adalah string kosong. Jika ya, semuanya baik; jika tidak, maka atur window.location.hash ke string kosong. Maka tampaknya $statehanya mencoba untuk pergi ke suatu tempat sekali daripada dua kali.

Juga, jika Anda tidak ingin bergantung pada default aplikasi rundan state.go(...), Anda dapat mencoba untuk menangkap nilai hash dan menggunakan nilai hash untuk menentukan status anak tempat Anda berada sebelum penyegaran halaman, dan menambahkan kondisi ke area di Anda kode tempat Anda mengatur state.go(...).

mg1075
sumber
1

Dalam kasus saya itu karena pola url yang saya gunakan

url saya seperti / ui / project /: parameter1 /: parameter2.

Saya tidak perlu paramerter2 dalam semua kasus perubahan negara. Dalam kasus di mana saya tidak memerlukan parameter kedua url saya akan seperti / ui / project /: parameter1 /. Dan setiap kali saya mengalami perubahan status saya akan memiliki controller saya di-refresh dua kali.

Solusinya adalah dengan mengatur parameter2 sebagai string kosong dan melakukan perubahan status.

Sherin Syriac
sumber
1

Saya mendapatkan inisialisasi rangkap ini terjadi karena alasan yang berbeda. Untuk beberapa transisi rute dalam aplikasi saya, saya ingin memaksa pengguliran ke dekat bagian atas halaman (mis. Dalam hasil pencarian paginasi ... mengklik berikutnya akan membawa Anda ke atas halaman 2).

Saya melakukan ini dengan menambahkan pendengar $rootScope $on $viewContentLoadedyang (berdasarkan kondisi tertentu) dieksekusi

$location.hash('top');

Secara tidak sengaja ini menyebabkan rute saya dievaluasi ulang dan pengendali diinisialisasi ulang

Harry Lime
sumber
1

Dalam kasus saya mengganti nama controller ke nama yang berbeda menyelesaikan masalah.

Ada konflik nama pengontrol dengan modul " angular-ui-tree ": Saya mengganti nama pengontrol dari "CatalogerTreeController" menjadi " TreeController " dan kemudian pengontrol ini mulai dijalankan dua kali pada halaman di mana arahan " ui-tree " digunakan karena arahan ini menggunakan kontroler bernama " TreeController ".

AlexDEV.pro
sumber
1

Bagi mereka yang menggunakan sintaks ControllerAs, cukup deklarasikan label controller di $ routeprovider sebagai berikut:

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

atau

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

Setelah mendeklarasikan $ routeprovider, jangan berikan controller seperti pada tampilan. Alih-alih gunakan label pada tampilan.

M. Arnold
sumber
0

Saya memiliki masalah yang sama dan setelah mencoba semua jawaban saya akhirnya menemukan bahwa saya memiliki arahan dalam pandangan saya yang terikat pada pengontrol yang sama.

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

Setelah menghapus arahan, pengontrol berhenti dipanggil dua kali. Sekarang pertanyaan saya adalah, bagaimana bisa menggunakan direktif ini terikat pada ruang lingkup controller tanpa masalah ini

Daniel Vilas-Boas
sumber
0

Saya baru saja menyelesaikan masalah saya, yang sebenarnya cukup mengecewakan. Ini adalah aplikasi hybrid ionik, saya telah menggunakan ui-router v0.2.13. Dalam kasus saya ada pembaca epub (menggunakan epub.js) yang terus-menerus melaporkan "tidak ada dokumen yang ditemukan" begitu saya menavigasi ke perpustakaan buku saya dan memilih buku lainnya. Ketika saya memuat ulang buku browser sedang diterjemahkan dengan sempurna tetapi ketika saya memilih buku lain mendapat masalah yang sama lagi.

Penyelesaian saya sangat sederhana. Saya baru saja dihapus reload:truedari $state.go("app.reader", { fileName: fn, reload: true });dalamLibraryController

maksbd19
sumber
0

Saya memiliki masalah yang sama [email protected], dan itu karena garis miring ekstra di akhir rute regex:

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

untuk

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

dan itu bekerja dengan benar.

B.Ma
sumber
0

Cukup tambahkan kasus saya di sini juga:

Saya menggunakan angular-ui-router dengan$state.go('new_state', {foo: "foo@bar"})

Setelah saya menambahkan encodeURIComponent untuk parameter, masalah itu pergi: $state.go('new_state', {foo: encodeURIComponent("foo@bar")}).

Apa yang terjadi? Karakter "@" dalam nilai parameter tidak diizinkan di URL. Sebagai akibatnya, angular-ui-router membuat pengontrol saya dua kali: selama kreasi pertama ia melewati "foo @ bar" asli, selama kreasi kedua akan melewati versi yang disandikan "foo% 40bar". Setelah saya secara eksplisit menyandikan parameter seperti yang ditunjukkan di atas, masalahnya hilang.

Tom
sumber
-1

Saya tahu saya dipanggil dua kali karena saya memanggil metode dua kali dari html saya.

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

Bagian yang disorot menyebabkan findX () dipanggil dua kali. Semoga ini bisa membantu seseorang.

Nandu Prajapati
sumber