ध्यान दें
उत्तर के बदलावों का उपयोग $window.history.back()करने वाले सभी उत्तर , प्रश्न का एक महत्वपूर्ण हिस्सा याद करते हैं: आवेदन की स्थिति को सही स्थिति में कैसे पुनर्स्थापित करना है क्योंकि इतिहास कूदता है (पीछे / आगे / ताज़ा)। ये ध्यान रखते हुए; कृपया, पर पढ़ें।
हाँ, ब्राउज़र को वापस / फॉरवर्ड (इतिहास) करना संभव है और शुद्ध ui-routerस्टेट-मशीन को चलाने के दौरान रिफ्रेश करना संभव है, लेकिन इसमें कुछ करने में समय लगता है।
आपको कई घटकों की आवश्यकता है:
अनोखा यूआरएल । जब आप url बदलते हैं, तो ब्राउज़र केवल बैक / फॉरवर्ड बटन को सक्षम करता है, इसलिए आपको प्रति यूआरएल स्टेट में एक अद्वितीय यूआरएल उत्पन्न करना होगा। हालांकि इन url में किसी भी राज्य की जानकारी शामिल नहीं है।
एक सत्र सेवा । प्रत्येक उत्पन्न url को एक विशेष स्थिति में सहसंबद्ध किया जाता है, ताकि आपको अपने url-state जोड़े को संग्रहीत करने के तरीके की आवश्यकता हो ताकि आप अपने कोणीय ऐप को वापस / अग्रेषित या ताज़ा क्लिक द्वारा पुनः आरंभ करने के बाद राज्य की जानकारी प्राप्त कर सकें।
एक राज्य का इतिहास । यूआई-राउटर का एक सरल शब्दकोष अद्वितीय url द्वारा कुंजीबद्ध है। यदि आप एचटीएमएल 5 पर भरोसा कर सकते हैं तो आप एचटीएमएल 5 हिस्ट्री एपीआई का उपयोग कर सकते हैं , लेकिन यदि, मेरी तरह, तो आप इसे कोड की कुछ पंक्तियों में स्वयं लागू नहीं कर सकते हैं (नीचे देखें)।
एक स्थान सेवा । अंत में, आपको अपने कोड द्वारा आंतरिक रूप से ट्रिगर किए गए दोनों यूआई-राउटर राज्य परिवर्तनों को प्रबंधित करने में सक्षम होना चाहिए, और सामान्य ब्राउज़र यूआरएल परिवर्तन आमतौर पर ब्राउज़र बटन पर क्लिक करने या ब्राउज़र बार में सामान टाइप करने से ट्रिगर होते हैं। यह सब थोड़ा मुश्किल हो सकता है क्योंकि यह उलझन में होना आसान है कि क्या ट्रिगर हुआ।
यहाँ इन आवश्यकताओं में से प्रत्येक का मेरा कार्यान्वयन है। मैंने सब कुछ तीन सेवाओं में बांधा है:
सत्र सेवा
class SessionService
setStorage:(key, value) ->
json = if value is undefined then null else JSON.stringify value
sessionStorage.setItem key, json
getStorage:(key)->
JSON.parse sessionStorage.getItem key
clear: ->
@setStorage(key, null) for key of sessionStorage
stateHistory:(value=null) ->
@accessor 'stateHistory', value
accessor:(name, value)->
return @getStorage name unless value?
@setStorage name, value
angular
.module 'app.Services'
.service 'sessionService', SessionService
यह जावास्क्रिप्ट sessionStorageऑब्जेक्ट के लिए एक आवरण है । मैंने यहाँ स्पष्टता के लिए इसे काटा है। इसकी पूरी व्याख्या के लिए कृपया देखें: मैं एक AngularJS सिंगल पेज एप्लिकेशन के साथ ताज़ा पृष्ठ को कैसे संभालूँ
राज्य का इतिहास सेवा
class StateHistoryService
@$inject:['sessionService']
constructor:(@sessionService) ->
set:(key, state)->
history = @sessionService.stateHistory() ? {}
history[key] = state
@sessionService.stateHistory history
get:(key)->
@sessionService.stateHistory()?[key]
angular
.module 'app.Services'
.service 'stateHistoryService', StateHistoryService
StateHistoryServiceभंडारण और उत्पन्न, अद्वितीय यूआरएल द्वारा keyed ऐतिहासिक राज्यों की बहाली के बाद दिखता है। शब्दकोश शैली वस्तु के लिए यह वास्तव में सिर्फ एक सुविधा आवरण है।
राज्य स्थान सेवा
class StateLocationService
preventCall:[]
@$inject:['$location','$state', 'stateHistoryService']
constructor:(@location, @state, @stateHistoryService) ->
locationChange: ->
return if @preventCall.pop('locationChange')?
entry = @stateHistoryService.get @location.url()
return unless entry?
@preventCall.push 'stateChange'
@state.go entry.name, entry.params, {location:false}
stateChange: ->
return if @preventCall.pop('stateChange')?
entry = {name: @state.current.name, params: @state.params}
url = "/#{@state.params.subscriptionUrl}/#{Math.guid().substr(0,8)}"
@stateHistoryService.set url, entry
@preventCall.push 'locationChange'
@location.url url
angular
.module 'app.Services'
.service 'stateLocationService', StateLocationService
StateLocationServiceदो घटनाओं संभालती है:
स्थान परिवर्तन । यह तब कहा जाता है जब ब्राउज़र स्थान बदल जाता है, आमतौर पर जब पीछे / आगे / ताज़ा बटन दबाया जाता है या जब ऐप पहली बार शुरू होता है या जब उपयोगकर्ता एक यूआरएल में टाइप करता है। यदि वर्तमान स्थान के लिए कोई राज्य .url मौजूद है, StateHistoryServiceतो इसका उपयोग यूआई-राउटर के माध्यम से राज्य को पुनर्स्थापित करने के लिए किया जाता है $state.go।
राज्य-परिवर्तन । यह तब कहा जाता है जब आप आंतरिक रूप से राज्य को स्थानांतरित करते हैं। वर्तमान राज्य का नाम और पाराम StateHistoryServiceएक जनरेट किए गए url द्वारा कुंजी में संग्रहीत किए जाते हैं । यह उत्पन्न यूआरएल कुछ भी आप चाहते हैं, यह मानव पठनीय तरीके से राज्य की पहचान कर सकता है या नहीं हो सकता है। मेरे मामले में मैं एक स्टेटम प्लस (एक गाइड से प्राप्त अंकों के एक यादृच्छिक रूप से उत्पन्न अनुक्रम का उपयोग कर रहा हूं) (गाइड जनरेटर स्निपेट के लिए पैर देखें)। उत्पन्न यूआरएल को ब्राउज़र बार में प्रदर्शित किया जाता है और, महत्वपूर्ण रूप से, ब्राउज़र के आंतरिक इतिहास स्टैक का उपयोग करके जोड़ा जाता है @location.url url। इसका ब्राउज़र के इतिहास स्टैक में url जोड़ना जो आगे / पीछे बटन को सक्षम करता है।
इस तकनीक के साथ बड़ी समस्या यह है कि विधि @location.url urlमें कॉल stateChangeकरने से $locationChangeSuccessघटना शुरू हो जाएगी और इसलिए locationChangeविधि को कॉल करना होगा । समान रूप से कॉल करने @state.goसे घटना और इस विधि locationChangeको ट्रिगर किया जाएगा । यह बहुत भ्रामक हो जाता है और ब्राउज़र इतिहास को समाप्त नहीं करता है।$stateChangeSuccessstateChange
समाधान बहुत सरल है। आप preventCallसरणी को एक स्टैक ( popऔर push) के रूप में उपयोग किया जा रहा है देख सकते हैं । प्रत्येक बार विधियों में से एक को कहा जाता है, यह दूसरी विधि को केवल एक समय-काल कहा जाता है। यह तकनीक $ घटनाओं के सही ट्रिगर के साथ हस्तक्षेप नहीं करती है और सब कुछ सीधे रखती है।
अब हमें केवल इतना करना है HistoryServiceकि राज्य के परिवर्तनकारी जीवन-चक्र में उचित समय पर विधियों को कॉल करें । यह .runइस तरह से AngularJS Apps विधि में किया जाता है :
कोणीय app.run
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
एक गाइड जनरेट करें
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
इस सब के साथ, आगे / पीछे बटन और ताज़ा बटन सभी अपेक्षित रूप से काम करते हैं।