2012-10-17 21 views
147

में विचारों के बीच बदलते समय दायरे का मॉडल बनाए रखें मैं AngularJS सीख रहा हूं। के मैं /View1My1Ctrl, और /view2My2Ctrl का उपयोग कर का उपयोग कर मान लीजिए; जिसे टैब का उपयोग करने के लिए नेविगेट किया जा सकता है जहां प्रत्येक दृश्य का अपना सरल, लेकिन अलग-अलग रूप होता है।AngularJS

मैं कैसे होगा यह सुनिश्चित करें कि मान View1 के रूप में प्रवेश किया रीसेट नहीं कर रहे हैं, जब कोई उपयोगकर्ता पत्ते और फिर View1 रिटर्न?

मेरा मतलब यह है कि पर दूसरी विज़िट कैसे देख सकती है मॉडल के ठीक उसी स्थिति को छोड़ दें जैसा मैंने छोड़ा था?

उत्तर

9

$ रूटस्कोप एक बड़ा वैश्विक चर है, जो एक-एक चीजों या छोटे ऐप्स के लिए ठीक है। यदि आप अपने मॉडल और/या व्यवहार को समाहित करना चाहते हैं (और संभावित रूप से इसे कहीं और पुन: उपयोग करना चाहते हैं तो एक सेवा का उपयोग करें)। ओपी के Google समूह पोस्ट के अलावा, https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion भी देखें।

165

मैंने यह करने के लिए कुछ समय लगाया कि ऐसा करने का सबसे अच्छा तरीका क्या है। मैं राज्य को रखना चाहता था, जब उपयोगकर्ता पृष्ठ छोड़ देता है और फिर पुराने पृष्ठ पर वापस जाने के लिए बैक बटन दबाता है; और न केवल मेरे सभी डेटा को जड़कोप में डालें।

अंतिम परिणाम प्रत्येक नियंत्रक के लिए एक सेवा है। नियंत्रक में, आपके पास केवल फ़ंक्शंस और चर होते हैं जिन पर आप परवाह नहीं करते हैं, अगर उन्हें साफ़ किया जाता है।

नियंत्रक के लिए सेवा निर्भरता इंजेक्शन द्वारा इंजेक्शन दी जाती है। चूंकि सेवाएं सिंगलेट हैं, इसलिए उनका डेटा नियंत्रक में डेटा की तरह नष्ट नहीं होता है।

सेवा में, मेरे पास एक मॉडल है। मॉडल में केवल डेटा है - कोई फ़ंक्शन नहीं -। इस तरह इसे जेएसओएन से आगे बढ़ने के लिए इसे आगे बढ़ाया जा सकता है। मैंने दृढ़ता के लिए एचटीएमएल 5 स्थानीय स्टोरेज का इस्तेमाल किया।

अन्त में मैं window.onbeforeunload और $rootScope.$broadcast('saveState'); इस्तेमाल किया जाने के लिए सभी सेवाओं को पता है कि वे अपने राज्य को बचाने के लिए करना चाहिए, और $rootScope.$broadcast('restoreState') उन्हें अपने राज्य (जब उपयोगकर्ता पृष्ठ छोड़ के लिए इस्तेमाल किया बहाल करने के लिए यह बताने के लिए और करने के लिए वापस जाने के लिए वापस बटन दबाता है क्रमशः पृष्ठ)।

उदाहरण सेवा मेरी userController के लिए userService कहा जाता है:

app.factory('userService', ['$rootScope', function ($rootScope) { 

    var service = { 

     model: { 
      name: '', 
      email: '' 
     }, 

     SaveState: function() { 
      sessionStorage.userService = angular.toJson(service.model); 
     }, 

     RestoreState: function() { 
      service.model = angular.fromJson(sessionStorage.userService); 
     } 
    } 

    $rootScope.$on("savestate", service.SaveState); 
    $rootScope.$on("restorestate", service.RestoreState); 

    return service; 
}]); 

userController उदाहरण

function userCtrl($scope, userService) { 
    $scope.user = userService; 
} 

दृश्य तो यह

<h1>{{user.model.name}}</h1> 
तरह बंधन का उपयोग करता है

और एप्लिकेशन मॉड्यूल में, रन समारोह के भीतर मैं प्रसारण savestate की और restoreState

$rootScope.$on("$routeChangeStart", function (event, next, current) { 
    if (sessionStorage.restorestate == "true") { 
     $rootScope.$broadcast('restorestate'); //let everything know we need to restore state 
     sessionStorage.restorestate = false; 
    } 
}); 

//let everthing know that we need to save state now. 
window.onbeforeunload = function (event) { 
    $rootScope.$broadcast('savestate'); 
}; 

