Undefined value return by Angular - angularjs

I have a Angular function to retrieve taxi annonces and i need to calculate the distance between the user connected et the author of annonce then I have something like this :
In my HTML :
<main class="main list_page" ng-controller="taxiRechercheCtrl" ng-init="loadRecherche()">
In Angular :
myApp.controller("taxiRechercheCtrl", ['$scope','$http','$location', 'TaxiService', 'UserService', function($scope, $http, $location, TaxiService, UserService){
$scope.loadRecherche = function(){
UserService.getPosition().then(function(position){
TaxiService.find($scope.recherche).then(function(response){
$scope.annonces = response.annonces;
for(var i=0;i<$scope.annonces.length;i++){
$scope.annonces[i].Distance = my calculate distance
}
}, function(err){
console.log(err);
});
}, function(err){
console.log(err);
});
};
$scope.calculeDistanceGoogle = function(origin, destination){
var origin1 = new google.maps.LatLng(origin.Latitude, origin.Longitude);
var destination1 = new google.maps.LatLng(destination.latitude, destination.longitude);
var args = {
origins: [origin1],
destinations: [destination1],
travelMode: 'DRIVING'
};
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(args, function(response, status) {
var elt = response.rows[0].elements[0];
$scope.distanceTxt = elt.distance.text;
});
return $scope.distanceTxt;
}
}
In $scope.annonces[i].Distance = my calculate distance, I want the distance value returned by my calculeDistanceGoogle function.
I tried :
$scope.calculeDistanceGoogle($scope.annonces[i].Ville, response.position).then(function(response){
console.log(response);
}, function(err){
console.log(err);
});
but I have the error : $scope.calculeDistanceGoogle(...).then is not a function.
I tried use $scope.distanceTxt variable, I try directly :
var myposition = $scope.calculeDistanceGoogle($scope.annonces[i].Ville, response.position);

The $scope.calculeDistanceGoogle(...) is not a function that return a Promise, so you can't call .then(...) clause.
And then, this code is wrong:
service.getDistanceMatrix(args, function(response, status) {
var elt = response.rows[0].elements[0];
$scope.distanceTxt = elt.distance.text;
});
return $scope.distanceTxt;
because probabily that service is asynchronous.
My suggestion is return a promise with the value of distanceTxt as data (add error if present on the promise too).

Related

Angular Datatables Server Side Search Request is Returning Empty Object

Problem
I'm using server side pagination and search, pagination is working fine but when i enter some text into search box which automatically sends request to server, it immediately returns back with empty object but its also bringing "recordsTotal" for pagination to work. which means one query is executing but the second one is NOT.
API Test using postman
I've tested the API USING POSTMAN and what ever search string i send, it brings me back the appropriate results but when i send it via search box (FROM FRONT END) it just simply won't work
Here is my Controller Code:
I've intentionally commented "fnCallback(records)" but I'm consoling "console.log(result)" the result array returned from back-end API
angular.module('withServerSide', ['datatables'])
.controller('withServerSideController', function WithPromiseController($scope, DTOptionsBuilder, DTColumnBuilder, filterService)
{
$scope.dtColumns = [
DTColumnBuilder.newColumn('es_officer_id', 'Id').withOption('searchable', true),
DTColumnBuilder.newColumn('es_officer_name', 'Name').withOption('searchable', true)
];
$scope.dtOptions = DTOptionsBuilder
.newOptions()
.withFnServerData(serverData)
.withDataProp('data') // tried data aswell
.withOption('processing', true)
.withOption('serverSide', true)
.withOption('paging', true)
.withOption('stateSave', true)
.withOption('lengthMenu', [5, 10, 20, 30, 50, 100 ])
.withDisplayLength(5)
.withPaginationType('full_numbers')
.withButtons([
'colvis',
'print',
'excel'
])
function serverData(sSource, aoData, fnCallback, oSettings)
{
//All the parameters you need is in the aoData variable
var draw = aoData[0].value;
var limit = aoData[4].value; // item per page
var order = aoData[2].value[0].dir; // order by asc or desc
var start = aoData[3].value; // start from
var search = aoData[5].value; // search string
//Then just call your service to get the records from server side
filterService.execute(start, limit, order, search).then(function(result)
{
console.log(result);
// var records = {
// 'draw': draw,
// 'recordsTotal': result.data.recordsTotal,
// 'recordsFiltered': result.data.recordsFiltered,
// 'data': result.data.es_officers
// };
// // console.log(records);
// fnCallback(records);
});
}
});
Here is Code for filterService factory:
angular.module('Main_Module').factory('filterService', filterService);
filterService.$inject = ['$q', '$http']
function filterService($q, $http)
{
var service = {
execute: execute
};
return service;
// Start-From LIMIT ASC | DESC
function execute(start, limit, order, search)
{
// console.log(start, length, order);
var defered = $q.defer();
//Make a request to backend api and then call defered.resolve(result);
// /SELECTSpecific/:TableName/:Start/:Length/:Order
$http({
url : 'http://localhost:3000/api/SELECTQPromise/es_officers/'+start+'/'+limit+'/'+order+'/'+search,
method: 'POST'
})
.then(function(result)
{
defered.resolve(result);
})
.catch(function(err)
{
defered.reject(err);
});
return defered.promise;
}
};
Back-end Code:
router.post('/SELECTQPromise/:TableName/:start/:limit/:order/:search', function(req, res)
{
function doQuery1()
{
var query1 = "SELECT COUNT(*) AS recordsTotal FROM " + req.params.TableName;
var defered = Q.defer();
connection.query(query1, function(err, result) //defered.makeNodeResolver()
{
if(err)
{
defered.reject(err);
}
else
{
defered.resolve(result[0]);
}
});
return defered.promise;
}
function doQuery3()
{
var query3 = "SELECT es_officer_id, es_officer_name FROM "+req.params.TableName+
" WHERE es_officer_name LIKE '%"+req.params.search+"%'"+
" ORDER BY es_officer_id "+req.params.order;//+" LIMIT "+req.params.start+", "+req.params.limit;
var defered = Q.defer();
connection.query(query3, function(err, result) //defered.makeNodeResolver());
{
if(err)
{
defered.reject(err);
}
else
{
defered.resolve(result);
}
});
return defered.promise;
}
Q.all([doQuery1(), doQuery3()]).then(function(result)
{
// res.json({"Error" : false, "Message" : "success", [req.params.TableName] : result[1], "recordsTotal": result[0].recordsTotal, "recordsFiltered": result[0].recordsTotal});
res.send(result);
})
.catch(function(err)
{
res.send(err);
});
});
I've figured out the problem and I'm mentioned it here in case if anyone face the same problem in the future.
on this line I thought I'm assigning value to search where as in actual .value itself.
var search = aoData[5].value;
the search string is with the .value object, the correct would be
var search = aoData[5].value.value;
Now its working absolutely fine.

Second jsonp http get request - using $q gives 404 error despite GET showing 200

I've found a couple of similar posts to this, but the answers (which boil down to putting callback=JSONP_CALLBACK into the get request) aren't working for me. Using that in the request generates an immediate 404 error, while using callback=angular.callbacks._0 at least lets the first request return a successful response. The problem is that using the very same request function with the very same params a second time to refresh the data or get the next 20 objects, returns a 404 error even though the actual get returns a 200 and the data can be seen in chrome tools.
I'm, new to using $q deferred promises, so I'm hoping that the issue has something to do with that not allowing enough time for a response before executing the reject. I'm attaching the code, which involves the Yelp API as did the other couple of posts I found on this issue. The most closely related is: (Subsequent JSONP requests give status 404 despite GET status 200), but there's another which uses the same callback string I'm using (Yelp API and AngularJS).
This particular project is for an ionic mobile app that gets coffee shops based on users geolocation.
Here's the code for the service (secret stuff removed):
var app = angular.module('caffeine.services', []);
app.service("YelpService", function ($q, $http, $cordovaGeolocation, $ionicPopup) {
function randomString(length, chars) {
var result = '';
for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))];
return result;
};
var method = 'GET';
var url = 'http://api.yelp.com/v2/search';
var consumerSecret = ''; //Consumer Secret
var tokenSecret = ''; //Token Secret
var self = {
'page': 1,
'isLoading': false,
'hasMore': true,
'results': [],
'ranStr': randomString(32, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'),
'timeStamp':new Date().getTime(),
'lat': 51.544440,
'lon': -0.022974,
'term': 'coffee',
'oauthConKey': '', //Consumer Key
'oauthToken': '', //Token
'oauthSigMeth': 'HMAC-SHA1',
'refresh': function () {
self.page = 1;
self.isLoading = false;
self.hasMore = true;
self.results = [];
return self.load();
},
'next': function () {
self.page += 1;
return self.load();
},
'load': function () {
self.isLoading = true;
var deferred = $q.defer();
ionic.Platform.ready(function() {
$cordovaGeolocation
.getCurrentPosition({timeout:10000, enableHighAccuracy:false})
.then(function(position){
self.lat = position.coords.latitude;
self.lon = position.coords.longitude;
console.log('latlong = '+self.lat+','+self.lon);
var params = {
callback: 'angular.callbacks._0',
page: self.page,
ll: self.lat+','+self.lon,
term: self.term,
oauth_consumer_key: self.oauthConKey, //Consumer Key
oauth_token: self.oauthToken, //Token
oauth_signature_method: self.oauthSigMeth,
oauth_timestamp: self.timeStamp,
//new Date().getTime(),
oauth_nonce: self.ranStr
};
var signature = oauthSignature.generate(method, url, params, consumerSecret, tokenSecret, { encodeSignature: false});
params['oauth_signature'] = signature;
console.log('url ='+url);
console.log('params.ll = '+params.ll);
$http.jsonp(url, {params: params}).success(function (callback) {
self.isLoading = false;
console.log(callback.businesses);
if (callback.businesses.length == 0) {
self.hasMore = false;
} else {
angular.forEach(callback.businesses, function (business) {
self.results.push(business);
});
}
self.isLoading = false;
deferred.resolve(callback.businesses);
})
.error( function (callback, status, headers, config) {
self.isLoading = false;
console.error('data not received');
console.error('data: '+callback);
console.error('status: '+status);
console.error('headers: '+headers);
console.error('congig: '+config);
deferred.reject(callback);
});
}, function(err) {
console.error('Error getting position');
console.error(err);
$ionicPopup.alert({
'title': 'Please turn on geolocation',
'template': 'It looks like you have geolocation turned off. Please turn on geolocation in your app settings to use this app.'
});
})
});
return deferred.promise;
}
};
self.load();
return self;
});

