Wait for function calculation to finish, then launch filter


#1

This might bbe more of a JS question.
I have an ng-repeat which displays list of restaurant.
Those are displayed thanks to a custom function which rank them by distance from the user. Because list can be extensive, performance are rather bad, and user have to wait 15-25 sec before seing list. I have tried to add a limitTo filter (first 20 values), with a Loadmore(). Works fine BUT, restaurant are sorted out randomly, it looks distance calculation had not time to be performed. Then when hitting the load button, sorting by distance is fine.
Anyone has an idea of how to arrange this, which is I guess - to first make the calculation, THEN “launch” display ?
Thanks,

Here is my controller.js :

// VENUELIST CONTROLLER
.controller('venuelistController', function ($scope, $rootScope, venuesFactory, position, GreatCircle) {
    "use strict";
    $scope.venueList = venuesFactory.getVenues(); //call to restaurant factory
    $scope.position = position;
    $scope.distanceTo = function(venue) { // call special function to calculate distance btw user and restaurant
	var distance = GreatCircle.distance( venue.long,venue.lat, position.longitude, position.latitude)
		venue.distance = distance;
		distance = distance.toFixed(1);
	return distance;
	
	};
	$scope.totalDisplayed = 20; // implementing a load more capability
	$scope.loadMore = function () {
		$scope.totalDisplayed += 20;  
	};

})	

and my html:

<ion-list>
	<span class="list_intro_text"> {{venueList.length}} Restaurants and Food venues in Paris, sorted by distance</span>
    <ion-item  bindonce  ng-repeat= "venue in venueList | orderBy: 'distance' | limitTo:totalDisplayed " href="#"> <!--  | selectedRestaurantType:selection -->  
		<article class="item_frame">
			<div class="marker_left_container">
				<img  class="venue_rest_marker" ng-src="{{venue.icon}}">	
				<span class="venu_type_text">{{venue.venueType}}</span>
				<span class="distance_from_user_rest"> {{distanceTo(venue)}} km</span>
				<span class="distance_from_user_rest2">from current location</span>
				<a browse-to="https://www.google.com/maps/dir//{{venue.lat}},{{venue.long}}/">
					<img src="img/get_direction_v7.png" class="Gmap_dir_icon">
				</a>
			</div>
			<div class="restaurant_details_container">
				<h1 class="restaurant_name_inlist">{{venue.Name}}</h1>
				<span class="restaurant_detail_inlist2">{{venue.subCuisine}}<br> {{venue.subsubCuisine}}</span>
				<span class="restaurant_address">{{venue.address}}, <br> </span>
				<span class="restaurant_address">{{venue.cp}}, {{venue.city}} <br><br></span>
			</div>
		</article><!--main article frame 1 -->		
    </ion-item>	
</ion-list>
<button class="button button-outline button-stable custom_button_lau" ng-click="loadMore()">Load more</button>	

#2

Use $q promises or Ecmascript promises.


#3

Actually ignore my previous post. :slight_smile:

You can create an empry array and then do forEach and add new property with distanceTo to it, when forEach is done, then assign it to scope variable?


#4

ok ! but how would you do that? I am still not very “fluent” with Angular and forEach !


#5

Maybe something like that?

var venueList = venuesFactory.getVenues()

angular.forEach(venueList, function(venue) {
  venue.distance = distanceTo(venue)
});

$scope.venuelist = venueList;

#6

You can also add this code to route resolve to make sure it is done before view is loaded


#7

hummm… I have some trouble embedding the .forEach in the existing code without breaking everything !


#8

If you are able to post simple plunkr I can help you debug there…


#9

That would be awesome ! this is a plunker i used in thew past that I just amended a minute ago with the load more possibility . In this one, we talk about restaurant whereas before it was about “venues” but code is otherwise 100% the same (this is because list was too long, so I did split in two categories).


#10

#11

Hey ! looks like plnkr is working like expecting and should now integrate easily in my environment, thanks a lot for your help :smile:


#12

Instead of ng-repeat, use Ionic’s collection-repeat directive which uses virtual DOM. Your performance issues will be gone and you won’t have to find workarounds for bad performance


#13

thanks @djett , I am not very keen on collection -repeat though, as it looks like all item need similar height


#14

