The Parable of the Lost State
- Hello ... - Aah
!
- Well, why are you?
- I am afraid of you!
- What is it?
- You always humiliate me ...
- Heh, okay, I won’t.
- True?
- Doo, do you want some candy with an ajax?
- Of course!
- Come on Tada, fly to us in St. Petersburg. Here is a list of flights for which there are tickets sorted by price: rasp.yandex.ru/search?cityFrom=St . Petersburg&cityTo=Moscow
- Um ... something you lied to uncle - there are generally all flights from Moscow to St. Petersburg, sorted by time of departure.
“Um ... really, it didn't work out well ... but do you know why?”
- Ne?
- Because the state of the application does not affect the uri. Therefore, each time you go to this page from bookmarks, you will have to reinstall filtering and sorting.
- Bloo, what to do?
- Resign yourself, for as a visitor you can’t do anything already.
- And if I were a developer?
- Then you could go along the REST path and make the application state completely dependent on uri.
- But then there will be a reload of the page.
- And you only change the hash-part of the page.
“But how do I know if uri has changed?”
- There are libraries for this.
- What if the state of my application is a multidimensional structure?
- Use Hiqus .
- Oh, how complicated it is ...
- Why is it so complicated? See:
- And how to change the state?
- Yes, elementary:
- A wash?
- Yes, also not a problem:
- It seems nothing complicated.
- Namely. Catch Libu and blow at all times in St. Petersburg, otherwise they will eat all the tasty:
!
- Well, why are you?
- I am afraid of you!
- What is it?
- You always humiliate me ...
- Heh, okay, I won’t.
- True?
- Doo, do you want some candy with an ajax?
- Of course!
- Come on Tada, fly to us in St. Petersburg. Here is a list of flights for which there are tickets sorted by price: rasp.yandex.ru/search?cityFrom=St . Petersburg&cityTo=Moscow
- Um ... something you lied to uncle - there are generally all flights from Moscow to St. Petersburg, sorted by time of departure.
“Um ... really, it didn't work out well ... but do you know why?”
- Ne?
- Because the state of the application does not affect the uri. Therefore, each time you go to this page from bookmarks, you will have to reinstall filtering and sorting.
- Bloo, what to do?
- Resign yourself, for as a visitor you can’t do anything already.
- And if I were a developer?
- Then you could go along the REST path and make the application state completely dependent on uri.
- But then there will be a reload of the page.
- And you only change the hash-part of the page.
“But how do I know if uri has changed?”
- There are libraries for this.
- What if the state of my application is a multidimensional structure?
- Use Hiqus .
- Oh, how complicated it is ...
- Why is it so complicated? See:
HashState.listen( function(){ // вешаем обработчик изменения хэша
console.log( 'state changed to: ' + HashState ) // дампим всё состояние
console.log( 'filters: ' + HashState.sub( 'filters' ) ) // дампим лишь состояние фильтров
console.log // выводим состояние сортировки
( 'order by: '
+ HashState.get( 'order', 'by' )
+ ' '
+ ( HashState.get( 'order', 'reverse' ) ? 'desc' : 'asc' )
)
})
- And how to change the state?
- Yes, elementary:
HashState.put( 'order:by:cost' )
HashState.put( 'order', 'reverse', true )
HashState.put( 'filters', { type: 'airplane', free: true } )
- A wash?
- Yes, also not a problem:
HashState( '' ) // стираем вообще всё
HashState.put( 'filters', '' ) // стираем лишь состояние фильтров
- It seems nothing complicated.
- Namely. Catch Libu and blow at all times in St. Petersburg, otherwise they will eat all the tasty:
var HashState= new function(){
Version: 1
Description: 'stores data in hash part of uri'
License: 'public domain'
Implementation:
var handlers= []
var latency= 25
var timer= 0
var hrefLast= ''
var dataLast= null
var data= null
var has= function( list, item ){
for( var i= list.length - 1; i >= 0; --i ) if( list[i] === item ) return true
return false
}
var drop= function( list, item ){
for( var i= list.length - 1; i >= 0; --i ) if( list[i] === item ) list.splice( i, 1 )
}
var listen= function( handler ){
if( has( handlers, handler ) ) return
handlers.push( handler )
schedule()
}
var forget= function( handler ){
drop( handlers, handler )
if( !handlers.length ) freeze()
}
var freeze= function(){
timer= clearTimeout( timer )
}
var schedule= function(){
freeze()
timer= setTimeout( update, latency )
}
var update= function(){
var href= document.location.href
if( href !== hrefLast ){
data= Hiqus( href.replace( /^[^#]*#?/, '' ) )
if( dataLast+'' != data )
for( var i= 0, len= handlers.length; i < len; ++i )
handlers[i].call()
hrefLast= href
dataLast= data
}
if( timer ) schedule()
}
var change= function( data ){
document.location= '#' + data
}
var HashState= function(){
if( !arguments.length ) return Hiqus( data )
change( data= Hiqus.apply( null, arguments ) )
return HashState
}
HashState.prototype= function(){
this.listen= function( handler ){
listen( handler )
return this
}
this.forget= function( handler ){
forget( handler )
return this
}
this.revive= function(){
schedule()
return this
}
this.freeze= function(){
freeze()
return this
}
this.put= function(){
HashState( data.put.apply( data, arguments ) )
return this
}
this.get= function(){
return data.get.apply( data, arguments )
}
this.sub= function(){
return data.sub.apply( data, arguments )
}
this.toString= function(){
return ''+HashState()
}
return this
}.apply( HashState )
update()
Export: return HashState
Usage:
HashState.listen( function(){ // observe changing
console.log( 'state changed to: ' + HashState ) // all state
console.log( 'filters: ' + HashState.sub( 'filters' ) ) // sub state
console.log
( 'order by: '
+ HashState.get( 'order', 'by' ) // one value
+ ' '
+ ( HashState.get( 'order', 'reverse' ) ? 'desc' : 'asc' )
)
})
HashState( '' ) // clear all
// add parameters
HashState.put( 'order:by:cost' )
HashState.put( 'order', 'reverse', true )
HashState.put( 'filters', { type: 'airplane', free: true } )
HashState.put( 'filters', '' )
}