AngularJS'de global değişkenler


348

Bir denetleyicideki kapsamda bir değişkeni başlatan bir sorunum var. Daha sonra bir kullanıcı oturum açtığında başka bir denetleyicide değiştirilir. Bu değişken, gezinme çubuğu gibi şeyleri kontrol etmek için kullanılır ve kullanıcının türüne bağlı olarak sitenin bölümlerine erişimi kısıtlar, bu nedenle değerini tutması önemlidir. Bununla ilgili sorun, onu başlatan denetleyicinin açısal bir şekilde tekrar çağrılması ve daha sonra değişkeni ilk değerine sıfırlamasıdır.

Bunun küresel değişkenleri ilan etmenin ve başlatmanın doğru yolu olmadığını, aslında küresel olmadığını varsayıyorum, bu yüzden sorum doğru yol nedir ve bu açısalın mevcut sürümü ile ilgili iyi örnekler var mı?


12
Bu # 1 sonuç olduğundan: Artık uygulama genelinde sabitler ve değişkenler oluşturmak için app.constant () ve app.value () yöntemlerini kullanabilirsiniz. Daha fazlası için: bit.ly/1P51PED
Mroz

Yanıtlar:


491

Temel olarak "global" değişkenler için 2 seçeneğiniz vardır:

$rootScopetüm kapsamların bir üst öğesidir, bu nedenle burada ortaya çıkan değerler tüm şablonlarda ve denetleyicilerde görünür olur. $rootScopeBunu kullanmak çok kolaydır, çünkü herhangi bir denetleyiciye enjekte edebilir ve bu kapsamdaki değerleri değiştirebilirsiniz. Uygun olabilir, ancak küresel değişkenlerin tüm problemlerine sahiptir .

Hizmetler, herhangi bir denetleyiciye enjekte edebileceğiniz ve denetleyicinin kapsamındaki değerlerini gösterebileceğiniz tek öğelerdir. Hizmetler, singleton olmak hala 'küresel' olmakla birlikte, bunların kullanıldığı ve maruz kaldığı yerler üzerinde çok daha iyi bir kontrole sahipsiniz.

Hizmetleri kullanmak biraz daha karmaşık, ama o kadar değil, işte bir örnek:

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

ve sonra bir denetleyicide:

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

İşte çalışan jsFiddle: http://jsfiddle.net/pkozlowski_opensource/BRWPM/2/


141
Gönderen Açısal SSS : Tersine, tek amacı hayatta bilgi depolamayı ve dönüş bite bir hizmet oluşturmayın.
Jakob Stoeck

7
Ben kullanıyorum Btford Express by + Açısal tohum . Controller1'de $ rootScope üzerinde bir değişken ayarlayıp başka bir url'ye (Controller2 tarafından desteklenmektedir) geçersem bu değişkene erişebilirim. Ancak, Controller2'de sayfayı yenilersem değişkene artık $ rootScope üzerinden erişilemez. Oturum açarken kullanıcı verilerini kaydediyorsam, bu verilerin sayfa yenilemede bile başka bir yerden erişilebilir olmasını nasıl sağlayabilirim?
Craig Myles

19
@ JakobStoeck Bunu bu cevapla birleştirin ve verileri rootScope'a koymaya devam edin. Bunun da doğru olduğunu düşünmüyorum. Global olarak kullanılan veri bitlerini depolamanın ve geri göndermenin açısal yolu nedir?
user2483724 18:14

11
Özellikle değerleri depolamak için olan bir hizmetin dezavantajlarının ne olduğunu merak ediyorum. İzole, sadece ihtiyacınız olan yere enjekte edilir ve kolayca test edilebilir. Dezavantajı nedir?
Brian

12
Tanrım, neden herkes gerçek küresel değişkenlerden korkuyor, uygulamanızın ne içereceğini biliyorsanız, sadece aşırı karmaşık şeyler yerine gerçek bir küresel js değişkeni yapın
Max Yari

93

Yalnızca bir değeri saklamak istiyorsanız , Sağlayıcılardaki Açısal belgelere göre , Değer tarifini kullanmalısınız:

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

