AngularJS: Hizmet özelliklerine bağlanmanın doğru yolu


162

AngularJS bir service özelliği bağlamak için nasıl en iyi uygulama arıyorum.

AngularJS kullanılarak oluşturulan bir hizmetteki özelliklere nasıl bağlanacağını anlamak için birden çok örnek üzerinden çalıştım.

Aşağıda bir hizmetteki özelliklere nasıl bağlanılacağına dair iki örneğim var; ikisi de çalışır. İlk örnek temel bağlamaları ve ikinci örnek $ scope. $ Watch özelliğini kullanarak hizmet özelliklerine bağlanır

Bir hizmetteki özelliklere bağlanırken bu örneklerden herhangi biri tercih ediliyor mu yoksa bunun önerileceğinin farkında olmadığım başka bir seçenek var mı?

Bu örneklerin dayanağı, hizmetin “lastUpdated” ve “call” özelliklerini her 5 saniyede bir güncellemesi gerektiğidir. Hizmet özellikleri güncellendiğinde görünümün bu değişiklikleri yansıtması gerekir. Bu örneklerin ikisi de başarıyla çalışır; Bunu yapmanın daha iyi bir yolu olup olmadığını merak ediyorum.

Temel Ciltleme

Aşağıdaki kod görüntülenebilir ve burada çalıştırılabilir: http://plnkr.co/edit/d3c16z

