Variabel global dalam AngularJS

348

Saya punya masalah di mana saya menginisialisasi variabel pada lingkup di controller. Kemudian akan berubah di pengontrol lain ketika pengguna login. Variabel ini digunakan untuk mengontrol hal-hal seperti bilah navigasi dan membatasi akses ke bagian-bagian situs tergantung pada jenis pengguna, sehingga penting bahwa itu memegang nilainya. Masalahnya adalah bahwa pengontrol yang menginisialisasi itu, dipanggil lagi oleh angular beberapa cara dan kemudian me-reset variabel kembali ke nilai awalnya.

Saya berasumsi ini bukan cara yang benar untuk mendeklarasikan dan menginisialisasi variabel global, yah itu tidak benar-benar global, jadi pertanyaan saya adalah apa cara yang benar dan apakah ada contoh bagus di sekitar yang bekerja dengan versi angular saat ini?

Bola lampu1
sumber
12
Karena ini adalah hasil google # 1: Sekarang Anda dapat menggunakan app.constant () dan app.value () untuk membuat konstanta dan variabel di seluruh aplikasi. Lebih lanjut di sini: bit.ly/1P51PED
Mroz

Jawaban:

491

Pada dasarnya Anda punya 2 opsi untuk variabel "global":

$rootScopeadalah induk dari semua cakupan sehingga nilai yang diekspos di sana akan terlihat di semua templat dan pengontrol. Menggunakannya $rootScopesangat mudah karena Anda cukup menyuntikkannya ke pengontrol apa saja dan mengubah nilai dalam lingkup ini. Mungkin nyaman tetapi memiliki semua masalah variabel global .

Layanan adalah lajang yang dapat Anda injeksi ke pengontrol apa pun dan memaparkan nilainya dalam lingkup pengontrol. Layanan, menjadi lajang masih bersifat 'global' tetapi Anda memiliki kontrol yang jauh lebih baik atas tempat yang digunakan dan diekspos.

Menggunakan layanan sedikit lebih rumit, tetapi tidak terlalu banyak, berikut adalah contohnya:

var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
  return {
      name : 'anonymous'
  };
});

dan kemudian di controller:

function MyCtrl($scope, UserService) {
    $scope.name = UserService.name;
}

Inilah jsFiddle yang berfungsi: http://jsfiddle.net/pkozlowski_opensource/BRWPM/2/

pkozlowski.opensource
sumber
141
Dari FAQ Angular : Sebaliknya, jangan membuat layanan yang tujuan hidupnya hanya untuk menyimpan dan mengembalikan bit data.
Jakob Stoeck
7
Saya menggunakan benih Express + Angular oleh Btford . Jika saya mengatur variabel pada $ rootScope di Controller1 katakan dan pindah ke url lain (didukung oleh Controller2 katakan) saya dapat mengakses variabel ini. Namun jika saya me-refresh halaman pada Controller2 maka variabel tidak lagi dapat diakses di $ rootScope. Jika saya menyimpan data pengguna saat masuk, bagaimana saya bisa memastikan data ini dapat diakses di tempat lain bahkan di halaman refresh?
Craig Myles
19
@ JakobStoeck Gabungkan ini dengan jawaban ini dan Anda tinggal meletakkan data di rootScope. Saya pikir itu juga tidak benar. Apa cara sudut pandang untuk menyimpan dan mengembalikan bit data yang digunakan secara global?
user2483724
11
Saya ingin tahu apa kerugian dari layanan yang khusus untuk menyimpan nilai. Terisolasi, hanya disuntikkan di mana Anda membutuhkannya, dan mudah diuji. Apa downside?
Brian
12
oh Tuhan, mengapa semua orang takut akan variabel global, jika Anda tahu akan terdiri dari apa aplikasi Anda, buat saja variabel global js nyata alih-alih hal
Max Yari
93

Jika Anda hanya ingin menyimpan nilai, menurut dokumentasi Angular pada Penyedia , Anda harus menggunakan resep Nilai:

var myApp = angular.module('myApp', []);
myApp.value('clientId', 'a12345654321x');

Kemudian gunakan dalam pengontrol seperti ini:

myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
    this.clientId = clientId;
}]);

Hal yang sama dapat dicapai menggunakan Penyedia, Pabrik, atau Layanan karena mereka "hanya gula sintaksis di atas resep penyedia" tetapi menggunakan Nilai akan mencapai apa yang Anda inginkan dengan sintaks minimal.

Opsi lainnya adalah menggunakan $rootScope, tetapi ini bukan pilihan karena Anda tidak boleh menggunakannya karena alasan yang sama Anda tidak boleh menggunakan variabel global dalam bahasa lain. Ini disarankan untuk digunakan dengan hemat.