Sonra böyle bir denetleyicide kullanın:

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

Aynı şey, bir Sağlayıcı, Fabrika veya Hizmet kullanılarak da sağlanabilir, çünkü bunlar sadece bir sağlayıcı tarifinin üstünde sadece sözdizimsel şekerdir, ancak Value'i kullanmak en az sözdizimi ile istediğinizi elde edecektir.

Diğer seçenek kullanmaktır $rootScope, ancak gerçekten bir seçenek değildir, çünkü aynı nedenlerle kullanmamalısınız, global değişkenleri diğer dillerde kullanmamalısınız. Onun az kullanılması tavsiye edilir .

Tüm kapsamlar devralındığından $rootScope, bir değişkeniniz varsa $rootScope.datave datadaha önce tanımlanmış ve $scope.datayerel bir kapsamda oluşturulan birini unutursanız sorun yaşarsınız.


Bu değeri değiştirmek ve tüm denetleyicilerinizde kalıcı olmasını istiyorsanız, bir nesne kullanın ve özellikleri göz önünde bulundurarak değiştirin Javascript "başvurunun kopyası" ile geçirilir :

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

JSFiddle örneği


1
Bir görünümdeki değeri değiştirdiğimde, yeni değer kalıcı değildir. Nasıl olur? Lütfen cevabınızı güncelleyebilir ve nasıl clientIdgüncellenebileceğini görelim mi?
Blaise

@DeanOrya Yenilenen sayfalar arasındaki güncellenmiş değeri korumak mümkün mü? Sayfayı yenilersem değer yeniden başlatılır.
Nabarun

Bunun için çerez, yerel depolama veya veritabanı gibi başka bir şey kullanmanız gerekir.
Dean Or

1
Bunu gerçekten çok seviyorum. Şimdi dev, sahne ve prod için oluşturma işlemi ile değiştirebilirim
jemiloii

1
Global değişkenlere benzer sabitlerin ve değerlerin kullanımını açıklayan basit bir makale vardır: ilikekillnerds.com/2014/11/…
RushabhG

36

AngularJS "global değişkenleri" kullanarak örnek $rootScope :

Denetleyici 1 genel değişkeni ayarlar:

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

Denetleyici 2 genel değişkeni okur:

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

İşte çalışan bir jsFiddle: http://jsfiddle.net/natefriedman/3XT3F/1/


2
Bu, yalıtılmış kapsam direktiflerinin görünümlerinde çalışmaz. Bkz. Jsfiddle.net/3XT3F/7 . Ancak $ root kullanarak bu sorunu çözebilirsiniz. Bkz. Jsfiddle.net/3XT3F/10 . @Natefaubion'a işaret
Tony Lâmpada

2
yenilemede $ rootScope değeri boş olur.
xyonme

$ rootScope.name sabit kodlaması bir değere eşittir ... aslında onu okumalı ve orada ayarlamalıyız.

25

Wiki havuzuna başka bir fikir eklemek için, Peki ya AngularJS ' valueve constantmodülleri? Onları sadece kendim kullanmaya başlıyorum, ama bu bana muhtemelen en iyi seçenek gibi geliyor.

Not: yazma zamanı itibariyle, açısal 1.3.7 son kararlı, bunların 1.2.0'da eklendiğine inanıyorum, bunu changelog ile doğrulamamıştım.

Kaç tanesini tanımlamanız gerektiğine bağlı olarak, bunlar için ayrı bir dosya oluşturmak isteyebilirsiniz. Ancak bunları genellikle uygulamamın hemen öncesinden tanımlarım.config() kolay erişim için engellemesinden . Bunlar hala etkili modüller olduğundan, bunları kullanmak için bağımlılık enjeksiyonuna güvenmeniz gerekir, ancak bunlar uygulama modülünüz için "global" olarak kabul edilir.

Örneğin:

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

Sonra herhangi bir denetleyicinin içinde:

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

