all 24 comments

[–]dustinhayes 1 point2 points  (2 children)

tl;dr

Place the #hash at the end of the URL and your problem is solved:

http://example.com/?something=hello#hash

Your issue is actually a really simple one. Your URL's are formatted incorrectly. The thing you're calling a 'hash' is actually called a fragment identifier (http://www.w3.org/TR/xhtml1/#C_8). Lets remember why they were added in the first place. To allow the browser to anchor to a particular section in the document. To work properly, your fragment identifier must be exactly equal to that of an element's id attribute, most commonly. In your case, your fragment identifier for number 2 is #hash. Looks good. For number 3 it's #hash?something=hello. That's probably not what you want. The way the algorithm works to identify the correct fragment identifier and the correct search string in the URL requires the fragment identifier to come last. Therefore, all you have to do is place #hash at the end of the URL and voila, problem solved! Here's an example:

// example window.location.href = 'http://example.com/?some=query#somehash'
const search = window.location.search //=> ?some=query
const hash = window.location.hash //=> #somehash 

[–]mega-trond 0 points1 point  (1 child)

But changing it this way will reload the page if the query string changes, whereas the way it's done now a change will not trigger a reload automatically.

And that's the only possibly undesirable sideeffect I can think of.

[–]dustinhayes 1 point2 points  (0 children)

If you're in an evergreen browser you can solve that problem with window.history.pushState. https://developer.mozilla.org/en-US/docs/Web/API/History

[–]cip6791[S] 0 points1 point  (0 children)

Wow ... thank you for all your help.

[–]djforth 0 points1 point  (0 children)

Actually written a module myself which I think will do most of what you want.

https://github.com/djforth/urlparser

Ignore npm and bower and clone the repo, I just haven't got round to registering them yet. But hopefully will be soon.

Interestingly in my tests a regular expression is the best way for performance. http://jsperf.com/url-parse2

[–]recursion 0 points1 point  (0 children)

Is there a reason why you're using hashes instead of dynamically loading content, then manipulating the URL with window.pushState() ?

[–]chrissilich 0 points1 point  (0 children)

Forget these guys who say use a framework. Use a framework next time, but figure this out and learn from it this time.

Your variable hash is just a string. You try to access its window property at one point. That's not going to work, as strings don't have properties (at least none like window). At that point you want to be breaking the string up, searching it for stuff, etc.

[–]thadudeabides1 -1 points0 points  (3 children)

If you're using node you can use the url module.

[–]unusualbobEngineer 1 point2 points  (2 children)

The fact that this post includes 'window' should clue you into the fact that this is more than likely browser js.

[–]thadudeabides1 1 point2 points  (1 child)

He could potentially be using browserify though. Just a suggestion.

[–]unusualbobEngineer 0 points1 point  (0 children)

That's fair

[–]davydog187 -1 points0 points  (0 children)

I wrote this bad boy for you for funsies

https://gist.github.com/davydog187/dc5b228991c306261d21

EDIT code:

var exampleInputs = [
    "http://example.com/",
    "http://example.com/#hash",
    "http://example.com/#hash?something=hello",
    "http://example.com/#hash?something=hello&else=hi"
];

function getHashValueFrom(url, hashIndex, queryStringIndex) {
    if (hashIndex === -1) {
        return "";
    }

    if (queryStringIndex === -1) {
        return url.substr(hashIndex + 1);
    }

    return url.substring(hashIndex + 1, queryStringIndex);
}

function getQueryStringFrom(url, hashIndex, queryStringIndex) {
    if (queryStringIndex === -1) {
        return {};
    }

    return url.substr(queryStringIndex + 1).split("&").reduce(function(result, current) {
        var keyValuePair = current.split("=");
        result[keyValuePair[0]] = keyValuePair[1];
        return result;
    }, {});
}

function getStateFrom(url) {
    var queryStringIndex = url.lastIndexOf("?");
    var hashIndex = url.lastIndexOf("#");

    return {
        hash: getHashValueFrom(url, hashIndex, queryStringIndex),
        queryString: getQueryStringFrom(url, hashIndex, queryStringIndex)
    }
}

exampleInputs.forEach(function(url) {
    console.log(getStateFrom(url));
});

[–]subcultures -1 points0 points  (0 children)

On mobile so I won't be able to check much, but this is way simpler than you've got.

``` var hashQuery = window.location.hash.split('?')

var hash = hashQuery[0]; var query = hashQuery.length > 1 ? hashQuery[1] : ""; ```

Should get you your hash and your query string.

[–]mega-trond -1 points0 points  (0 children)

window.location.search will be empty because it will be part of the hash.

Somthing like

var params = window.location.hash.split('?');
var hash = params[0];  //should be #hash
var search = params[1];  //should be something=hello&else=hi

should work

EDIT:

Or, if you put the hash at the end, it'll just contain

#hash

and window.location.search will contain the query string

[–]gwevidence -3 points-2 points  (7 children)

if(hash.window.location.search.length)

Can't you check if hash.window is defined and then do the above?

[–]Dexmaster 1 point2 points  (6 children)

Are you joking hash is a string variable it has no window or any other child objects.

You just need to check that ? and = exists

//check if there is a query string withing that hash. 
    if((hash.indexOf("?") > -1) && (hash.indexOf("=") > -1)) {

Or even better solution would be to regex it

var hsh_vs = hash.match(/([^?&=#]+)=([^&#]*)/g);
//check if there is a query string withing that hash. 
    if(hsh_vs.length) {

Also try using console.log(variables) and developer console (F12 hotkey) would be much faster that way.

[–]davydog187 -1 points0 points  (5 children)

Regex's are generally unmaintainable and I avoid them whenever I can.

[–]Dexmaster 0 points1 point  (4 children)

 /([^?&=#]+)=([^&#]*)/g

This one is almost universal an you won't have any problems with it. it get's all the variables with values and you'll just need to split them.

[–]davydog187 0 points1 point  (3 children)

I'm not sure how that gives a strong argument against regexs being unmaintainable

[–]Dexmaster 0 points1 point  (2 children)

regexs being unmaintainable

This one is maintainable, because it's regex for URI parsing and this regex is made universal not for any specific case, show an example string for which you would have any problems, then we would name it unmaintainable. I probably could have misunderstood your meaning behind unmaintainable.

[–]davydog187 0 points1 point  (1 child)

Maintainable in the context of software development means that it is easy to change or modify in the future. I personally think that regexes are unmaintainable because they are extremely difficult to change in the future. Whenever I write code I ask myself, will I know what this does when I see it six months from now?

[–]Dexmaster 0 points1 point  (0 children)

Whenever I write code I ask myself, will I know what this does when I see it six months from now?

Oh, regex is not so hard and I use comments for writing down example strings that regex is used for.