Factory in AngularJS/Ionic return different value

I am developing an app in Ionic and I am brand new on all this angular js, cordova and ionic.
The thing is that I am trying to create a service that ask to an API for a response. I make it work perfectly in the controller:
$scope.search = function(icao) {
console.log(icao);
$scope.forecastfuture = [];
$http.get("http://api.wunderground.com/............../UK/"+icao+".json")
.success(function(data, status, headers, config){
console.log(data);
console.log(typeof data);
for(i=0; i<36; i++){
var day = data.hourly_forecast[i].FCTTIME.pretty;
var maxtemp = data.hourly_forecast[i].temp.metric;
var mintemp = data.hourly_forecast[i].dewpoint.metric;
var feelslike = data.hourly_forecast[i].feelslike.metric;
var humidity = data.hourly_forecast[i].humidity;
var windspd = data.hourly_forecast[i].wspd.metric;
var winddir = data.hourly_forecast[i].wdir.dir;
var sky = data.hourly_forecast[i].condition;
var precip = data.hourly_forecast[i].qpf.metric;
var snow = data.hourly_forecast[i].snow.metric;
var icon = data.hourly_forecast[i].icon_url;
console.log(day);
console.log(maxtemp);
$scope.forecastfuture.push({
id: i,
day: day,
maxtemp: maxtemp,
mintemp: mintemp,
feelslike: feelslike,
humidity: humidity,
windspd: windspd,
winddir: winddir,
sky: sky,
precip: precip,
snow: snow,
icon: icon});
}
})
.error(function(data, status, headers, config){
console.log(data);
});
}
But now I am learning to create a Factory, because I will need this to be used more than once, but the return in the factory is different than in the controller you can see a log image here:
The first one is the factory return, as you can see the data is different than the second part, that is the response in the controller directly, the http.get.
My problem is that when I try to read anything from the factory it throw an error all the time. Here you have the code for the factory:
.factory('ForecastService', function(CurrentPosition, $http){
var wresp;
return{
getForecastResponse: function(country, city){
return $http.get("http://api.wunderground.com/api/.........../q/"+country+"/"+city+".json")
.success(function(data, status, headers, config){
console.log(data);
wresp = data;
return wresp;
});
},
getDay: function(i){
var day = wresp.hourly_forecast[i].FCTTIME.pretty;
return day;
},
getMaxTemp: function(i){
var maxtemp = wresp.hourly_forecast[i].temp.metric;
return maxtemp;
},
getMinTemp: function(i){
var mintemp = wresp.hourly_forecast[i].dewpoint.metric;
return mintempo;
},
getFeelsLike: function(i){
var feels = wresp.hourly_forecast[i].feelslike.metric;
return feels;
},
getHumidity: function(i){
var humidity = wresp.hourly_forecast[i].humidity;
return humidity;
},
getWindSpd: function(i){
var windspd = wresp.hourly_forecast[i].wspd.metric;
return windspd;
},
getWinDir: function(i){
var windir = wresp.hourly_forecast[i].wdir.dir;
return windir;
},
getSky: function(i){
var sky = wresp.hourly_forecast[i].condition;
return sky;
},
getPrecip: function(i){
var precip = wresp.hourly_forecast[i].qpf.metric;
return precip;
},
getSnow: function(i){
var snow = wresp.hourly_forecast[i].snow.metric;
return snow;
},
getIcon: function(i){
var icon = wresp.hourly_forecast[i].icon_url;
return icon;
}
}
})
and here the code in the controller to call this factory:
var forec = ForecastService.getForecastResponse("UK", "London");
var day = forec.getDay(1);
You are correct to return the $http call's result:
getForecastResponse: function(country, city){
return $http.get(...)
}
This returns a promise to which you'd need to do .then (or .success for $http-specific promise, but I don't recommend it), because the response is not yet received by the time you attempted to do .getDay.
So, in the controller:
ForecastService
.getForecastResponse("UK", "London")
.then(function(){
var day = ForecastService.getDay(1);
});

