How to current (not previous) state on windows popstate
Asked Answered
E

1

8

I am grabbing popstate and need to do various thing based on the current and originalEvent in the history stack. However, I can't figure out how to get the current state for comparison, but originalEvent works. Here's my JS code. The first IF statement throws an exception that e.state.id is not defined...

$(window).on("popstate", function(e) {
        //check and compare current state
        if (e.state.id == 'something') {  // throws an exception
            *do something*
        } else if (e.originalEvent.state !== null) { //previous state exists?
            *do something*
        } else { //no previous state
            *do something*
        }
    });

FYI, the push state is being set as:

history.pushState({id: 'view'}, '', '/view');
Eyelid answered 24/6, 2015 at 15:59 Comment(5)
Why don't you just store it on each popstate?Lyndalynde
I need to get the value of what we are going back FROM, not what we are going back TO...Eyelid
Just to be clear, you know that e.originalEvent isn't part of the history API? It's a reference jQuery provides to the original event data, rather than jQuery's event object. e.originalEvent.state is the data for the current popstate event.Lyndalynde
Yup, event.originalEvent does not at all provide a "from".Anthropomorphic
Same question, formulated more clearly: #36525912.Anthropomorphic
M
1

Extended History Object

This is my source you can see full resource from https://gist.github.com/HasanDelibas/12050fc59d675181ea973d21f882081a


This library contains:

  • history.states -> get state list
  • history.stateIndex -> current state index
  • "historyChange" event -> detect history change (from,to,side="back"|"forward")
  • Important! state must be object at history.pushState( **state**, ...)
(function(){
  let stateSymbol = "__state__index__";
  history.stateIndex =-1;
  history.states=[];
  let pushState = history.pushState;
  function add(data,title,url){
    if(data==null) data={};
    if(typeof data!="object") data={data:data};
    data[stateSymbol] = (history.stateIndex+1);
    history.states.splice(history.stateIndex+1,0,[data,title,url])
    history.states.splice(history.stateIndex+2)
    history.stateIndex++;
  }
  history.pushState =function(data,title,url=null){
    add(data,title,url);
    pushState.bind(history)(data,title,url);
  }
  addEventListener("popstate",function(e){
    var eventObject= {};
    var newStateIndex =  e.state!=null ? e.state[stateSymbol] : -1;
    eventObject.from = history.states[history.stateIndex];
    eventObject.to   = newStateIndex>-1 ? history.states[newStateIndex] : null;
    eventObject.side = history.stateIndex>newStateIndex ? "back" : "forward"; 
    if( newStateIndex > -1 && !(newStateIndex in history.states) ){
      add(history.state,"",window.location.href);
    }
    window.dispatchEvent(new CustomEvent("historyChange", {detail: eventObject} ))
    history.stateIndex = e.state!=null ? e.state[stateSymbol] : -1;
  });
})();

Now you can get all states with history.states object, and detect history change with addEventListener("popstate",function(e))

Using

/**
  * @param e.detail.from [data,title,url]
  * @param e.detail.to   [data,title,url]
  * @param e.detail.side "back" | "forward"
  */
addEventListener("historyChange",function(e){
  var from = e.detail.from; // [ data , title , url ]
  var to   = e.detail.to;   // [ data , title , url ]
  var side = e.detail.side; // "back" | "forward"
  console.log( `You changed history. Side is ${e.detail.side}.\nFrom:${e.detail.from[2]}\nTo:${e.detail.to[2]}`)
})


history.pushState("1", "DENEME-TEST" ,"?1");
history.pushState("2", "DENEME-TEST" ,"?2");
// list of history states
console.log( history.states )
/*
[
  [ {...} ,  "DENEME-TEST" ,"?1" ]
  [ {...} ,  "DENEME-TEST" ,"?2" ]
]
*/
// get history current state index
console.log( history.stateIndex )
/*
1
*/

Murtha answered 22/7, 2020 at 12:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.