के रूप में मैं इस इस मुद्दे पर आने के लिए कुछ समय लिया उल्लेख संभाल। यह करने का यह एक बहुत ही साफ तरीका है, लेकिन ऐसा कुछ करने के लिए इंजीनियरिंग का एक उचित हिस्सा है जिसे मैं संदिग्ध में विकसित करते समय एक बहुत ही आम मुद्दा मानता हूं।

मुझे आसान दिखना अच्छा लगेगा, लेकिन जब उपयोगकर्ता छोड़ देता है और पेज पर वापस आ जाता है, तब भी राज्य को नियंत्रकों को रखने के लिए साफ तरीके के रूप में। मैं कई दृश्यों के साथ एक स्पा है :

+9

यह बताता है कि पेज रीफ्रेश होने पर डेटा को कैसे बनाए रखना है, मार्ग बदलने पर इसे कैसे बनाए रखना है, इसलिए यह सवाल का जवाब नहीं देता है। इसके अलावा यह उन ऐप्स के लिए काम नहीं करेगा जो मार्गों का उपयोग नहीं करते हैं। इसके अलावा यह नहीं दिखाता है कि 'sessionStorage.restoreState'' सत्य पर सेट किया गया है। पृष्ठ रीफ्रेश होने पर डेटा को बनाए रखने के लिए एक सही समाधान के लिए, [यहां] देखें (http://stackoverflow.com/questions/25428170/angular-restore-scope-from- सत्रस्थान /25430797)। मार्ग बदलते समय लगातार डेटा के लिए, कार्लोस्कार्को के जवाब को देखें। आपको केवल एक सेवा में डेटा रखना है। –

+2

यह विचारों में लगातार रहता है, वैसे ही जैसा कि आप सुझाव देते हैं, इसे एक सेवा में स्टोर करें। दिलचस्प रूप से पर्याप्त है, यह एक पेज पर भी जारी रहता है उसी तरह से आप खिड़की के साथ सुझाव हैं .onbeforeunload। हालांकि मुझे डबल चेक बनाने के लिए धन्यवाद। यह उत्तर एक वर्ष से अधिक पुराना है और यह अभी भी कोणीय के साथ चीजों को करने का सबसे आसान तरीका प्रतीत होता है। – Anton

+0

