AngularJS: il modo corretto di associare alle proprietà di un servizio


162

Sto cercando la migliore pratica su come associare una proprietà di servizio in AngularJS.

Ho lavorato su più esempi per capire come associare le proprietà in un servizio creato utilizzando AngularJS.

Di seguito ho due esempi di come associare le proprietà in un servizio; entrambi funzionano. Il primo esempio usa i collegamenti di base e il secondo esempio usa $ scope. $ Watch per associare le proprietà del servizio

Uno di questi esempi è preferito quando si associa alle proprietà di un servizio o esiste un'altra opzione di cui non sono a conoscenza?

La premessa di questi esempi è che il servizio dovrebbe aggiornare le sue proprietà "lastUpdated" e "chiama" ogni 5 secondi. Una volta aggiornate le proprietà del servizio, la vista dovrebbe riflettere queste modifiche. Entrambi questi esempi funzionano correttamente; Mi chiedo se esiste un modo migliore per farlo.

Rilegatura di base

Il seguente codice può essere visualizzato ed eseguito qui: 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>

L'altro modo in cui ho risolto l'associazione alle proprietà del servizio consiste nell'utilizzare $ scope. $ Watch nel controller.

$ Portata. $ Orologio

Il seguente codice può essere visualizzato ed eseguito qui: 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>

Sono consapevole di poter utilizzare $ rootscope. $ Broadcast nel servizio e $ root. $ On nel controller, ma in altri esempi che ho creato che utilizzano $ broadcast / $ nella prima trasmissione non viene acquisito dal controller, ma le chiamate aggiuntive che vengono trasmesse vengono attivate nel controller. Se sei a conoscenza di un modo per risolvere il problema di $ rootscope. $ Broadcast, fornisci una risposta.

Ma per ribadire ciò che ho menzionato in precedenza, vorrei conoscere la migliore pratica su come associare le proprietà di un servizio.


Aggiornare

Questa domanda è stata originariamente posta e ha risposto ad aprile 2013. Nel maggio 2014, Gil Birman ha fornito una nuova risposta, che ho modificato come risposta corretta. Poiché la risposta di Gil Birman ha pochi voti positivi, la mia preoccupazione è che le persone che leggono questa domanda ignorino la sua risposta a favore di altre risposte con molti più voti. Prima di prendere una decisione su quale sia la risposta migliore, consiglio vivamente la risposta di Gil Birman.


Penso che la risposta di Josh David Miller sia migliore di quella di Gil Birman. E usando $ watch, $ watchGroup e $ watchCollection può persino migliorarlo. La separazione delle preoccupazioni è molto importante nelle app di medie e grandi dimensioni.
Jonathan,

@bardev Penso che entrambe le risposte non siano state utili e che i nuovi sviluppatori le avrebbero comprese completamente in modo errato.
Zalaboza,

Il problema di cui ti
stai

Risposte:


100

Considera alcuni pro e contro del secondo approccio :

  • 0 {{lastUpdated}} invece di {{timerData.lastUpdated}}, che potrebbe essere altrettanto facile {{timer.lastUpdated}}, che potrei sostenere sia più leggibile (ma non discutiamo ... sto dando a questo punto un punteggio neutro in modo da decidere tu stesso)

  • +1 Può essere conveniente che il controller agisca come una sorta di API per il markup in modo tale che se in qualche modo cambia la struttura del modello di dati è possibile (in teoria) aggiornare i mapping API del controller senza toccare il parziale HTML.

  • -1 Tuttavia, la teoria non è sempre pratica e di solito mi ritrovo a dover modificare il markup e la logica di controllo quando i cambiamenti sono chiamati per, in ogni caso . Quindi lo sforzo extra di scrivere l'API ne nega il vantaggio.

  • -1 Inoltre, questo approccio non è molto ASCIUTTO.

  • -1 Se si desidera associare i dati al ng-modelcodice, diventare ancora meno ASCIUTTO in quanto è necessario reimballare il $scope.scalar_valuesnel controller per effettuare una nuova chiamata REST.

  • -0.1 C'è un piccolo colpo di performance che crea osservatori extra. Inoltre, se le proprietà dei dati sono associate al modello che non necessitano di essere guardate in un determinato controller, creeranno un sovraccarico aggiuntivo per gli osservatori profondi.

  • -1 Cosa succede se più controller necessitano degli stessi modelli di dati? Ciò significa che hai più API da aggiornare ad ogni cambio di modello.

