Angularjs, passaggio dell'ambito tra le rotte


87

Ho una situazione con un modulo che si estende su più pagine (potrebbe non essere l'ideale, ma è così). Mi piacerebbe avere uno scopo per l'intero modulo che viene compilato man mano che procedi, in modo che se l'utente va avanti e indietro tra i passaggi è facile ricordare lo stato.

Quindi devo fare, in molto pseudo-codice:

  1. Impostato $scope.val = <Some dynamic data>
  2. Fare clic su un collegamento ed essere indirizzati a un nuovo modello (probabilmente con lo stesso controller).
  3. $scope.val dovrebbe essere ancora lo stesso valore che era nell'ultima pagina.

In qualche modo, la persistenza dei dati per l'ambito è il modo giusto per farlo o c'è qualche altro modo? Puoi persino creare un controller che abbia un ambito persistente tra le rotte, ad eccezione del salvataggio in un database, ovviamente.


Proprio come un'aggiunta a ganaraj: qui trovi un bel post sul blog con uno screencast su come far comunicare diversi controller. Ci sono anche un paio di utili jsfiddles con cui giocare. onehungrymind.com/angularjs-communicating-between-controllers Spero che aiuti.
F Lekschas

Risposte:


138

Devi utilizzare un servizio poiché un servizio persisterà per tutta la vita dell'app.

Supponiamo che tu voglia salvare i dati relativi a un utente

Ecco come definisci il servizio:

app.factory("user",function(){
        return {};
});

Nel tuo primo controller:

app.controller( "RegistrationPage1Controller",function($scope,user){
    $scope.user = user;
    // and then set values on the object
    $scope.user.firstname = "John";
    $scope.user.secondname = "Smith";
});

app.controller( "RegistrationSecondPageController",function($scope,user){
        $scope.user = user;
        // and then set values on the object
        $scope.user.address = "1, Mars";

    });

6
Ahhh! L'ho provato prima ma non sono riuscito a farlo funzionare perché ho usato lo stesso controller per entrambe le rotte, quindi ad ogni nuova rotta i valori predefiniti sovrascriverebbero quelli che ho inserito nella pagina precedente. Con due controller, o senza valori predefiniti, questo non accade più. Grazie!
Erik Honn

1
Che cosa riguarda Value Recipe docs.angularjs.org/guide/providers , come se myApp.value('clientId', 'a12345654321x');fosse persistente anche tra le rotte?
The Bndr

@TheBndr: Dovrebbe essere. I valori sono solo una forma speciale di servizi per come la intendo io.
Robert Koritnik

3
I servizi non mantengono i dati se ricarichi la pagina ... Quindi, se sei nella pagina 4 del tuo modulo e ricarichi quella pagina, perderai tutti i dati inseriti.
danielrvt

1
Bella risposta! Come punto a margine, una guida di stile per coloro che accettano questa risposta - servizi che non sono essi stessi costruttori (cioè usati come nuovi XX) dovrebbero essere chiamati cammello minuscolo: github.com/mgechev/angularjs-style-guide .
Matt Byrne

9

Il servizio funzionerà, ma un modo logico per farlo utilizzando solo ambiti e controller ordinari è impostare i controller e gli elementi in modo che riflettano la struttura del modello. In particolare, è necessario un elemento padre e un controller che stabiliscano un ambito padre. Le singole pagine del modulo dovrebbero risiedere in una vista che è un figlio per il genitore. L'ambito padre persiste anche se la visualizzazione figlio viene aggiornata.

Presumo che tu stia utilizzando ui-router in modo da poter avere viste con nome annidate. Quindi in pseudo-codice:

<div ng-controller="WizardController">
  <div name="stepView" ui-view/>
</div>

Quindi WizardController definisce le variabili di ambito che si desidera preservare nei passaggi del modulo multipagina (a cui mi riferisco come "procedura guidata"). Quindi i tuoi percorsi verranno aggiornati stepViewsolo. Ogni passaggio può avere i propri modelli, controller e ambiti, ma i loro ambiti vengono persi da una pagina all'altra. Ma gli ambiti in WizardController vengono mantenuti in tutte le pagine.

Per aggiornare gli ambiti di WizardController dai controller figlio, è necessario utilizzare la sintassi $scope.$parent.myProp = 'value'o definire una funzione setMyPropsu WizardController per ogni variabile di ambito. Altrimenti, se provi a impostare le variabili di ambito padre direttamente dai controller figlio, finirai per creare una nuova variabile di ambito sul figlio stesso, oscurando la variabile padre.

È un po 'difficile da spiegare e mi scuso per la mancanza di un esempio completo. Fondamentalmente si desidera un controller padre che stabilisca un ambito padre, che verrà preservato in tutte le pagine del modulo.


1
Questo funzionerebbe con ui-router sì (ed è un modo abbastanza carino per progettare una pagina come quella), ma non fuori dagli schemi. Fuori dagli schemi il metodo di servizio è la strada da percorrere.
Erik Honn

1
Giusto per chiarire, le proprietà dell'ambito padre verranno sempre ereditate dall'ambito figlio. Tuttavia, se si desidera impostare una proprietà dell'ambito padre dall'ambito figlio, è necessario accedervi sull'ambito padre, altrimenti si crea una nuova proprietà con lo stesso nome sull'ambito figlio. L'impostazione di una proprietà dell'ambito padre può essere eseguita andando:$scope.$parent.myProp = 'hello world';
mbursill

1
Questo è un approccio molto più gradevole rispetto all'utilizzo di un servizio. I servizi sono singleton, quindi qualsiasi stato definito è globale per l'applicazione. Se l'utente esce dalla procedura guidata a metà, quindi la riavvia, ci sarà uno stato residuo nel servizio dell'esecuzione precedente, a meno che non si assicuri di pulire correttamente il servizio in ogni punto di uscita, ma questo può diventare facilmente un notevole mal di testa da manutenzione!
Dan King,

Molto più entusiasta di questa risposta
Kurai Bankusu

I servizi sono la prima cosa che ti viene in mente se non stai utilizzando Angular UI Router. Se si utilizza il router UI, tuttavia, ha risoluzioni nidificate che possono mantenere le informazioni tra le viste nidificate. Penso che sarebbe un approccio più pulito rispetto al tentativo di accedere all'ambito genitore. medium.com/opinionated-angularjs/…
losmescaleros

5

I dati possono essere trasmessi tra i controllori in due modi

  1. $rootScope
  2. Modello

L'esempio seguente mostra il passaggio di valori utilizzando il modello

app.js

angular.module('testApp')
  .controller('Controller', Controller)
  .controller('ControllerTwo', ControllerTwo)
  .factory('SharedService', SharedService);

SharedService.js

function SharedService($rootScope){

 return{
    objA: "value1",
    objB: "value2"
  }
}

// Modifica il valore nel controller A

Controller.js

function Controller($scope, SharedService){

 $scope.SharedService = SharedService;

 $scope.SharedService.objA = "value1 modified";
}

// Accede al valore in controllertwo

ControllerTwo.js

function ControllerTwo($scope, SharedService){

 $scope.SharedService = SharedService;

 console.log("$scope.SharedService.objA"+$scope.SharedService.objA); // Prints "value1 modified"
}

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.