Restangular no BaseUrl when do PUT - angularjs

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;
});

Related

Undefined value return by Angular

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).

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;
});

Angularjs $http my second then before first then is done.

I am not sure what I am doing wrong here, but the Report.xls gets downloaded before report.students gets updated.
How can I make it wait for report.students to be updated before Report.xls get downloaded?
Here is my code
`data service function
function getStudentsForExcel() {
var filter = studentFilter;
filter.data.perPage = StudentsModel.data.countTotal;
return $http.post(url + "/summeries", filter.data)
.then(onStudentSummeries)
.catch(onError);
function onStudentSummeries(response) {
return response.data;
}
}`
This function in my controller
`
function tocsv() {
studentData.getStudentsForExcel().then(function(data) {
report.students = data;
}).then(function() {
var blob = new Blob([document.getElementById('tableReport').innerHTML], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
});
saveAs(blob, "Report.xls");
});
}`

Getting the phoneNumber using $cordovaContacts

I'm trying to get all the contacts in the phone using ng-cordova, I success to do that like the following, I create a service in AngularJS:
.factory("ContactManager", function($cordovaContacts) {
return {
getContacts: function() {
var options = {};
options.filter = "";
options.multiple = true;
//get the phone contacts
return $cordovaContacts.find(options);
}
}
})
Also the method find in the ng-cordova is't like the following:
find: function (options) {
var q = $q.defer();
var fields = options.fields || ['id', 'displayName'];
delete options.fields;
navigator.contacts.find(fields, function (results) {
q.resolve(results);
},
function (err) {
q.reject(err);
},
options);
return q.promise;
}
And did the following inside the controller:
ContactManager.getContacts().then(function(result){
$scope.users= result;
}, function(error){
console.log(error);
});
I noticed that in the $scope.users I find the formatted, middleName ..., but I can't find the phoneNumber, how can I get also the phoneNumbers?
If you log the contacts you should see an object with a phoneNumbers array in it.
ContactManager.getContacts().then(function(result){
$scope.users= result;
console.log(result);
...
If you don't it's something else.
I also made a somewhat close mock json of what the return looks like.

How do I do custom model data parsing in backbone.js?

While using backbone to hit an api, I've found that I need to only include some of the data in the response. The webserver is giving me back metadata in addition to data concerning my objects that I don't need.
The following solution works, but doesn't feel right. Is there a standard way of doing this?
var accountsCollection = new AccountsCollection();
accountsCollection.fetch({success : function(collection){
var results = new AccountsCollection();
collection.each(function(item){
results.add(new AccountModel({
id: item.toJSON().result[0].id,
messageText: item.toJSON().messageText,
address1: item.toJSON().result[0].address1,
address2: item.toJSON().result[0].address2
}));
});
onDataHandler(results);
}});
EDIT: This was my final solution based on the accepted answer:
parse: function(response) {
var accounts = [];
_.each(response['result'], function (account) {
accounts.push(account);
});
return accounts;
}
You could try overriding the Backbone.Collection.parse method and do some crazy underscore stuff. No idea if it fits your data..
var keysILike = ['foo', 'bar'];
AccountsCollection.extend({
parse: function(response) {
return _.compact(_.flatten(_.map(response, function (model) {
var tmp = {};
_.each(_.keys(model), function (key) {
if (_.contains(keysILike, key)) tmp[key] = model[key];
})
return tmp;
})));
}
});
With respect to #Sushanth's awesomeness you definitely want to use this solution:
var keysILike = ['foo', 'bar'];
AccountsCollection.extend({
parse: function(response) {
_.each(response, function (model) {
_.each(_.keys(model), function (key) {
if (!_.contains(keysILike, key)) delete model[key]
})
});
return response;
}
});

Resources