$scope.timerData = Timer.data;sta iniziando a sembrare possente allettante proprio ora ... Andiamo un po 'più a fondo in quell'ultimo punto ... Di che tipo di cambiamenti di modello stavamo parlando? Un modello sul back-end (server)? O un modello che viene creato e vive solo nel front-end? In entrambi i casi, ciò che è essenzialmente l' API di mappatura dei dati appartiene al livello di servizio front-end (una fabbrica o un servizio angolare). (Nota che il tuo primo esempio - la mia preferenza - non ha una tale API nel livello di servizio , il che va bene perché è abbastanza semplice da non averne bisogno.)

In conclusione , non è necessario disaccoppiare tutto. E per quanto riguarda il disaccoppiamento del markup interamente dal modello di dati, gli svantaggi superano i vantaggi.


I controller, in generale , non dovrebbero essere disseminati di $scope = injectable.data.scalar's. Piuttosto, dovrebbero essere cosparsi di $scope = injectable.data"s promise.then(..)" e $scope.complexClickAction = function() {..}"s"

Come approccio alternativo per ottenere il disaccoppiamento dei dati e quindi l'incapsulamento della vista, l'unico posto in cui ha davvero senso separare la vista dal modello è con una direttiva . Ma anche lì, non $watchvalori scalari nelle funzioni controllero link. Ciò non farà risparmiare tempo o renderà il codice più gestibile o leggibile. Non semplifica nemmeno i test poiché test robusti in angolare di solito testano comunque il DOM risultante . Piuttosto, in una direttiva richiedi la tua API di dati in forma di oggetto e preferisci usare solo gli $watcheri creati da ng-bind.


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

AGGIORNAMENTO : Sono finalmente tornato a questa domanda per aggiungere che non penso che nessuno dei due approcci sia "sbagliato". Inizialmente avevo scritto che la risposta di Josh David Miller era errata, ma a posteriori i suoi punti sono completamente validi, in particolare il suo punto sulla separazione delle preoccupazioni.