İlk sorudan aslında burada mutable (değer) veya final (sabit) olarak statik özellikler gerekli gibi geliyor. Kişisel fikrim her şeyden daha fazla, ancak çalışma zamanı yapılandırma öğelerini $rootScopeçok hızlı, çok dağınık hale getiriyor.


Değer modülünü çok kullanışlı ve özlü buluyorum. özellikle bir denetleyicinin içindeki bir $ kapsam değişkenine bağladığınızda, bu denetleyicinin mantığı veya görünümündeki değişiklikler genel değişken / değer / hizmete bağlanır
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;
}]);

HTML'nizde:

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

8
localStorage.username = 'blah'

Modern bir tarayıcıda olduğunuz garanti edilirse. Gerçi değerlerinizin hepsi dizgeye dönüştürülecektir.

Ayrıca yeniden yüklemeler arasında önbelleğe alınma gibi kullanışlı bir yararı vardır.


5
Heh, tüm değişkenleri localStorage ile saklayacağım. O zaman bir çeşit kalıcılığımız bile olacak! Ayrıca, dize sınırlamasını aşmak için, bir işlevin .toString () yöntemini saklayalım ve gerektiğinde değerlendirelim!
Shaz

gibi zaten @Shaz bahsettiği, bu persistensi sorunu var
Zubrowka

7

Yanılıyorsam lütfen beni düzeltin, ancak Angular 2.0 piyasaya çıktığında $rootScopeetrafta olacağına inanmıyorum . Benim varsayımım $scopeda kaldırılmakta olan gerçeğe dayanıyor . Açıkçası kontrolörler, sadece ng-controllermoda değil, hala var olacak . Bunun yerine kontrolörleri direktiflere enjekte etmeyi düşünün. Sürüm yaklaştıkça, 1.X'den 2.0 sürümüne geçmek için daha kolay bir zaman istiyorsanız hizmetleri global değişkenler olarak kullanmak en iyisi olacaktır.


Katılıyorum, doğrudan $ rootScope'a veri koymak Angular'ın tüm amacına aykırı. Biraz zaman ayırın ve kodunuzu düzgün bir şekilde düzenleyin ve sadece AngularJS 2.x yükseltmesinde değil, daha karmaşık hale geldikçe genellikle uygulamanızın gelişimi boyunca size yardımcı olacaktır.
CatalinBerta

3
$ RootScope kaldırılırsa, sadece "$ rootScope" adlı yeni bir hizmet yazın :)
uylmz

3

Ortam değişkenini ayrıca $windowbir denetleyicinin dışındaki bir genel değişken bildiriminin,$watch

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

Dikkat edin, sindirim döngüsü bu küresel değerlerle daha uzundur, bu nedenle her zaman gerçek zamanlı güncellenmez. Bu yapılandırma ile bu özet zamanı araştırmam gerekiyor.


0

Yanlışlıkla başka bir yöntem buldum:

Benim yaptığım bir ilan etmek oldu var db = nullyukarıdaki uygulama beyanı ve sonra onu modifiye app.jsiçinde bunu erişildiğinde sonra controller.js ben farkında değilim bu yöntemle bazı sorunlar olabilecek problem.there olmadan ulaşabilecek ama O var iyi bir çözüm sanırım.


0

Bunu deneyin, $rootScopekontrolöre enjekte etmeye zorlamayacaksınız .

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

Yapılandırma bloğu size $ rootScope hizmetini kullanmanızı sağlamadığından, yalnızca run bloğunda kullanabilirsiniz.


0

Aslında oldukça kolay. (Yine de Angular 2+ kullanıyorsanız.)

Basitçe ekleyin

declare var myGlobalVarName;

Bileşen dosyanızın üstünde bir yerde ("içe aktarma" ifadelerinden sonra olduğu gibi) ve bileşeninizin herhangi bir yerinde "myGlobalVarName" öğesine erişebileceksiniz.


-2

Bunun gibi bir şey de yapabilirsiniz ..

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

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}

3
$ rootScope bu şekilde kullanıldığında tanımsızdır.
Ahmad Ahmadi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.