<html>
<body ng-app="ServiceNotification" >

    <div ng-controller="TimerCtrl1" style="border-style:dotted"> 
        TimerCtrl1 <br/>
        Last Updated: {{timerData.lastUpdated}}<br/>
        Last Updated: {{timerData.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.timerData = Timer.data;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

Hizmet özelliklerine bağlamayı çözdüğüm diğer bir yol da denetleyicide $ scope. $ Watch kullanmaktır.

$ Kapsamı. $ İzle

Aşağıdaki kod görüntülenebilir ve burada çalıştırılabilir: http://plnkr.co/edit/dSBlC9

<html>
<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.$watch(function () { return Timer.data.lastUpdated; },
                function (value) {
                    console.log("In $watch - lastUpdated:" + value);
                    $scope.lastUpdated = value;
                }
            );

            $scope.$watch(function () { return Timer.data.calls; },
                function (value) {
                    console.log("In $watch - calls:" + value);
                    $scope.calls = value;
                }
            );
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

Hizmette $ rootscope. $ Yayın ve denetleyicide $ root. $ Açık kullanabileceğimin farkındayım, ancak ilk yayında $ broadcast / $ kullanan oluşturduğum diğer örneklerde ancak ek çağrılar denetleyicide tetiklenir. $ Rootscope. $ Broadcast problemini çözmenin bir yolunu biliyorsanız, lütfen bir cevap verin.

Ancak daha önce bahsettiğim şeyi yeniden ifade etmek için, bir hizmet özelliklerine nasıl bağlanacağına dair en iyi uygulamayı bilmek istiyorum.


Güncelleme

Bu soru ilk olarak Nisan 2013'te soruldu ve cevaplandı. Mayıs 2014'te Gil Birman, doğru cevap olarak değiştirdiğim yeni bir cevap verdi. Gil Birman cevabının çok az oyu olduğu için, endişem bu soruyu okuyan insanların cevabını daha fazla oyla diğer cevaplar lehine göz ardı edeceğidir. En iyi cevabın ne olduğuna karar vermeden önce Gil Birman'ın cevabını tavsiye ederim.


Josh David Miller'ın cevabı Gil Birman'dan daha iyi. Ve $ watch, $ watchGroup ve $ watchCollection kullanarak bunu daha da iyi hale getirebilir. Endişelerin ayrılması orta ila büyük boyutlu uygulamalarda çok önemlidir.
Jonathan

@bardev Her iki cevabın da yararlı olmadığını düşünüyorum ve yeni geliştiriciler bunları tamamen yanlış anlayacaklardı.
Zalaboza

Sorduğunuz sorun referans nesnelerin yerel JavaScript değişken davranışı ile ilgili, aşağıda biraz açıklama
ekledim

Yanıtlar:


100

İkinci yaklaşımın bazı artılarını ve eksilerini düşünün :

  • 0 {{lastUpdated}} yerine {{timerData.lastUpdated}}aynı kolaylıkla olabilir, hangi {{timer.lastUpdated}}ı daha okunabilir olduğunu iddia olabilir (ama Tartışmayalım let ... kendin için karar bu yüzden bu noktası nötr puanı veriyorum)

  • +1 Denetleyicinin işaretleme için bir çeşit API gibi davranması uygun olabilir, böylece veri modelinin yapısı bir şekilde değişirse (teoride) html kısmi değerine dokunmadan denetleyicinin API eşlemelerini güncelleyebilirsiniz .

  • -1 Ancak, teori her zaman pratik değildir ve yine de kendimi değişiklikler istendiğinde biçimlendirme ve denetleyici mantığını değiştirmek zorunda buluyorum . Bu nedenle, API yazma konusundaki ekstra çaba, avantajını reddeder.

  • -1 Ayrıca, bu yaklaşım çok KURU değildir.

  • -1 Kodunuza veri bağlamak istiyorsanız, yeni bir REST çağrısı yapmak için denetleyiciyi ng-modelyeniden paketlemeniz gerektiğinden daha az KURU olur $scope.scalar_values.

  • -0.1 Ekstra izleyici (ler) yaratan küçük bir performans isabeti var. Ayrıca, belirli bir denetleyicide izlenmesi gerekmeyen modele veri özellikleri eklenirse, derin gözlemciler için ek yük oluşturur.

  • -1 Birden fazla denetleyicinin aynı veri modellerine ihtiyacı varsa ne olur? Bu, her model değişikliğiyle güncellenecek birden çok API'nizin olduğu anlamına gelir.

$scope.timerData = Timer.data;şu anda kudretli bir ses çıkarmaya başlıyor ... Son noktaya biraz daha derinlemesine bakalım ... Ne tür bir model değişikliklerinden bahsediyorduk? Arka uçta (sunucu) bir model mi? Yoksa sadece ön uçta oluşturulan ve yaşayan bir model? Her iki durumda da, esasen veri eşleme API'sinin ne olduğu ön uç hizmet katmanına (açısal fabrika veya hizmet) aittir . (İlk örneğinizin - benim tercihim - hizmet katmanında böyle bir API'nın olmadığını unutmayın , bu da iyidir, çünkü ihtiyaç duymadığı kadar basittir.)

Sonuç olarak , her şeyin ayrıştırılması gerekmez. İşaretlemeyi tamamen veri modelinden ayırmakla birlikte, dezavantajlar avantajlardan ağır basmaktadır.


Kontrolörler, genel olarak $scope = injectable.data.scalar's ile çevrilmemelidir . Aksine, $scope = injectable.data', promise.then(..)' ve $scope.complexClickAction = function() {..}'

Veri-ayırımı ve böylece görüntüleme kapsülleme, o tek yer elde etmek alternatif bir yaklaşım olarak gerçekten modelden görünümü ayrılabilmesi için mantıklı olan bir yönerge ile . Ancak orada bile $watch, controllerveya linkişlevlerinde skaler değerler kullanmayın . Bu, zamandan tasarruf sağlamaz veya kodu daha sürdürülebilir veya okunabilir hale getirmez. Açısal olarak yapılan güçlü testler genellikle sonuçtaki DOM'u yine de test ettiğinden testi kolaylaştırmaz . Bunun yerine, bir yönergede veri API'nizi nesne biçiminde talep edin ve yalnızca $watchtarafından oluşturulan kullanıcıları kullanın ng-bind.


Örnek http://plnkr.co/edit/MVeU1GKRTN4bqA3h9Yio

<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Bad:<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
        Good:<br/>
        Last Updated: {{data.lastUpdated}}<br/>
        Last Updated: {{data.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.data = Timer.data;
            $scope.lastUpdated = Timer.data.lastUpdated;
            $scope.calls = Timer.data.calls;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 500);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>

GÜNCELLEME : Sonunda, bu yaklaşımın her ikisinin de "yanlış" olduğunu düşünmediğimi eklemek için geri döndüm. Başlangıçta Josh David Miller'ın cevabının yanlış olduğunu yazmıştım, ancak geçmişe bakıldığında, özellikle endişelerin ayrılması konusundaki noktaları tamamen geçerli.

Endişelerin bir kenara ayrılması (ama teğetsel olarak ilişkili), savunmasız kopyalamanın göz önünde bulundurmadığım başka bir nedeni daha var . Bu soru çoğunlukla doğrudan bir hizmetten veri okuma ile ilgilidir. Ancak ekibinizdeki bir geliştirici, görünümün görüntülenmeden önce denetleyicinin verileri önemsiz bir şekilde dönüştürmesi gerektiğine karar verirse ne olur? (Denetleyicilerin verileri hiç dönüştürüp dönüştürmeyeceği başka bir tartışmadır.) Öncelikle nesnenin bir kopyasını oluşturmazsa, farkında olmadan aynı verileri kullanan başka bir görünüm bileşeninde gerilemelere neden olabilir.

Bu sorunun gerçekten vurguladığı şey, tipik açısal uygulamanın (ve gerçekten herhangi bir JavaScript uygulamasının) mimari eksikliğidir: endişelerin sıkı bir şekilde birleştirilmesi ve nesne değişebilirliği. Son zamanlarda React ve değiştirilemez veri yapıları ile mimarlık uygulamasına hayran kaldım . Bunu yapmak aşağıdaki iki sorunu harika bir şekilde çözer:

  1. Endişelerin ayrılması : Bir bileşen, tüm verilerini sahne araçlarıyla tüketir ve küresel tektonlara (Açısal hizmetler gibi) çok az güvenir veya hiç güvenmez ve görünüm hiyerarşisinde üstünde ne olduğu hakkında hiçbir şey bilmez .

  2. Değişebilirlik : Tüm sahne değiştirilemez, bu da veri değişimini istememe riskini ortadan kaldırır.

Açısal 2.0, yukarıdaki iki noktayı elde etmek için React'ten yoğun bir şekilde borçlanma yolunda.


1
Daha fazla AngularJS ile çalışıyorum daha çok anlıyorum. AngularJS kontrol cihazlarının olabildiğince basit ve ince olması gerektiğine inanıyorum. Denetleyiciye $ saatler ekleyerek mantığı zorlaştırır. Sadece hizmetteki değeri referans alarak çok daha basit ve AngularJS yolundan daha fazla gibi görünüyor. -
Mike Barlow - BarDev

3
AngularJS'nin "on emri". Bir sebepten dolayı bildiricidir.
pilau

Josh David Miller'ın cevabı "YANLIŞ" değil. Her şey için bir zaman ve bir yer var.
JoshuaDavid

Bence haklısın, @FireCoding. Cevabı güncellemeyi planlıyorum.
Gil Birman

@GilBirman mükemmel cevap. Direktif için yazmayı ve örnek almayı düşünür müsünüz? Söylediklerinizi göstermek için "görünümü modelden ayırmanın gerçekten mantıklı olduğu tek yer bir yönerge ile. [...] Bunun yerine, bir yönergede veri API'nızı nesne biçiminde talep edin ve ng-bind tarafından oluşturulan gözlemciler. "
klode

78

Benim açımdan, $watchen iyi uygulama yolu olurdu.

Örneğinizi aslında biraz basitleştirebilirsiniz:

function TimerCtrl1($scope, Timer) {
  $scope.$watch( function () { return Timer.data; }, function (data) {
    $scope.lastUpdated = data.lastUpdated;
    $scope.calls = data.calls;
  }, true);
}

Tek ihtiyacınız olan bu.

Özellikler aynı anda güncellendiğinden, yalnızca bir saatiniz olması gerekir. Ayrıca, tek, oldukça küçük bir nesneden geldikleri için, sadece Timer.dataözelliği izlemek için değiştirdim . Geçilen son parametre $watch, yalnızca referansın aynı olduğundan emin olmak yerine derin eşitliği kontrol etmesini söyler.


Biraz bağlam sağlamak için, bu yöntemi hizmet değerini doğrudan kapsamına yerleştirmeyi tercih etmemin nedeni, endişelerin uygun şekilde ayrılmasını sağlamaktır. Çalışmanızın, hizmetleriniz hakkında hiçbir şey bilmesine gerek yoktur. Kontrolörün görevi her şeyi birbirine yapıştırmaktır; görevi, hizmetlerinizden veri almak ve bunları gereken şekilde işlemek ve ardından ihtiyaç duyduğunuz her türlü özelliğe görüşünüzü sağlamaktır. Ama işinin sadece hizmeti görmek için geçmesi olduğunu sanmıyorum. Aksi takdirde, kontrolör orada ne yapıyor? AngularJS geliştiricileri, şablonlara herhangi bir "mantık" eklememeyi seçtiklerinde aynı mantığı takip ettiler (örn. ifİfadeler).

Adil olmak gerekirse, burada muhtemelen birden fazla perspektif var ve diğer cevapları dört gözle bekliyorum.


3
Biraz detaylandırabilir misin? Görünümü servise daha az bağlı olduğu için $ saatlerini mi tercih edersiniz? Ie, {{lastUpdated}}vs.{{timerData.lastUpdated}}
Mark Rajcok

2
Timer.data$ Seyretmek için @BarDev Timer$ kapsamında tanımlanmalıdır, çünkü $ watch'a ilettiğiniz dize ifadesi kapsamla değerlendirilir. İşte bunun nasıl yapılacağını gösteren bir dalgıç . ObjectEquality parametresi burada belgelenmiştir - 3. parametre - ancak çok iyi açıklanmamıştır.
Mark Rajcok

2
Performans açısından, $watcholdukça verimsiz. En cevapları görün stackoverflow.com/a/17558885/932632 ve stackoverflow.com/questions/12576798/...
Krym

11
@Kyrm Bu muhtemelen bazı durumlarda doğrudur, ancak performansla uğraşırken yalnızca istatistiksel olarak anlamlı, genelleştirilmiş olanlardan ziyade "klinik olarak önemli" performans geliştirmelerini aramamız gerekir. Mevcut bir uygulamada bir performans sorunu varsa, bu sorunun giderilmesi gerekir. Aksi takdirde, en iyi uygulamaları takip etmeyen ve kanıtlanmış bir faydası olmayan, okunması daha zor, hata eğilimli bir koda yol açan erken bir optimizasyon örneğidir.
Josh David Miller

1
İzleyicinin alıcıyı çağırmak için bir işlev kullandığını varsayarsak, evet. İyi çalışıyor. Ayrıca bir koleksiyonda örnekleri döndüren hizmetlerin bir destekçisiyim, bunun yerine es5'in alıcı ve ayarlayıcı özellikleri oldukça iyi.
Josh David Miller

19

Partiye geç, ancak gelecekteki Google çalışanları için verilen cevabı kullanmayın.

JavaScript, nesneleri referans olarak geçirme mekanizmasına sahipken, "sayılar, dizeler vb." Değerleri için yalnızca sığ bir kopya geçirir.

Yukarıdaki örnekte, bir hizmetin bağlayıcı öznitelikleri yerine, hizmeti neden kapsama maruz bırakmıyoruz?

$scope.hello = HelloService;

Bu basit yaklaşım, açısal iki yönlü ciltleme ve ihtiyacınız olan tüm büyülü şeyleri yapabilecektir. Denetleyicinizi izleyiciler veya gereksiz işaretleme ile hacklemeyin.

Hizmet özelliklerinizin üzerine yanlışlıkla yazdığınızdan endişe ediyorsanız, definePropertyonu okunabilir, numaralandırılabilir, yapılandırılabilir yapmak veya alıcıları ve ayarlayıcıları tanımlamak için kullanın. Hizmetinizi daha sağlam hale getirerek çok fazla kontrol elde edebilirsiniz.

Son ipucu: Zamanınızı kontrol cihazınız üzerinde hizmetlerinizden daha fazla harcıyorsanız, yanlış yapıyorsunuz :(.

Sağladığınız belirli demo kodunda şunları yapmanızı tavsiye ederim:

 function TimerCtrl1($scope, Timer) {
   $scope.timer = Timer;
 }
///Inside view
{{ timer.time_updated }}
{{ timer.other_property }}
etc...

Düzenle:

Yukarıda belirttiğim gibi, hizmet özelliklerinizin davranışını aşağıdakileri kullanarak kontrol edebilirsiniz: defineProperty

Misal:

// Lets expose a property named "propertyWithSetter" on our service
// and hook a setter function that automatically saves new value to db !
Object.defineProperty(self, 'propertyWithSetter', {
  get: function() { return self.data.variable; },
  set: function(newValue) { 
         self.data.variable = newValue; 
         // let's update the database too to reflect changes in data-model !
         self.updateDatabaseWithNewData(data);
       },
  enumerable: true,
  configurable: true
});

Şimdi kontrolörümüzde

$scope.hello = HelloService;
$scope.hello.propertyWithSetter = 'NEW VALUE';

hizmetimiz değerini değiştirecek propertyWithSetterve yeni değeri bir şekilde veritabanına gönderecektir!

Ya da istediğimiz her yaklaşımı benimseyebiliriz.

İçin MDN belgelerine bakın defineProperty.


Yukarıda $scope.model = {timerData: Timer.data};doğrudan anlattığım şeyden eminim , doğrudan Scope yerine modele bağlamak.
Scott Silvi

1
AFAIK, js nesne başvurusu Hizmet her şey için çalışır. Bunun gibi kodlama: $ scope.controllerVar = ServiceVar, $ scope.controllerVar içinde yaptığınız her şey ServiceVar'da da yapılır.
Kai Wang

@KaiWang, DefineAttribute kullanmaya karar vermedikçe, hizmetlerinizin denetleyicilerin yanlışlıkla hizmet verilerinizi değiştirmesini önlemek için bir ayarlayıcı işlevine sahip olmasını sağlayabilirsiniz.
Zalaboza

12

Bu sorunun bağlamsal bir bileşeni olduğunu düşünüyorum.

Bir hizmetten yalnızca veri alıyorsanız ve bu bilgileri görünümüne yayarsanız, doğrudan service özelliğine bağlamanın iyi olduğunu düşünüyorum. Sadece benim görüşüme göre tüketmek için model özelliklerini hizmet özelliklerini eşlemek için boilerplate kodu yazmak istemiyorum .

Ayrıca, açısal performans iki şeye dayanmaktadır. Birincisi, bir sayfada kaç cilt olduğunu. İkincisi, alıcı fonksiyonlarının ne kadar pahalı olduğudur. Misko burada bunun hakkında konuşuyor

Hizmet verileri üzerinde örnek özel mantık gerçekleştirmeniz gerekiyorsa (hizmetin kendisinde uygulanan veri masajının aksine) ve bunun sonucu görünüme maruz kalan veri modelini etkiler, o zaman $ watcher'ın uygun olduğunu söyleyebilirim. işlev çok pahalı olmadığı sürece. Pahalı bir işlev durumunda, sonuçları yerel (denetleyiciye) değişkeninde önbelleğe almanızı, $ watcher işlevi dışında karmaşık işlemlerinizi gerçekleştirmenizi ve ardından kapsamınızı bunun sonucuna bağlamanızı öneririm.

Bir uyarı olarak, hiçbir özelliği doğrudan $ kapsamınızın dışında bırakmamalısınız . $scopeDeğişken modeliniz DEĞİLDİR. Modelinize referansları var.

Zihnimde, bilgileri hizmetten görünüme yaymak için "en iyi uygulama":

function TimerCtrl1($scope, Timer) {
  $scope.model = {timerData: Timer.data};
};

Ve sonra görüşünüz içerecektir {{model.timerData.lastupdated}}.


bu öneriye dikkat ederek, javascript konusunda uzman olmayan biri bunu bir dize olan bir özellikle yapmaya çalışabilir. Bu durumda, javascript nesneye başvuru yapmaz, ancak ham dizeyi kopyalar. (ve bu değişir, eğer değişirse güncellenmez)
Valerio

7
Her zaman noktayı kullanmanız gereken 'uyarım' ile örtmedim mi (yani $ kapsamı dışında değil, $ scope.model kapalı). $ Scope.model.someStringProperty varsa ve görünümünüzde model.someStringProperty'ye başvuruyorsanız, iç gözlemciler prop üzerinde değil, nesnede olacak çünkü güncellenecektir.
Scott Silvi

6

Yukarıdaki örneklere dayanarak, bir denetleyici değişkenini bir hizmet değişkenine şeffaf bir şekilde bağlayacağımı düşündüm.

Aşağıdaki örnekte, Controller $scope.countdeğişkenindeki değişiklikler otomatik olarak Servis countdeğişkenine yansıtılacaktır .

Üretimde, aslında bu bağlamayı, bir hizmet üzerindeki kimliği güncellemek için kullanıyoruz; bu, daha sonra senkronize olmayan bir şekilde veri getirir ve hizmetini değiştirir. Daha fazla ciltleme, hizmet kendini güncellediğinde denetleyicilerin otomatik olarak güncelleneceği anlamına gelir.

Aşağıdaki kod http://jsfiddle.net/xuUHS/163/ adresinde çalışırken görülebilir.

Görünüm:

<div ng-controller="ServiceCtrl">
    <p> This is my countService variable : {{count}}</p>
    <input type="number" ng-model="count">
    <p> This is my updated after click variable : {{countS}}</p>

    <button ng-click="clickC()" >Controller ++ </button>
    <button ng-click="chkC()" >Check Controller Count</button>
    </br>

    <button ng-click="clickS()" >Service ++ </button>
    <button ng-click="chkS()" >Check Service Count</button>
</div>

Hizmet / Denetleyici:

var app = angular.module('myApp', []);

app.service('testService', function(){
    var count = 10;

    function incrementCount() {
      count++;
      return count;
    };

    function getCount() { return count; }

    return {
        get count() { return count },
        set count(val) {
            count = val;
        },
        getCount: getCount,
        incrementCount: incrementCount
    }

});

function ServiceCtrl($scope, testService)
{

    Object.defineProperty($scope, 'count', {
        get: function() { return testService.count; },
        set: function(val) { testService.count = val; },
    });

    $scope.clickC = function () {
       $scope.count++;
    };
    $scope.chkC = function () {
        alert($scope.count);
    };

    $scope.clickS = function () {
       ++testService.count;
    };
    $scope.chkS = function () {
        alert(testService.count);
    };

}

Bu harika bir çözüm, teşekkür ederim, bu bana çok, çok akıllı bir şekilde yardımcı oldu :)
Javis Perez

2

Ben onun yerine öznitelikleri yerine hizmetin kendisine bağlamak için daha iyi bir yol olduğunu düşünüyorum .

İşte nedeni:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular.min.js"></script>
<body ng-app="BindToService">

  <div ng-controller="BindToServiceCtrl as ctrl">
    ArrService.arrOne: <span ng-repeat="v in ArrService.arrOne">{{v}}</span>
    <br />
    ArrService.arrTwo: <span ng-repeat="v in ArrService.arrTwo">{{v}}</span>
    <br />
    <br />
    <!-- This is empty since $scope.arrOne never changes -->
    arrOne: <span ng-repeat="v in arrOne">{{v}}</span>
    <br />
    <!-- This is not empty since $scope.arrTwo === ArrService.arrTwo -->
    <!-- Both of them point the memory space modified by the `push` function below -->
    arrTwo: <span ng-repeat="v in arrTwo">{{v}}</span>
  </div>

  <script type="text/javascript">
    var app = angular.module("BindToService", []);

    app.controller("BindToServiceCtrl", function ($scope, ArrService) {
      $scope.ArrService = ArrService;
      $scope.arrOne = ArrService.arrOne;
      $scope.arrTwo = ArrService.arrTwo;
    });

    app.service("ArrService", function ($interval) {
      var that = this,
          i = 0;
      this.arrOne = [];
      that.arrTwo = [];

      $interval(function () {
        // This will change arrOne (the pointer).
        // However, $scope.arrOne is still same as the original arrOne.
        that.arrOne = that.arrOne.concat([i]);

        // This line changes the memory block pointed by arrTwo.
        // And arrTwo (the pointer) itself never changes.
        that.arrTwo.push(i);
        i += 1;
      }, 1000);

    });
  </script>
</body> 

Bu dalgıç üzerinde oynayabilirsiniz .


1

Gözetmenlerimi mümkün olduğunca az tutmayı tercih ederim. Sebebim deneyimlerime dayanıyor ve kişi teorik olarak tartışabilir.
Watchers kullanmayla ilgili sorun, istediğiniz herhangi bir bileşen veya hizmetteki yöntemlerden herhangi birini çağırmak için kapsamdaki herhangi bir özelliği kullanabilmenizdir.
Gerçek bir dünya projesinde, çok yakında izlenebilir olmayan ( izlenmesi daha iyi söylenir) bir yöntem zinciri çağrılır ve değerler değiştirilir, bu da özellikle yerleşik süreci trajik hale getirir.


0

Hizmet gönderen herhangi bir veriyi bağlamak iyi bir fikir değildir (mimari), ancak artık ihtiyacınız varsa bunu yapmanın 2 yolunu öneririm

1) Hizmetinizin içinde olmayan verileri alabilirsiniz.

2) angularjs olaylarını kullanabilirsiniz. İstediğiniz zaman bir sinyal ($ rootScope'tan) gönderebilir ve istediğiniz yere yakalayabilirsiniz.

Belki bu size yardımcı olabilir. Örneklerle daha fazlasına ihtiyacınız varsa, işte link

http://www.w3docs.com/snippets/angularjs/bind-value-between-service-and-controller-directive.html


-1

Ne dersin

scope = _.extend(scope, ParentScope);

ParentScope nereye enjekte edilir?


-2

En Şık Çözümler ...

app.service('svc', function(){ this.attr = []; return this; });
app.controller('ctrl', function($scope, svc){
    $scope.attr = svc.attr || [];
    $scope.$watch('attr', function(neo, old){ /* if necessary */ });
});
app.run(function($rootScope, svc){
    $rootScope.svc = svc;
    $rootScope.$watch('svc', function(neo, old){ /* change the world */ });
});

Ayrıca, EDA'lar (Olay Odaklı Mimariler) yazdım, bu yüzden aşağıdaki [basitleştirilmiş sürüm] gibi bir şey yapmaya eğilimliyim:

var Service = function Service($rootScope) {
    var $scope = $rootScope.$new(this);
    $scope.that = [];
    $scope.$watch('that', thatObserver, true);
    function thatObserver(what) {
        $scope.$broadcast('that:changed', what);
    }
};

Sonra, denetleyicime istenen kanalda bir dinleyici koydum ve yerel kapsamımı bu şekilde güncel tutuyorum.

Sonuç olarak, bir şeyleri SOLID tuttuğunuz ve zayıf bağlantı kullandığınız sürece , bir "En İyi Uygulama" nın pek çoğu yoktur - daha çok tercih edilir. İkinci kodu savunmamın nedeni, EDA'ların doğası gereği mümkün olan en düşük bağlantıya sahip olmasıdır. Ve bu gerçek hakkında fazla endişelenmiyorsanız, aynı proje üzerinde birlikte çalışmaktan kaçınalım.

Bu yardımcı olur umarım...

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.