Separazione delle preoccupazioni a parte (ma tangenzialmente correlate), c'è un'altra ragione per la copia difensiva che non ho considerato. Questa domanda riguarda principalmente la lettura dei dati direttamente da un servizio. Ma cosa succede se uno sviluppatore del tuo team decide che il controller deve trasformare i dati in un modo banale prima che la vista li mostri? (Se i controller debbano trasformare i dati è un'altra discussione.) Se prima non crea una copia dell'oggetto, potrebbe involontariamente causare regressioni in un altro componente della vista che consuma gli stessi dati.

Ciò che questa domanda mette davvero in evidenza sono le carenze architettoniche della tipica applicazione angolare (e in realtà qualsiasi applicazione JavaScript): stretto accoppiamento di preoccupazioni e mutabilità degli oggetti. Di recente mi sono innamorato dell'applicazione di architettura con React e strutture di dati immutabili. In questo modo si risolvono meravigliosamente i seguenti due problemi:

  1. Separazione delle preoccupazioni : un componente consuma tutti i suoi dati tramite oggetti di scena e ha una dipendenza minima o nulla dai singleton globali (come i servizi angolari) e non sa nulla di ciò che è accaduto sopra di esso nella gerarchia della vista.

  2. Mutabilità : tutti gli oggetti di scena sono immutabili, il che elimina il rischio di involontaria mutazione dei dati.

Angular 2.0 è ora sulla buona strada per prendere in prestito pesantemente da React per raggiungere i due punti sopra.


1
Più lavoro con AngularJS, più capisco. Credo che i controller AngularJS debbano essere il più semplici e sottili possibile. Aggiungendo $ watch nel controller, ciò complica la logica. Facendo semplicemente riferimento al valore nel servizio, è molto più semplice e sembra essere più simile ad AngularJS. -
Mike Barlow - BarDev,

3
I "dieci comandamenti" di AngularJS. È dichiarativo per un motivo.
pilau,

La risposta di Josh David Miller non è "INCORRETTA". C'è un tempo e un luogo per tutto.
JoshuaDavid,

Penso che tu abbia ragione, @FireCoding. Sto programmando di aggiornare la risposta.
Gil Birman,

@GilBirman ottima risposta. Ti dispiacerebbe scrivere ed esempio per la direttiva? Per illustrare ciò che hai detto "l'unico posto che ha davvero senso separare la vista dal modello è con una direttiva. [...] Piuttosto, in una direttiva richiedi la tua API di dati in forma di oggetto e preferisci usare solo $ osservatori creati da ng-bind. "
Klode,

78

Dal mio punto di vista, $watchsarebbe il metodo migliore.

Puoi effettivamente semplificare un po 'il tuo esempio:

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

Questo è tutto ciò di cui hai bisogno.

Poiché le proprietà vengono aggiornate contemporaneamente, è necessario un solo orologio. Inoltre, poiché provengono da un singolo oggetto piuttosto piccolo, l'ho cambiato per guardare solo la Timer.dataproprietà. L'ultimo parametro passato a gli $watchdice di verificare la profonda uguaglianza piuttosto che assicurarsi che il riferimento sia lo stesso.


Per fornire un piccolo contesto, il motivo per cui preferirei questo metodo al posizionamento del valore del servizio direttamente nell'ambito è quello di garantire un'adeguata separazione delle preoccupazioni. Il tuo punto di vista non dovrebbe avere bisogno di sapere nulla dei tuoi servizi per poter funzionare. Il compito del controller è di incollare tutto insieme; il suo compito è quello di ottenere i dati dai tuoi servizi ed elaborarli in qualsiasi modo necessario e quindi fornire alla tua vista le specifiche di cui ha bisogno. Ma non credo che il suo compito sia semplicemente passare il servizio direttamente alla vista. Altrimenti, cosa ci fa il controller? Gli sviluppatori di AngularJS hanno seguito lo stesso ragionamento quando hanno scelto di non includere alcuna "logica" nei modelli (ad es. ifDichiarazioni).

Ad essere sinceri, ci sono probabilmente più prospettive qui e non vedo l'ora di altre risposte.


3
Puoi elaborare un po '? Preferisci gli orologi $ perché la vista è meno abbinata al servizio? {{lastUpdated}}{{timerData.lastUpdated}}
Vale a

2
@BarDev, da utilizzare Timer.datain un $ watch, Timerdeve essere definito nell'ambito $ scope, poiché l'espressione di stringa che si passa a $ watch viene valutata rispetto all'ambito. Ecco un plunker che mostra come farlo funzionare. Il parametro objectEquality è documentato qui - 3 ° parametro - ma in realtà non è spiegato troppo bene.
Mark Rajcok,

2
Per quanto riguarda le prestazioni, $watchè abbastanza inefficiente. Vedi le risposte su stackoverflow.com/a/17558885/932632 e stackoverflow.com/questions/12576798/…
Krym

11
@Kyrm Questo è probabilmente vero in alcune circostanze, ma quando si tratta di prestazioni dobbiamo cercare i miglioramenti "clinicamente significativi" delle prestazioni, piuttosto che quelli statisticamente significativi e generalizzati. Se si verifica un problema di prestazioni in un'applicazione esistente, è necessario risolverlo. Altrimenti, è solo un caso di ottimizzazione prematura, che porta a un codice più difficile da leggere e soggetto a bug che non segue le migliori pratiche e che non ha alcun vantaggio dimostrato.
Josh David Miller,

1
Supponendo che l'osservatore utilizzi una funzione per chiamare il getter, quindi sì. Funziona bene. Sono anche un sostenitore dei servizi che restituiscono istanze in una raccolta, dove invece le funzionalità getter e setter di es5 sono piuttosto buone.
Josh David Miller,

19

In ritardo alla festa, ma per futuri Googler - non utilizzare la risposta fornita.

JavaScript ha un meccanismo di passaggio di oggetti per riferimento, mentre passa solo una copia superficiale per valori "numeri, stringhe ecc".

Nell'esempio sopra, invece di associare gli attributi di un servizio, perché non esponiamo il servizio all'ambito?

$scope.hello = HelloService;

Questo semplice approccio renderà angolare in grado di eseguire rilegature bidirezionali e tutte le cose magiche di cui hai bisogno. Non hackerare il controller con watcher o markup non necessari.

E se sei preoccupato per la tua vista che sovrascrive accidentalmente gli attributi del tuo servizio, usa definePropertyper renderlo leggibile, enumerabile, configurabile o definire getter e setter. Puoi ottenere un sacco di controllo rendendo il tuo servizio più solido.

Suggerimento finale: se passi il tempo a lavorare sul tuo controller più dei tuoi servizi, allora stai sbagliando :(.

In quel particolare codice demo che hai fornito, ti consiglio di fare:

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

Modificare:

Come accennato in precedenza, è possibile controllare il comportamento degli attributi del servizio tramite defineProperty

Esempio:

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

Ora nel nostro controller se lo facciamo

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

il nostro servizio cambierà il valore propertyWithSettere pubblicherà il nuovo valore nel database in qualche modo!

Oppure possiamo adottare qualsiasi approccio desideriamo.

Consultare la documentazione MDN per defineProperty.


Abbastanza sicuro che è quello che stavo descrivendo sopra, con $scope.model = {timerData: Timer.data};, semplicemente collegandolo al modello invece che direttamente su Scope.
Scott Silvi,

1
AFAIK, il riferimento all'oggetto js funziona per tutto ciò che è in servizio. La codifica in questo modo: $ scope.controllerVar = ServiceVar, tutto ciò che fai in $ scope.controllerVar viene fatto anche in ServiceVar.
Kai Wang,

@KaiWang concorda, a meno che tu non decida di utilizzare DefineAttribute, puoi rendere i tuoi servizi dotati di una funzione setter per impedire ai controller di mutare accidentalmente i tuoi dati di servizio.
Zalaboza,

12

Penso che questa domanda abbia una componente contestuale.

Se stai semplicemente estraendo dati da un servizio e irradiando tali informazioni alla sua vista, penso che il legame diretto con la proprietà del servizio vada bene. Non voglio scrivere molto codice boilerplate per mappare semplicemente le proprietà del servizio alle proprietà del modello da utilizzare a mio avviso.

Inoltre, le prestazioni in angolare si basano su due cose. Il primo è il numero di associazioni presenti in una pagina. Il secondo è quanto costose funzioni getter. Misko ne parla qui

Se è necessario eseguire una logica specifica dell'istanza sui dati del servizio (al contrario del massaggio dei dati applicato all'interno del servizio stesso) e il risultato di ciò influisce sul modello di dati esposto alla vista, allora direi che un $ watcher è appropriato, come purché la funzione non sia terribilmente costosa. Nel caso di una funzione costosa, suggerirei di memorizzare nella cache i risultati in una variabile locale (al controller), eseguendo le tue operazioni complesse al di fuori della funzione $ watcher e quindi vincolando il tuo ambito al risultato.

Come avvertimento, non dovresti appendere nessuna proprietà direttamente dal tuo $ scope. La $scopevariabile NON è il tuo modello. Ha riferimenti al tuo modello.

Nella mia mente, "best practice" per semplicemente irradiare informazioni dal servizio fino a visualizzare:

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

E quindi la tua vista conterrebbe {{model.timerData.lastupdated}}.


attento a quel suggerimento, qualcuno non esperto in JavaScript potrebbe provare a farlo con una proprietà che è una stringa. In tal caso javascript non fa riferimento all'oggetto, ma copia la stringa non elaborata. (e questo è male perché non viene aggiornato, se cambia)
Valerio

7
Non ho coperto questo con il mio 'avvertimento' che dovresti sempre usare il punto (il che significa che non appenderlo a $ scope, ma a $ scope.model). Se hai $ scope.model.someStringProperty e fai riferimento a model.someStringProperty nella tua vista, verrà aggiornato, perché gli osservatori interni saranno sull'oggetto, non sul prop.
Scott Silvi,

6

Basandomi sugli esempi precedenti, ho pensato di aggiungere in modo trasparente una variabile del controller a una variabile di servizio.

Nell'esempio seguente le modifiche alla $scope.countvariabile Controller si rifletteranno automaticamente nella countvariabile Service .

In produzione stiamo effettivamente utilizzando questo bind per aggiornare un ID su un servizio che quindi recupera i dati in modo asincrono e ne aggiorna le varianti di servizio. Ulteriore associazione significa che i controller vengono automaticamente aggiornati quando il servizio si aggiorna da solo.

Il codice seguente può essere visto funzionante su http://jsfiddle.net/xuUHS/163/

Visualizza:

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

Servizio / Controller:

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

}

