Le migliori pratiche per l’utilizzo di $ rootcope in un’applicazione Angularjs?

Abbiamo una grande applicazione Angularjs 1.6 che ha $ rootscope sparsi in tutta l’app in oltre 200 punti in filtri, servizi, percorsi, ecc. Quindi è necessario refactoring, ma non sono sicuro di sapere quando rimuoverlo. Quando è buona norma usare $ rootcope nell’applicazione?

Ho letto tutto da Mai, a usarlo per la memorizzazione di variabili, che presumo fosse per la condivisione di dati tra i controller. Da allora ho letto che è preferibile utilizzare fabbriche / servizi per questo caso d’uso e ho anche letto che un caso d’uso valido è usare $ rootscope come bus di eventi globali.

Non ho davvero visto questo spiegato nei documenti di Angularjs.

Da ng-book :

Quando Angular inizia a funzionare e genera la vista, creerà un’associazione dall’elemento root ng-app a $ rootScope. Questo $ rootScope è il genitore finale di tutti gli oggetti $ scope. L’object $ rootScope è l’object più vicino che abbiamo al contesto globale in un’app Angular. È una ctriggers idea attaccare troppa logica a questo contesto globale, nello stesso modo in cui non è una buona idea sporcare l’ambito globale di JavaScript.

Hai ragione, dovresti sicuramente usare i Servizi per condividere dati e logica tra i tuoi moduli.

Mettere molta logica in $ rootScope significa avere una scarsa manutenibilità e modularità nell’applicazione, è anche molto difficile testare i problemi.

Ti consiglio vivamente di dare un’occhiata a:

  • Servizi AngularJS Documentation
  • Articolo brillante di Thinkster su come condividere i dati tra i controller
  • Screencast di Simpulton
  • @ Breck421 rispondere a questa domanda

So che potrebbe essere facile colbind tutto a $ rootScope , ma è difficile lavorarci su, apportare piccole modifiche, riutilizzare il codice per altre applicazioni o moduli e testare l’applicazione in generale.

MODIFICARE

Recentemente ho dovuto recuperare alcuni elementi dall’API e catturare questi elementi per mostrarli in una determinata vista. Il meccanismo di recupero degli oggetti era in una certa Factory , mentre il meccanismo per formattare e mostrare gli oggetti era in un Controller .

Quindi, ho dovuto emettere un evento in Factory quando gli elementi sono stati recuperati e catturare questo evento nel Controller .

$ modo rootScope

 //Factory $rootScope.$broadcast('refreshItems', items); //Controller $scope.$on('refreshItems', doSomething()); 

Ha funzionato chiaramente ma non mi piaceva molto usare $rootScope e ho anche notato che le prestazioni di quel compito erano piuttosto miserabili.

Poi ho provato a dare un colpo a Postal.js :

Postal.js è un bus di messaggi in memoria – molto liberamente ispirato ad AMQP – scritto in JavaScript. Postal.js viene eseguito nel browser o sul server utilizzando node.js. Prende il familiare paradigma di “eventing-style” (di cui la maggior parte degli sviluppatori di JavaScript è familiare) e lo estende fornendo “broker” e implementazioni di sottoscrittori che sono più sofisticate di quelle che normalmente si trovano nell’emissione / aggregazione di eventi semplici.

Ho provato a utilizzare Postal.js per questo tipo di esigenze e ho scoperto che è molto più veloce dell’utilizzo di $rootScope per questo scopo.

 //Factory $scope.$bus.publish({ channel : 'reloadItems', topic : 'reloadItems' data : items ); //Controller $scope.$bus.subscribe({ channel : 'reloadItems', topic : 'reloadItems', callback : function () { resetAndLoadItems(); } }); 

Spero di esserti stata utile.

Da documenti Angluar : ogni applicazione ha un unico scopo di root. Tutti gli altri ambiti sono ambiti discendenti dell’ambito di base. Gli ambiti forniscono una separazione tra il modello e la vista , tramite un meccanismo per osservare il modello per le modifiche.

Ovviamente questo dipenderà da una questione di opinioni e stile. Tendo a seguire uno stile molto vicino alla Guida Angular Style di John Papa .

In linea con i due, e seguendo una buona strategia di separazione delle preoccupazioni, la mia architettura contiene modelli di fabbrica condivisi attraverso l’applicazione. I miei controllori a loro volta sono tutti vincolati ai servizi che detengono i dati condivisi.

L’utilizzo di $ rootScope come bus eventi globale è esattamente come Angular lo utilizza. Dovresti taggare e fare lo stesso? Non vedo perché no. Ma se lo sei, assicurati che lo scopo sia chiaramente definito e magari usi anche il tuo servizio per registrare eventi sul bus globale degli eventi. In questo modo stai disaccoppiando la tua app da Angular e se decidi di voler cambiare la struttura in cui vive il tuo bus di eventi globale, puoi cambiarla in un unico posto.

Questo è quello che sto suggerendo:

Bus di eventi globali

 // Angular specific: add service to module angular.module('app').factory('globalEventBus', GlobalEventBus); // Angular specific: inject dependencies GlobalEventBus.$inject(['$rootScope']); // Non framework specific. // param: fameworkEventBus will be $rootScope once injected function GlobalEventBus(fameworkEventBus) { var globalEventBus = this; globalEventBus.registerEvent(params...){ fameworkEventBus. } return globalEventBus; } 

Modelli di dati globali

I miei modelli di dati sono intelligenti e tendono a contenere funzioni che forniscono informazioni su se stessi o recuperano / restituiscono dati specifici.

 // Angular specific: add service to module angular.module('app').factory('dataModel', DataModel); function DataModel() { var dataModel= this; dataModel.myData = {}; dataModel.GetSpecificData = funtion(param){ return ... } return dataModel; } 

Il controller

 // Angular specific angular.module('app').controller('MyController', MyController); // Angular specific: inject dependencies to controller MyController.$inject = ['dataModel']; // By convention I use the same parameter name as the service. // It helps me see quickly if my order of injection is correct function MyController(dataModel) { var myController = this; // Bind to the service itself, and NOT to the service data property myController.myData = dataModel; myController.doStuff = function(){ } } 

Ecco un post divertente sull’associazione ai servizi e non sul servizio delle proprietà.

Tutto sumto devi essere il giudice di ciò che funziona meglio per te. Una buona architettura del sistema e un buon stile mi hanno risparmiato innumerevoli ore di risoluzione di problemi completamente evitabili.

Dopo aver lavorato ancora con Angular e più leggendo ho trovato questa regola di base per usare $ rootscope che volevo aggiungere alle altre risposte:

Aggiungi solo proprietà statiche o costanti. Qualsiasi altra cosa che rappresenta uno stato mutevole o un valore mutabile dovrebbe avere una direttiva o un controller corrispondente per gestirlo.