Karena semua lingkup diwarisi dari $rootScope, jika Anda memiliki variabel $rootScope.datadan seseorang lupa yang datasudah didefinisikan dan dibuat $scope.datadalam lingkup lokal Anda akan mengalami masalah.


Jika Anda ingin mengubah nilai ini dan mempertahankannya di semua pengontrol Anda, gunakan objek dan modifikasi properti dengan mengingat Javascript dilewatkan oleh "salinan referensi" :

myApp.value('clientId', { value: 'a12345654321x' });
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
    this.clientId = clientId;
    this.change = function(value) {
        clientId.value = 'something else';
    }
}];

Contoh JSFiddle

Dekan Atau
sumber
1
Ketika saya mengubah nilai pada satu tampilan, nilai baru tidak persisten. Bagaimana bisa? Bisakah Anda memperbarui jawaban Anda dan biarkan kami melihat bagaimana Anda clientIddapat diperbarui?
Blaise
@DeanOr Apakah mungkin untuk mempertahankan nilai yang diperbarui di antara penyegaran halaman? Nilai akan diinisialisasi ulang jika saya me-refresh halaman.
Nabarun
Anda harus menggunakan sesuatu yang lain untuk itu seperti cookie, penyimpanan lokal, atau database.
Dean Or
1
Saya sangat suka yang ini. Sekarang saya dapat memodifikasi dengan membangun proses untuk dev, stage, dan prod
jemiloii
1
Ada artikel sederhana yang menjelaskan penggunaan konstanta dan nilai-nilai yang mirip dengan variabel Global: ilikekillnerds.com/2014/11/…
RushabhG
36

Contoh AngularJS "variabel global" menggunakan $rootScope :

Pengendali 1 mengatur variabel global:

function MyCtrl1($scope, $rootScope) {
    $rootScope.name = 'anonymous'; 
}

Controller 2 membaca variabel global:

function MyCtrl2($scope, $rootScope) {
    $scope.name2 = $rootScope.name; 
}

Berikut adalah jsFiddle yang berfungsi: http://jsfiddle.net/natefriedman/3XT3F/1/

NateFriedman
sumber
2
Ini tidak berfungsi dalam pandangan arahan lingkup terisolasi. Lihat jsfiddle.net/3XT3F/7 . Tetapi Anda dapat menggunakan $ root untuk mengatasinya. Lihat jsfiddle.net/3XT3F/10 . Terima kasih kepada @natefaubion karena menunjukkannya
Tony Lâmpada
2
saat refresh, nilai $ rootScope akan kosong.
xyonme
Hardcoding $ rootScope.name sama dengan beberapa nilai .. sebenarnya kita perlu membacanya dan mengaturnya di sana.
25

Demi menambahkan ide lain ke kumpulan wiki, tapi bagaimana dengan AngularJS ' valuedanconstant modul? Saya baru saja mulai menggunakannya sendiri, tetapi bagi saya sepertinya ini adalah pilihan terbaik di sini.

Catatan: pada saat penulisan, Angular 1.3.7 adalah stable terbaru, saya percaya ini ditambahkan di 1.2.0, belum mengkonfirmasi ini dengan changelog sekalipun.

Bergantung pada berapa banyak yang perlu Anda tentukan, Anda mungkin ingin membuat file terpisah untuk mereka. Tapi saya biasanya mendefinisikan ini sebelum .config()blok aplikasi saya untuk akses mudah. Karena ini masih merupakan modul yang efektif, Anda harus mengandalkan injeksi ketergantungan untuk menggunakannya, tetapi itu dianggap "global" ke modul aplikasi Anda.

Sebagai contoh:

angular.module('myApp', [])
  .value('debug', true)
  .constant('ENVIRONMENT', 'development')
  .config({...})

Kemudian di dalam pengontrol apa pun:

angular.module('myApp')
  .controller('MainCtrl', function(debug, ENVIRONMENT), {
    // here you can access `debug` and `ENVIRONMENT` as straight variables
  })

Dari pertanyaan awal sebenarnya terdengar seperti sifat statis diperlukan di sini, baik sebagai bisa berubah (nilai) atau final (konstan). Ini lebih merupakan pendapat pribadi saya daripada yang lain, tetapi saya menemukan menempatkan item konfigurasi runtime pada $rootScopeterlalu berantakan, terlalu cepat.


sumber
Saya menemukan modul nilai sangat berguna dan ringkas. terutama ketika Anda mengikatnya ke variabel $ scope di dalam controller, sehingga perubahan dalam logika atau tampilan controller terikat ke variabel global / nilai / layanan
Ben Wheeler
20
// app.js or break it up into seperate files
// whatever structure is your flavor    
angular.module('myApp', [])    