Restangular no BaseUrl when do PUT

i'm using Restangular and trying to PUT some data but it seems to lose the BaseUrl.
In the config function i define the BaseUrl for Restangular and others Restangular fields.
Constants.restangularBaseUrl is http://192.168.1.100/api/
RestangularProvider.setBaseUrl(Constants.restangularBaseUrl)
.setRestangularFields({
selfLink: '_links.self.href',
id: '_id',
etag: '_etag'
})
.addResponseInterceptor(function(data, operation, what, url, response, deferred){
if (operation === 'getList') {
var result = data._items;
result._meta = data._meta;
result._links = data._links;
return result;
}
return data;
});
Then i have some models like this:
(function(){
angular.module('models.ebayItems', ['services.constants', 'restangular'])
.service('EbayItems', ['Constants', 'Restangular', function (Constants, Restangular) {
Restangular.extendModel('ebayitems', function(model) {
model.toggleMonitor = function(){
var item = this;
Restangular.one('ebayitems', this._id).patch({active: this.active}, '', {'If-Match': this._etag})
.then(function(data){
item._etag = data._etag;
}, function(error){
console.log('error', error);
});
};
return model;
});
var ebayItems = Restangular.all('ebayitems');
var ebayItemsOneSearch = function(_id){
return ebayItems.customGETLIST('', {where: {searchId: _id}});
};
return {
items: ebayItems,
oneSearch: ebayItemsOneSearch
};
}])
})();
Now when i try to do a put request with an item based on that model:
item.put()
it uses the wrong url, i mean it loses the BaseUrl, so instead of putting at:
http://192.168.1.100/api/ebayitems/12345
it puts at
http://192.168.1.100/ebayitems/12345
resulting in a 404 error.
Why?
What am i doing wrong?
Any help really appreciated.
Thank you
The problem was that setting a selfLink field that was a relative url from the API backend it overrides the BaseUrl.
Removing that field from the config function it worked.
RestangularProvider.setBaseUrl(Constants.restangularBaseUrl)
.setRestangularFields({
id: '_id',
etag: '_etag'
})
.addResponseInterceptor(function(data, operation, what, url, response, deferred){
if (operation === 'getList') {
var result = data._items;
result._meta = data._meta;
result._links = data._links;
return result;
}
return data;
});