यहां वापस आने के लिए धन्यवाद, भले ही यह पुराना हो :)। निश्चित रूप से आपके समाधान में दोनों विचार और पृष्ठ शामिल हैं, लेकिन यह नहीं बताता कि कौन सा कोड किस उद्देश्य से कार्य करता है, और [यह पर्याप्त नहीं है कि यह उपयोग योग्य हो सकता है] (http://stackoverflow.com/questions/25428170/angular-restore- गुंजाइश-से-sessionstorage/25,430,797)। मैं केवल पाठकों को [आगे के प्रश्न] से बचने के लिए चेतावनी दे रहा था (http://stackoverflow.com/questions/25428170/angular-restore-scope-from-essionstorage/25430797)। यह अच्छा होगा अगर आपके पास अपने उत्तर को बेहतर बनाने के लिए संपादन करने का समय हो। –

22

एक कुछ सबसे अच्छा अभ्यास

jsfiddle

var myApp = angular.module('myApp',[]); 
myApp.factory('UserService', function() { 
    var userService = {}; 

    userService.name = "HI Atul"; 

    userService.ChangeName = function (value) { 

     userService.name = value; 
    }; 

    return userService; 
}); 

function MyCtrl($scope, UserService) { 
    $scope.name = UserService.name; 
    $scope.updatedname=""; 
    $scope.changeName=function(data){ 
     $scope.updateServiceName(data); 
    } 
    $scope.updateServiceName = function(name){ 
     UserService.ChangeName(name); 
     $scope.name = UserService.name; 
    } 
} 
+0

मुझे इसे पृष्ठ नेविगेशन के बीच भी करना है (पेज रीफ्रेश नहीं)। क्या ये सही है? – FutuToad

+0

मुझे लगता है कि मुझे इस उत्तर को पूरा करने के लिए भाग जोड़ना चाहिए, नियंत्रक नष्ट होने पर 'अपडेट सेवा' को कॉल किया जाना चाहिए - '$ स्कोप। $ ('$ नष्ट', फ़ंक्शन() { console.log (' Ctrl नष्ट हो गया '); $ scope.updateServiceName ($ scope.name); }); ' – Shivendra

6

मैं एक ही समस्या थी के साथ एक जवाब के लिए देर सा लेकिन सिर्फ अद्यतन बेला, यह मैं क्या किया है

var app = angular.module('otisApp', ['chieffancypants.loadingBar', 'ngRoute']); 

app.config(['$routeProvider', function($routeProvider){ 
    $routeProvider.when('/:page', { 
     templateUrl: function(page){return page.page + '.html';}, 
     controller:'otisCtrl' 
    }) 
    .otherwise({redirectTo:'/otis'}); 
}]); 

मैं सभी विचारों के लिए केवल एक ही नियंत्रक जनसंपर्क है, लेकिन,: एक ही पृष्ठ (ajax के बिना) में है, इसलिए इस मॉड्यूल के कोड है oblem सवाल, नियंत्रक हमेशा की तरह, डेटा ताज़ा आदेश इस व्यवहार मैं लोगों के ऊपर क्या सुझाव है और मुझे लगता है कि इस प्रयोजन के लिए एक सेवा बनाया किया से बचने के लिए के रूप में ही है, तो नियंत्रक को इसे पारित इस प्रकार है:

app.factory('otisService', function($http){ 
    var service = {    
     answers:[], 
     ... 

    }   
    return service; 
}); 

app.controller('otisCtrl', ['$scope', '$window', 'otisService', '$routeParams', 
function($scope, $window, otisService, $routeParams){   
    $scope.message = "Hello from page: " + $routeParams.page; 
    $scope.update = function(answer){ 
     otisService.answers.push(answers); 
    }; 
    ... 
}]); 

अब मैं अपने किसी भी विचार से अद्यतन फ़ंक्शन को कॉल कर सकता हूं, मान पास कर सकता हूं और अपना मॉडल अपडेट कर सकता हूं, मुझे दृढ़ता डेटा के लिए html5 एपिस का उपयोग करने की आवश्यकता नहीं है (यह मेरे मामले में है, शायद अन्य मामलों में उपयोग करने के लिए आवश्यक होगा html5 apis स्थानीय स्टोरेज और अन्य सामान की तरह)।

+0

हाँ, एक आकर्षण की तरह काम किया। हमारे डेटा फैक्ट्री को पहले ही कोड किया गया था और मैं कंट्रोलर ए सिंटैक्स का उपयोग कर रहा था, इसलिए मैंने इसे $ स्कोप नियंत्रक को फिर से लिखा है, इसलिए कोणीय इसे नियंत्रित कर सकता है। कार्यान्वयन बहुत सरल था। यह पहला एंजुलर ऐप है जिसे मैं writtng कर रहा हूँ। tks – egidiocs

8

कोणीय वास्तव में बॉक्स से बाहर की तलाश में नहीं प्रदान करता है। क्या मैं पूरा करने के लिए क्या आप के बाद कर रहे हैं करना होगा में उपयोग निम्नलिखित जोड़ें ऑन

UI Router & UI Router Extras

इन दोनों राज्य आधारित रूटिंग और चिपचिपा राज्यों के साथ प्रदान करेगा, आप कर सकते हैं राज्यों और सभी जानकारी के बीच टैब होगा बोलने के लिए "जीवित रहता है" के दायरे के रूप में बचाया जाना चाहिए।

दोनों पर प्रलेखन की जांच करें क्योंकि यह बहुत सीधी आगे है, यूई राउटर एक्स्ट्रा के पास चिपचिपा राज्य कैसे काम करता है इसका एक अच्छा demonstration है।

+0

मैंने दस्तावेज़ पढ़े हैं, लेकिन जब उपयोगकर्ता ब्राउजर बैक बटन पर क्लिक करता है तो फॉर्म इनपुट को संरक्षित करने के तरीके को नहीं मिला। क्या आप मुझे विनिर्देशों के लिए इंगित कर सकते हैं, कृपया? धन्यवाद! – Dalibor

+0

उपयोग के लिए अच्छा नहीं है, माता-पिता को अतिरिक्त टेम्पलेट जोड़ने की आवश्यकता है। – sendreams

1

समाधान है कि उन स्कोप

भीतर अनेक दायरे और कई चर के लिए काम करेंगे यह सेवा एंटोन के जवाब के आधार पर किया गया था, लेकिन अधिक विस्तृत है और अनेक दायरे भर में काम करेंगे और एक से अधिक गुंजाइश चर का चयन की अनुमति देता है एक ही दायरे में। यह प्रत्येक दायरे को इंडेक्स करने के लिए मार्ग पथ का उपयोग करता है, और उसके बाद स्कोप वेरिएबल नाम एक स्तर को गहराई से इंडेक्स करने के लिए उपयोग करता है। उदाहरण

$rootScope.$on('$locationChangeStart', function (event, next, current) { 
    $rootScope.$broadcast('savestate'); 
}); 

window.onbeforeunload = function (event) { 
    $rootScope.$broadcast('savestate'); 
}; 

अपने नियंत्रक में restoreScope सेवा सम्मिलित करें (:

इस कोड के साथ सेवा बनाएँ:

angular.module('restoreScope', []).factory('restoreScope', ['$rootScope', '$route', function ($rootScope, $route) { 

    var getOrRegisterScopeVariable = function (scope, name, defaultValue, storedScope) { 
     if (storedScope[name] == null) { 
      storedScope[name] = defaultValue; 
     } 
     scope[name] = storedScope[name]; 
    } 

    var service = { 

     GetOrRegisterScopeVariables: function (names, defaultValues) { 
      var scope = $route.current.locals.$scope; 
      var storedBaseScope = angular.fromJson(sessionStorage.restoreScope); 
      if (storedBaseScope == null) { 
       storedBaseScope = {}; 
      } 
      // stored scope is indexed by route name 
      var storedScope = storedBaseScope[$route.current.$$route.originalPath]; 
      if (storedScope == null) { 
       storedScope = {}; 
      } 
      if (typeof names === "string") { 
       getOrRegisterScopeVariable(scope, names, defaultValues, storedScope); 
      } else if (Array.isArray(names)) { 
       angular.forEach(names, function (name, i) { 
        getOrRegisterScopeVariable(scope, name, defaultValues[i], storedScope); 
       }); 
      } else { 
       console.error("First argument to GetOrRegisterScopeVariables is not a string or array"); 
      } 
      // save stored scope back off 
      storedBaseScope[$route.current.$$route.originalPath] = storedScope; 
      sessionStorage.restoreScope = angular.toJson(storedBaseScope); 
     }, 

     SaveState: function() { 
      // get current scope 
      var scope = $route.current.locals.$scope; 
      var storedBaseScope = angular.fromJson(sessionStorage.restoreScope); 

      // save off scope based on registered indexes 
      angular.forEach(storedBaseScope[$route.current.$$route.originalPath], function (item, i) { 
       storedBaseScope[$route.current.$$route.originalPath][i] = scope[i]; 
      }); 

      sessionStorage.restoreScope = angular.toJson(storedBaseScope); 
     } 
    } 

    $rootScope.$on("savestate", service.SaveState); 

    return service; 
}]); 

अपने अनुप्रयोग मॉड्यूल में अपने रन समारोह के लिए इस कोड जोड़ें नीचे):

function My1Ctrl($scope, restoreScope) { 
    restoreScope.GetOrRegisterScopeVariables([ 
     // scope variable name(s) 
     'user', 
     'anotherUser' 
    ],[ 
     // default value(s) 
     { name: 'user name', email: '[email protected]' }, 
     { name: 'another user name', email: '[email protected]' } 
    ]); 
} 

उपर्युक्त उदाहरण संग्रहीत मूल्य पर $ scope.user प्रारंभ करेगा, अन्यथा प्रदत्त मान पर डिफ़ॉल्ट होगा और उसे सहेज देगा। यदि पृष्ठ बंद है, ताज़ा किया गया है, या मार्ग बदल दिया गया है, तो सभी पंजीकृत स्कोप चर के वर्तमान मान सहेजे जाएंगे, और अगली बार मार्ग/पृष्ठ का दौरा किया जाएगा।

+0

जब मैंने इसे अपने कोड में जोड़ा तो मुझे एक त्रुटि मिली "TypeError: अपरिभाषित संपत्ति 'लोकल' नहीं पढ़ सकता" मैं इसे कैसे ठीक कर सकता हूं? @brett –

+0

क्या आप अपने मार्गों को संभालने के लिए कोणीय का उपयोग कर रहे हैं? मैं अनुमान लगा रहा हूं कि "नहीं" $$.current अपरिभाषित प्रतीत होता है। –

+0

हां, कोणीय मेरे रूटिंग को संभालने वाला है। । JBenchApp.config ([ '$ routeProvider', '$ locationProvider', समारोह ($ routeProvider, $ locationProvider) { \t $ routeProvider जब ('/ डैशबोर्ड: यहाँ मैं क्या मार्ग में है का एक नमूना है ', { templateUrl:' partials/dashboard.html ', नियंत्रक:' जेबेंचकूट ' }) –

2

सेवाओं का एक विकल्प मूल्य स्टोर का उपयोग करना है।

मेरे ऐप के आधार में मैं इस

var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']); 

agentApp.value('agentMemory', 
    { 
     contextId: '', 
     sessionId: '' 
    } 
); 
... 

और फिर मेरी नियंत्रक में मैं सिर्फ मूल्य की दुकान का संदर्भ गयी। मुझे नहीं लगता कि उपयोगकर्ता ब्राउज़र को बंद कर देता है तो यह चीज़ रखता है।

angular.module('rbAgent') 
.controller('AgentGoalListController', ['agentMemory', '$scope', '$rootScope', 'config', '$state', function(agentMemory, $scope, $rootScope, config, $state){ 

$scope.config = config; 
$scope.contextId = agentMemory.contextId; 
...