Backbone navigate triggers twice in Firefox

2019-06-17 07:01发布

Trying to use Backbone's navigate property.

 this.navigate("week/" + companyName + "/" + employeeNo + "/" + weekEnd, { trigger: true, replace: false });

The code above is executed once.

It hits this:

routes: {
    "week/:companyName/:employeeNo/:weekEnd": "getWeek"
},

And then this function gets hit twice:

getWeek: function (companyName, employeeNo, weekEnd) {
    console.log('getWeek:', companyName, employeeNo, weekEnd);
 }

It is logged twice in Firefox, only once in IE and Chrome.

What's the issue here? I originally didn't even have trigger set to true, and Firefox ignored that and still triggered the URL.

3条回答
甜甜的少女心
2楼-- · 2019-06-17 07:38

Question may be old, but for me this was still relevant. Encoding the url wasn't enough in my case. I replaced the GetHash() function in Backbone with:

getHash: function (t) { 
    var e = (t || this).location.href.match(/#(.*)$/);
    return match ? this.decodeFragment(match[1]) : '';
}
查看更多
Viruses.
3楼-- · 2019-06-17 07:48

I had a similar issue recently with Firefox doing two server calls after a Backbone.navigate. In my case it was because we had not encoded the string. Does your company name have any characters which should be encoded?

You could try:

this.navigate("week/" + escape(companyName) + "/" + employeeNo + "/" + weekEnd, { trigger: true, replace: false });
查看更多
做自己的国王
4楼-- · 2019-06-17 07:53

Stepping in as I've run into the same issue and got to the underlying problem here.

As everyone mentioned before, the problem comes from URL encoding. Now as to why the issue only appears in Firefox...

Let's start by summarizing quickly how the routes are called when the hash changes. There are 3 key functions here:

  • loadUrl: this function is the one that will call your route handler.
  • navigate: this is the function used to change the route manually. If the trigger flag is set to true, the function will call loadUrl.
  • checkUrl: this function is set as callback for the onhashchange event on the window object (when it's available of course). It also runs loadUrl on certain conditions.

Now, we're getting to the interesting part.

When you run navigate, Backbone will cache the fragment you navigated to. The hash changing, checkUrl will also be called. This function will then check if the cached hash equals the current one, so as not to execute loadUrl if you called navigate before, because it would mean it has already been called. To make that comparison, checkUrl gets the current hash with the function getFragment, which uses getHash. Here is getHash's code:

getHash: function(window) {
  var match = (window || this).location.href.match(/#(.*)$/);
  return match ? match[1] : '';
},

And you got your problem. location.href is URI-encoded in firefox, but is not in chrome. So if you navigated to another hash (with or without the trigger flag), in firefox, Backbone will cache the unencoded version of your hash, and then compare it with the encoded version. If your hash contained a should-be-encoded character, the result of the comparison will be negative, and Backbone will execute the route handler it should not execute.

As per the solution, well, folks said it before, your URIs should be encoded.

查看更多
登录 后发表回答