is invoking a service into another service in angular

I need to save data and then I need to dispaly the changes immediately afterwards.
That's why I Have a
updateSaisine which allows me to update data
getOneSaisine which allows me get the data and display them:
Which is the more correct way and for which reasons ?
Should I write:
$scope.saveSaisine = function() {
saisineSrv.updateSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).
then(
function() {
$scope.errorMessages = [];
if ($scope.currentSaisine.idMotif) {
toaster.pop('success', 'Réponse', 'Success');
angular.element('#modalSaisine').modal('hide');
saisineSrv.getOneSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).then(function(response) {
$scope.currentSaisine.dateModif = response.dateModif;
});
},
function error(response) {
$scope.errorMessages = response.data;
toaster.pop('error', 'Réponse', 'We have a problem');
}
);
};
OR
$scope.saveSaisine = function() {
saisineSrv.updateSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).
then(
function() {
$scope.errorMessages = [];
if ($scope.currentSaisine.idMotif) {
toaster.pop('success', 'Réponse', 'Success');
angular.element('#modalSaisine').modal('hide');
},
function error(response) {
$scope.errorMessages = response.data;
toaster.pop('error', 'Réponse', 'We have a problem');
}
);
saisineSrv.getOneSaisine($scope.currentSaisine.idSaisine, $scope.currentSaisine).then(function(response) {
$scope.currentSaisine.dateModif = response.dateModif;
});
};
the first option is a correct way how you should refresh your data because these services are asynchronous thus in the second example you may don't get fresh data (the getOneSaisine can finish before updateSaisine).

Resources