@yurinondual
I do not know why, I struggle implementing the plunker into my project. It looks like the functions are just not run.

Eg: on my console, when I try to enter the view where the list is to be displayed (which remains blank) the console prints :

whereas on Plunker, I can see the full log

I know it is difficult to figure without the full code, but you might have an idea ?
thanks,
Laurent


#15

show me your routes definition in app.js, i suspect you forgot to add route resolve. Please read about Angular route resolve or ui-router route resolve


#16

hi and thanks @yurinondual, sorry for late reply, was out of town for the wkend. Here is my app.js. Will check documents now .

 angular.module('wmapp', ['ionic', 'wmapp.controllers',  'wmapp.factory_dishes', 'wmapp.factory_stories',    'wmapp.factory_restaurants', 'wmapp.factory_venues', 
  'pasvaz.bindonce', 'greatCircles', 'ngSanitize'])
.run(function ($ionicPlatform) {
    "use strict";
    $ionicPlatform.ready(function () {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins.Keyboard) {
            cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
        }
        if (window.StatusBar) {
        // org.apache.cordova.statusbar required
            StatusBar.styleDefault();
        }
    });
})

.config(function ($stateProvider, $urlRouterProvider) {
    "use strict";
    $stateProvider


        .state('wmapp', { 
            url: "/wmapp",
            abstract: true,
            cache: false,
            templateUrl: "templates/pages/wm_main.html",
            controller: 'wmAppController'
        })
		
        .state('wmapp.dishList', { 
            url: "/dishList",
            cache: false,
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/dishList.html",
                    controller: 'DishListController'
                }
            }
        })
		
         .state('wmapp.dish', {
            url: "/dishList/:itemid",
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/dish.html",
                    controller: 'DishController'
                }
            }
        })
		
        .state('wmapp.dishTypeList', { 
            url: "/dishTypeList",
            cache: false,
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/wm_main.html",
                    controller: 'dishTypeListController'
                }
            }
        })
		
        .state('wmapp.restaurantTypeList', {
            url: "/restaurantTypeList",
            cache: false,
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/wm_main.html",
                    controller: 'restaurantTypeListController'
                }
            }
        })			
		
        .state('wmapp.storyList', { 
            url: "/storyList",
            cache: false,
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/storyList.html",
                    controller: 'storyListController'
                }
            }
        })

        .state('wmapp.story', {
            url: "/storyList/:itemid",
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/story.html",
                    controller: 'storyController'
                }
            }
        })
	
         .state('wmapp.restaurantList', {
            url: "/restaurantList",
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/restaurantList.html",
                    controller: 'restaurantlistController',
					    resolve: {
						position: function($q, positionService) {
						  deferred = $q.defer();
						  
						  positionService.then(function(position){
							console.log(position, "hhihih")
							deferred.resolve(position)
						  })
						  return deferred.promise
						}
					  } 
                }
            }
        })
		
         .state('wmapp.venueList', { 
            url: "/venueList",
            views: {
                'menuContent': {
                    templateUrl: "templates/pages/venueList.html",
                    controller: 'venuelistController'
					
                }
            }
        })
		
        .state('wmapp.search', { //WMAPP-CHILD 
            url: "/search",
            views: {
                'menuContent': {
                    templateUrl: "templates/search.html",
                    controller: 'searchController'
                }
            }
        })


    // if none of the above states are matched, use this as the fallback
    $urlRouterProvider.otherwise('/wmapp/dishList');
});

#17

Hmm maybe when navigating to ‘wmapp.venueList’ make sure that view with name=“menuContent” is available in html


#18

nope something still does not work… :frowning: I had put here the seperate files as is ; if you want to have a look at what I have exactly in my app.
Please note that to facilitate testing with what you provided earlier, I had tried to apply function to Restaurant and NOT venues.


#20

It’s all messed up a bit :smiley:

Why do you need ng-controller in html? you are already doing it in your app.js. It’s hard to say where the problem is without seeing all other templates/views


#21

yeah I know ! I guess I really need to dive much more in AngularJS and understand things . Here is what I’ve done, I created a new branch on git, so you can see the whole project and maybe have a clue at waht is happening :smile:

here it is : https://github.com/celiostat/Whichmeal_Ionic/tree/loadmore