Questa è una soluzione fantastica, grazie, mi ha aiutato molto, un modo molto intelligente di farlo :)
Javis Perez,

2

Penso che sia un modo migliore per associare il servizio stesso invece degli attributi su di esso.

Ecco perché:

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

Puoi giocare su questo plunker .


1

Preferirei mantenere i miei osservatori il meno possibile. La mia ragione si basa sulle mie esperienze e si potrebbe argomentare teoricamente.
Il problema con l'utilizzo di watcher è che è possibile utilizzare qualsiasi proprietà nell'ambito per chiamare uno dei metodi in qualsiasi componente o servizio desiderato.
In un progetto del mondo reale, molto presto ti ritroverai con una catena non tracciabile (meglio dire difficile da rintracciare) di metodi che vengono chiamati e che i valori vengono modificati, il che rende particolarmente tragico il processo di onboarding.


0

Associare qualsiasi dato, che invia il servizio non è una buona idea (architettura), ma se ne hai più bisogno ti suggerisco 2 modi per farlo

1) puoi ottenere i dati non all'interno del tuo servizio. Puoi ottenere i dati all'interno del tuo controller / direttiva e non avrai problemi a vincolarli ovunque

2) puoi usare gli eventi angularjs. Ogni volta che vuoi, puoi inviare un segnale (da $ rootScope) e catturarlo dove vuoi. Puoi persino inviare un dato su quel eventName.

Forse questo può aiutarti. Se hai bisogno di più con esempi, ecco il link

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


-1

Che dire

scope = _.extend(scope, ParentScope);

Dove ParentScope è un servizio iniettato?


-2

Le soluzioni più eleganti ...

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

Inoltre, scrivo EDA (Event-Driven Architectures), quindi tendo a fare qualcosa del tipo [versione semplificata]:

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

Quindi, inserisco un ascoltatore nel mio controller sul canale desiderato e mantengo aggiornato il mio ambito locale in questo modo.

In conclusione, non c'è molto di una "Best Practice" - piuttosto, è principalmente la sua preferenza - fintanto che stai mantenendo le cose SOLID e impiegando un accoppiamento debole. Il motivo per cui vorrei sostenere quest'ultimo codice è perché gli EDA hanno l' accoppiamento più basso possibile per natura. E se non sei troppo preoccupato per questo fatto, evitiamo di lavorare insieme allo stesso progetto.

Spero che questo ti aiuti...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.