.constant('CONFIG', {
    'APP_NAME' : 'My Awesome App',
    'APP_VERSION' : '0.0.0',
    'GOOGLE_ANALYTICS_ID' : '',
    'BASE_URL' : '',
    'SYSTEM_LANGUAGE' : ''
})

.controller('GlobalVarController', ['$scope', 'CONFIG', function($scope, CONFIG) {

    // If you wish to show the CONFIG vars in the console:
    console.log(CONFIG);

    // And your CONFIG vars in .constant will be passed to the HTML doc with this:
    $scope.config = CONFIG;
}]);

Di HTML Anda:

<span ng-controller="GlobalVarController">{{config.APP_NAME}} | v{{config.APP_VERSION}}</span>

sumber
8
localStorage.username = 'blah'

Jika Anda dijamin menggunakan peramban modern. Padahal tahu nilai-nilai Anda semua akan berubah menjadi string.

Juga memiliki manfaat praktis di-cache di antara reload.

Kevin
sumber
5
Heh, saya akan menyimpan semua variabel melalui localStorage. Kami bahkan akan memiliki semacam kegigihan kalau begitu! Juga, untuk mengatasi batasan string, mari kita simpan .toString () dari suatu fungsi kemudian evaluasi ketika diperlukan!
Shaz
seperti yang telah disebutkan oleh @Shaz, ini memiliki masalah kegigihan
Żubrówka
7

Harap perbaiki saya jika saya salah, tetapi ketika Angular 2.0 dirilis, saya tidak yakin $rootScopeakan ada. Dugaan saya didasarkan pada fakta yang $scopesedang dihapus juga. Jelas pengendali, akan tetap ada, hanya tidak dalam ng-controllermode. Pikirkan menyuntikkan pengendali ke arahan sebagai gantinya. Ketika rilis sudah dekat, akan lebih baik menggunakan layanan sebagai variabel global jika Anda ingin waktu yang lebih mudah untuk beralih dari verison 1.X ke 2.0.

jason328
sumber
Saya setuju, memasukkan data langsung ke $ rootScope bertentangan dengan seluruh tujuan Angular. Luangkan sedikit waktu dan atur kode Anda dengan benar dan itu akan membantu Anda, tidak hanya dalam upgrade AngularJS 2.x, tetapi secara umum sepanjang pengembangan aplikasi Anda karena semakin kompleks.
CatalinBerta
3
Jika $ rootScope dihapus, cukup tulis layanan baru yang disebut "$ rootScope" :)
uylmz
3

Anda juga dapat menggunakan variabel lingkungan $windowsehingga variabel global menyatakan di luar pengontrol dapat diperiksa di dalam a$watch

var initWatch = function($scope,$window){
    $scope.$watch(function(scope) { return $window.globalVar },
        function(newValue) {
            $scope.updateDisplayedVar(newValue);
    });
}

Karena, siklus digest lebih panjang dengan nilai-nilai global ini, sehingga tidak selalu diperbarui secara real-time. Saya perlu menyelidiki waktu intisari itu dengan konfigurasi ini.

Megaman
sumber
0

Saya hanya menemukan metode lain karena kesalahan:

Apa yang saya lakukan adalah mendeklarasikan var db = nulldeklarasi aplikasi di atas dan kemudian memodifikasinya app.jssaat saya mengaksesnya di controller.js Saya dapat mengaksesnya tanpa masalah. Mungkin ada beberapa masalah dengan metode ini yang tidak saya sadari tapi itu solusi yang bagus saya kira.

Mamba hitam
sumber
0

Coba ini, Anda tidak akan dipaksa untuk menyuntikkan $rootScopedi controller.

app.run(function($rootScope) {
    $rootScope.Currency = 'USD';
});

Anda hanya dapat menggunakannya dalam menjalankan blok karena blok konfigurasi tidak akan memberi Anda menggunakan layanan $ rootScope.

Rahul Murari
sumber
0

Ini sebenarnya cukup mudah. (Lagi pula, jika Anda menggunakan Angular 2+.)

Cukup tambahkan

declare var myGlobalVarName;

Di suatu tempat di bagian atas file komponen Anda (seperti setelah pernyataan "impor"), dan Anda akan dapat mengakses "myGlobalVarName" di mana saja di dalam komponen Anda.

Andy Corman
sumber
-2

Anda juga dapat melakukan sesuatu seperti ini ..

function MyCtrl1($scope) {
    $rootScope.$root.name = 'anonymous'; 
}

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}
pkdkk
sumber
3
$ rootScope tidak terdefinisi saat Anda menggunakannya dengan cara ini.
Ahmad Ahmadi