I'm having a headache with Backbone router in Safari
I have this piece of code:
app.navigate("ask/" + encodedSearchKey,true);
and in my router:
var AppRouter = Backbone.Router.extend({
routes:{
"":"main",
"ask/*encodedSearchKey":"askSearch",
},
askSearch:function(){
...
},
...
});
app = new AppRouter();
Backbone.history.start();
In chrome, it works as expected, the URL gets routed and the askSearch function gets called once
however, in Safari, the askSearch function actually gets executed twice
and when I tried
app.navigate("ask/" + encodedSearchKey,false);
In chrome the askSearch function was not called as expected, but the Safari it actually gets called once
I have run through the debugger and am pretty sure the app.navigate line always gets called once only, and there is nothing else that could fire the askSearch function except the router itself
now I know I can fix this by detecting browser type, but I did not find any similar problems online, it seems that people do not have this issue, am I doing something very wrong here?
I think I've just run across the same issue and found a solution... Safari seems to strip the string from the url for vanity purposes, this then re-triggers the router causing the view to rendered again but lacking the query string data.
The solution I used was fairly simple in the router:
myView: function () {
if (window.location.search.length) {
myView.render();
} else {
return false;
}
}
This stops the 2nd render from proceeding. Although this os only really applicable if you only ever want to render that view with a query string.
The navigate function's second argument is not a boolean but an option object:
app.navigate("ask/" + encodedSearchKey, {
trigger: true
});
in Firefox is the url is not encoded the rout will fire twice, some times...
Related
I'm at my wits end on this one, so any help is greatly appreciated!
I've been making an angular/node/mysql app for the past few weeks and came across this issue. I have a database running mysql that stores a list of users and their information. I created an API to provide the front-end with access to user data for login and all that. The flow is as follows:
User enters new state where info on them needs to be preloaded:
.state('info', {
url: '/info',
templateUrl: 'views/info.html',
controller: 'InfoController',
resolve: {
postPromise: ['user', function(user) {
return user.loadInfo();
}]
The code is run in the user factory so that data is fetched before the page loads:
app.factory('user', ['$http', 'auth', function($http, auth) {
var user = {};
user.loadInfo = function() {
var userId = auth.currentUser();
return $http.get('/users/' + userId).success(function(data) {
angular.copy(data, user);
});
};
return user;
}]);
The page loads fine the first time. Then I navigate somewhere else via $state.go('home') or something, and when I try to return to the same page (/info) it sometimes doesn't work. What happens is I enter in the new url, and the browser basically ignores it and just shows the url of my current page.
Start at localhost:8080/#/home
Type in localhost:8080/#/info and go there
Works fine first time. Navigate to localhost:8080/#/home
Now at localhost:8080/#/home
Type in localhost:8080/#/info, and the browser ignores it, just displaying localhost:8080/#/home
I've tried commenting out angular.copy, and that seems to fix the issue, but I still need to copy the data over that I fetch from the server (which does successfully get transferred).
So my primary question is: Is there an alternative to angular.copy that I can use that will work here? I still find it weird that it is used in all the examples but is causing this issue here.
Secondary question: If angular.copy is the way to go, have any of you seen this issue and have a guess at what's causing it? Does something look off in what I'm doing?
Bonus Info: I don't know how quite to describe this, but sometimes if I wait long enough before going back to the problem url, it works... I notice that a call is made to the server right as I'm typing in the problem url (before even hitting enter) and when that happens, it seems work. It's intermittent though, and stops any $state.go() calls from working to that problem url if they are called through a button click.
Alright, I got the answer for this one and it's pretty dumb. "user" is an object inside of the factory and "loadInfo" is a function attached to user. When I did the angular.copy(), data from the server overwrote the loadInfo function so I couldn't use it again...
So yeah, that's solved.
I'm using angular-ui.github.io/angular-google-maps/
I use the recommended lazy loading technique, I have this in my app.js:
.config(function(uiGmapGoogleMapApiProvider) {
uiGmapGoogleMapApiProvider.configure({
// key: 'your api key',
v: '3.20' //defaults to latest 3.X anyhow
//libraries: 'weather,geometry,visualization'
});
})
And at some point in my controller, I execute this:
var uiGmapGoogleMapApiTimer = $timeout(function() {
reject("uiGmapGoogleMapApi didn't respond after 10 seconds.");
}, 5000);
console.log('DUDE.01');
uiGmapGoogleMapApi.then(function(maps) {
console.log('DUDE.02');
$timeout.cancel(uiGmapGoogleMapApiTimer);
geocoder = new google.maps.Geocoder();
resolve(geocoder);
}, function(err) {
console.log('DUDE.03');
});
So, when I'm offline, the timer will kick in, and I send the user back to the login page. (Originally I simply exit the app. It works in android, but in iOS it doesnt work, it's in fact forbidden by Apple).
So... that's why now I'm sending it back to login page.
Now, in the login page, I reactivate my wifi.... and once I'm back in the page that (is supposed to) show the map.... it breaks. The success handler of uiGmapGoogleMapApi.then never gets called. (Dude.01 gets printed, but Dude.02 nor Dude.03 get printed).
So... that page (wrongly) thinks that the device is still disconnected.
I suppose it's because the loading of google map javascripts is only done once (during load -- that´s why if I close my app, and return back, things will run just fine).
So... it's not really lazy loading (?). Or... if it's lazy loading, it doesn't seem to support scenarios like... try loading it the second time (if the first time failed because of connectivity).
Is anyone familiar enough with the source code of angular-ui.github.io/angular-google-maps/ to suggest what's the solution for this problem?
I looked at the logs I put in the library's code... I came to the conclusion: I need way to get line 183 to be re-executed on the second time I call uiGmapGoogleMapApi.then ... Currently it doesn't. It only gets called the first, when I start my app, and having internet connection since the beginning.
And based on what I understand from this doc on "provider", I need the uiGmapGoogleMapApi to be reinstantiated (right before) the second time I try to use it.
https://docs.angularjs.org/api/auto/service/$provide
Is that right? How?
Looks like I'm battling against provider caching here. Because I use dependency injection in my controller to get reference to uiGmapGoogleMapApi. (I have .controller('myctrl', function(uiGmapGoogleMapApi) {...})
what I might need is:
.controller('myctrl', function() {
var uiGmapGoogleMapApi = $injector.get('uiGmapGoogleMapApi');
//or something along that line maybe
})
I just tried it, still doesn't work.
Please help.
Thanks,
Raka
Well, my "solution" is: instead of going to login page, I simply refresh the app., by setting the current url of the window object to index.html.
Recently I've stumbled upon a very strange code in production that is seemingly using the fact that under some conditions Angular may fire the $locationChangeStart event upon the initial page load. Moreover the next parameter value will be equal to the current value. That seems very odd to me.
I didn't find any relevant documentation for that but here is the fiddle that shows such a situation http://jsfiddle.net/tJSPt/327/
Probably the only difference is that in production we are using the manual Angular bootstrap.
Can anyone explain or point to the trustful sources of information on why is that event triggered upon the page load? Is that something we have to expect or that is just the particularity of the current Angular implementation or our way of using it?
I have experienced this recently but the reason it happened was because I'm using ui-router and the controllerAs syntax. Perhaps you are too?
I stumbled upon this link that helped me out: History should not be changed until after route resolvers have completed
I listened to the $locationChangeStart broadcast but it hit the breakpoint when I entered the state instead of when exciting.
I fixed mine by doing the following:
I listened to $stateChangeStart instead.
I had to move the code above var vm = this;
Here's my code look like after:
// ...
$scope.$on('$stateChangeStart', function (event) {
if (vm.myForm!= null && vm.myForm.$dirty) {
if (!confirm("Are you sure you want to leave this page?")) {
event.preventDefault();
}
}
});
var vm = this;
// vm.xxx = xxxx; .etc ...
I've been facing this issue with Backbone routing and figured I'd spent enough time investigating:
There are two urls at play here: / and /post/:id. The / page has links to various posts via /post/:id. When I click the post link, the post page loads, but backbone immediately changes the url to /. Not only does this look bad, it also triggers route handlers at the wrong time. I'm not doing anything special... here's my code:
PostRouter = Backbone.Router.extend({
routes : {
"" : "doHome"
},
initialize : function() {
},
doHome : function() {
// do some stuff before navigating
window.location = "/";
}
})
...
var router = new PostRouter();
Backbone.history.start({ pushState: Modernizr.history });
Again, the doHome function is called immediately after the post page loads. Clearly this causes the site to navigate back to the home page. I can obviously remove that call to window.location to prevent that, but the url still gets updated to the root url, which isn't acceptable.
Thanks in advance!
UPDATE 1:
If I go directly to "localhost:808/post/:id" the url immediately changes to "localhost:8080/". However, if I do this exact same thing in private browser window, this behavior is not observed.
UPDATE 2:
Given what I found in update 1, I went crazy and started from scratch: I cleared 4 weeks of browsing history (sigh), stopped my local server and cleaned up all persistent sessions and redeployed my app. Alas, it worked! That said, I am not listing this as a solution as it doesn't help explain what exactly is going on and how to solve it. Additionally, it leaves me concerned about this happening to users of my site. I'd have no way to tell that this was happening and, even if I did, I couldn't tell them how to fix it on their end (clearing 4 weeks of browser history is not an option!). Can anyone shed some light on what might have been going on?
why don't you try to add
console.log(Backbone.history.handlers);
at the end to see, how your rout is added to Backbone.history. This might shed some light.
I have the following backbone.js controller:
App.Controllers.PlanMembers = Backbone.Controller.extend({
routes: {
"message/:messageType": "sendMessage",
"": "index"
},
sendMessage: function (messageType) {
alert(messageType);
},
index: function () {
alert('should not get here');
}
});
I want the index to action to be executed when the page loads for the first time which it does, I also have another route which is sent to the sendMessage action and requests are routed fine from links like the one below:
<a class="sms" href="#message/sms" ><img src="/img/buttons/transmit_blue.gif" /></a>
The problem is that after it executes the sendMessage action, it then goes onto fire the index action again which is not what I require.
Can anyone tell me how to ensure that only the sendMessage Route is fired?
It turns out this is a known issue
This fixed the problem.
I honestly thought I was going insane!
The code that you have added works for me, but I don't know if there is something else in your code that could be causing this. Are you perhaps routing to this action from a view based upon the receipt of a DOM event? If so, the absence of a preventDefault statement can sometimes cause this sort of double-rendering (routing) behavior. So perhaps add some additional context/detail to your question.