Angular Google Map, lazy loading, second time - angularjs

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.

Related

url/state changes not working after angular.copy called in a factory

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.

Why calling different subscription on the same collection cause error in meteor?

I working on this angular-meteor tutorial step 12
an I have a question in
Stopping a subscription Topic
you can use ctrl+f using "meteorSubscribe"
then the key sentence on that topic is
The reason is that we are calling a different subscription on the same collection inside the partyDetails controller.
the code before correction is
$scope.party = $meteor.object(Parties, $stateParams.partyId).subscribe('parties');
$scope.users = $meteor.collection(Meteor.users, false).subscribe('users');
then after correction
$scope.party = $meteor.object(Parties, $stateParams.partyId);
$scope.users = $meteor.collection(Meteor.users, false).subscribe('users');
$scope.$meteorSubscribe('parties');
I try to run before correction code and nothing(error) show in cmd but it just cause the wrong result as tutorial say
if you navigate to the party details page and then go back, pagination and search will stop working.
Then i got two question
Why no error show on cmd?
Why error from partyDetails controller affect to partiesList controller search and pagination? What is their relation?
EDIT: If you don't cancel a subscription, then if you navigate away and back again you will end up trying to subscribe twice to the same publication, resulting in the error, because subscriptions in meteor last until you end them.
There are two ways to get rid of a subscription with angular-meteor. One you can assign a handle variable to the subscription and then on navigating away from the page you can stop it. Two (the recommended way) is to use $scope.$meteorSubscribe instead of $meteor.subscribe() because it is set up to automatically remove the subscription when the scope is destroyed.
I can't see all of your code to know for sure why you are or are not getting the errors you think you should, hopefully this sheds some light on what is going on in the tutorial.
The very end result would be something like:
$meteor.autorun($scope, function() {
$meteor.subscribe('parties', {
limit: parseInt($scope.perPage),
skip: parseInt(($scope.page - 1) * $scope.perPage),
sort: $scope.sort
}).then(function() {
$scope.partiesCount = $meteor.object(Counts, 'numberOfParties', false);
$scope.parties = $meteor.collcetion(function() {
return Parties.find({}, {
sort: $scope.getReactively('sort');
});
});
});
});
Notice that he's also changing the publish function on the server. It helps to understand if you click the links to show the git diffs.

Google maps not always fully rendering in Ionic

Having trouble with always rendering google maps in my Ionic app. When I first land on a view from a list of items on the previous view, the map always renders in its complete state. However, if I go back to the previous view and tap a different business, or even the same one, it appears as if the map is only rendering 25% of the complete map. I'm having this issue on both the emulator and on my iPhone.
Example
Code
getData.getBusinesses()
.then(function(data) {
// get businesses data from getData factory
})
.then(function(data) {
// get businesses photo from getData factory
})
.then(function(data) {
// get some other business stuff
})
.then(function() {
// get reviews for current business from separate async call in reviews factory
})
.then(function() {
// instantiate our map
var map = new GoogleMap($scope.business.name, $scope.business.addr1, $scope.business.city, $scope.business.state, $scope.business.zip, $scope.business.lat, $scope.business.long);
map.initialize();
})
.then(function() {
// okay, hide loading icon and show view now
},
function(err) {
// log an error if something goes wrong
});
What doesn't make sense to me is that I'm using this exact code for a website equivalent of the app, yet the maps fully load in the browser every time. The maps also fully load when I do an ionic serve and test the app in Chrome. I did also try returning the map and initializing it in a following promise, but to no avail.
I've also tried using angular google maps, but the same issue is occurring. I think I might want to refactor my gmaps.js (where I'm creating the Google Maps function) into a directive, but I don't know if that will actually fix anything (seeing as angular google maps had the same rendering issue).
I don't think the full code is necessary, but if you need to see more let me know.
EDIT
It seems that wrapping my map call in a setTimeout for 100ms always renders the map now. So I guess the new question is, what's the angular way of doing this?
I'm seeing similar issues with ng-map in Ionic. I have a map inside of a tab view and upon switching tabs away from the map view and back again, I would often see the poorly rendered and greyed out map as you describe above. Two things that I did that may help fix your issue:
Try using $state.go('yourStateHere', {}, {reload: true}); to get back to your view. The reload: true seemed to help re-render the map properly when the map was within the tab's template.
After wrapping the map in my own directive, I found the same thing happening again and wasn't able to fix it with the first suggestion. To fix it this time, I started with #Fernando's suggestion and added his suggested $ionicView.enter event to my directive's controller. When that didn't work, I instead added a simple ng-if="vm.displayMap" directive to the <ng-map> directive and added the following code to add it to the DOM on controller activation and remove it from the DOM right before leaving the view.
function controller($scope) {
vm.displayMap = true;
$scope.$on('$ionicView.beforeLeave', function(){
vm.displayMap = false;
});
}
Hope that helps.
don't use setTimeout on this!
You need to understand that the map is conflicting with the container size or something (example: map is loading while ionic animation is running, like swiping).
Once you understand this, you need to set map after view is completely rendered.
Try this on your controller:
$scope.$on('$ionicView.enter', function(){
var map = new GoogleMap($scope.business.name,
$scope.business.addr1, $scope.business.city,
$scope.business.state, $scope.business.zip,
$scope.business.lat, $scope.business.long);
map.initialize();
});

Add "intermediary" page prior to full page load Angular

My problem
I am using Angular to create a Phonegap application. Most of my pages are fairly small and the transition/responsiveness is quick and smooth. However I have one page that is fairly large that I am having an issue with.
The method for changing to this page is straightforward:
<button ng-click="$location.url('/page2')"></button>
When you "tap" the button above it takes about 1-2s to respond and change pages. I have double checked all areas for improvement on this page and determined that the delay is caused by Angular compiling and parsing the DOM of this page prior to changing the page. Please note that I am testing this on a real device so it is not due to emulator speeds.
The question
Is there a way to automatically or manually intercept page changes and put them in a sort of "loading" page so the response to the button click is immediate and page change is visible but the page content loads in a second or 2 later onto this "loading" page.
Its only an issue cause it is very awkward to click something and have nothing happen. I am having a very hard time finding any resources on this matter so if someone can even point me in the right direction to look I would be grateful.
Edit:
A super hacky solution I found was to use an ng-include on wrapper page and delay the include for a little bit.
myBigPageWrapper.html:
<div ng-include="page"></div>
Controller:
$scope.page = '';
setTimeout(function() { $scope.page='/pages/myBigPage.html'; $scope.$apply(); }, 1000);
Then navigate to your wrapper page instead: $location.url('/myBigPageWrapper')
This is obviously not ideal... But I hope this helps clarify what I am attempting to do.
Page2.html
This is the section that causes the page to slow down, commenting this out makes the page load very quickly. There are 13 pages in the "auditPages" array each containing about 50 lines of html mostly containing form input elements. Quite a bit of logic however it runs great once it is loaded. I am not going to include all the pages as it would be overload.
<div class="page-contents">
<form name="auditPageForm">
<div ng-repeat="(pageKey, pageData) in auditPages " ng-show="currentAuditPage.name==pageData.name">
<audit-form page="pageData">
<ng-include src=" 'partials/audit/auditSections/'+pageData.name+'.html'" onload="isFormValid(pageKey)"></ng-include>
</audit-form>
</div>
</form>
</div>
To sum up my comments above:
Your question was:
Is there a way to automatically or manually intercept page changes and
put them in a sort of "loading" page?
A lot of people asks for this question since Angular doesn't seem to provide a nice handling of a loading transition.
Indeed, the possible nicest solution would have been to "play" with the resolve property of angular's module configuration.
As we know, resolve allows to run some logic before the targeted page is rendered, dealing with a promise. The ideal would be to be able to put a loading page on this targeted page, while the resolve code is running.
So some people have nice ideas like this one:
Nice way to handle loading icon while route is changing
He uses $routeChangeStart event, so the loading icon would happen on the SOURCE page.
I use it and it works well.
Also, there is another way: make use of $http interceptor (like #oori answer above), to have a common code allowing to put a loading icon but...I imagine you don't want the same icon on every kind of http request the page does, it's up to you.
Maybe in the future, a solution would come directly associated to the resolve property.
Angular has $httpProvider.responseInterceptors
// Original by zdam: http://jsfiddle.net/zdam/dBR2r/
angular.module('LoadingService', [])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.responseInterceptors.push('myHttpInterceptor');
var spinnerFunction = function (data, headersGetter) {
angular.element(document.getElementById('waiting')).css('display','block');
return data;
};
$httpProvider.defaults.transformRequest.push(spinnerFunction);
}])
// register the interceptor as a service, intercepts ALL angular ajax http calls
.factory('myHttpInterceptor', ['$q','$window', function ($q, $window) {
return function (promise) {
return promise.then(function (response) {
angular.element(document.getElementById('waiting')).css('display','none');
return response;
}, function (response) {
angular.element(document.getElementById('waiting')).css('display','none');
return $q.reject(response);
});
};
}])

Backbone Navigates to Base URL Immediately After Page Load

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.

Resources