I have this factory:
angular.module('core.actor').factory('Actor', ['$resource',
function ($resource) {
return $resource('api/actor/:actorId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true
},
update: {
method: 'PUT'
}
});
}
]);
And this is part of my paging function:
if (self.pk == "-6" && self.searchTerm == undefined) {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit
})
} else if (self.pk == "-6") {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit,
search: self.searchTerm
})
} else if (self.searchTerm == undefined) {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit,
pk: self.pk.toString()
})
} else {
self.actorsToAdd = Actor.query({
offset: pageOffset,
limit: pageLimit,
search: self.searchTerm,
pk: self.pk.toString()
})
}
It changes the GET request generated by Actor depending on certain conditions. I'm looking for a way to parametrize this function so I would be able to replace 'Actor' with a variable.
Something along the lines of:
pageType = Movie;
var page = function (pageType){
self.itemsToAdd = pageType.query({
offset: pageOffset,
limit: pageLimit
})
}
Is it possible? If so, how?
This is how I do it, rather than passing individual parameters into the query, pass in a object, which contains your query parameters.
angular.module('core.actor').factory('Actor', ['$resource',
function ($resource) {
return $resource('api/actor/:actorId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true,
params: { queryParams: '#_queryParams' }
},
update: {
method: 'PUT'
}
});
}
]);
so your call to it looks like this
Actor.query({ queryParams: {
offset: pageOffset,
limit: pageLimit,
pk: self.pk.toString()
}})
Then on the server I look at which values are contained in my (json parsed) params, in order to construct the appropriate query on the database.
After your latest comment, is this the kind of thing you're looking for?
angular.module('core.actor').factory('Api', ['$resource',
function ($resource) {
return {
actor: $resource('api/actor/:actorId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true,
params: {queryParams: '#_queryParams'}
},
update: {
method: 'PUT'
}
}),
movie: $resource('api/move/:moveId/', {}, {
query: {
method: 'GET',
isArray: true,
cache: true,
params: {queryParams: '#_queryParams'}
},
update: {
method: 'PUT'
}
})
};
}
]);
You could then call either Api.movie.query() or Api.actor.query()
For completeness, heres how my server side code looks when building my query.
var constructUserQuery = function (queryParams) {
var query = { $or: [], $and: [] };
if (queryParams.name) {
query.$and.push({ displayName: { $regex: queryParams.name, $options: 'i'} });
}
if (queryParams.client) {
query.$or.push({ client: mongoose.Types.ObjectId(queryParams.client) });
}
if (queryParams.roles) {
query.$or.push({ roles: { $in: queryParams.roles }});
}
// Ignore the current user, if it's supplied
if (queryParams.user) {
query.$and.push({ _id: { $ne: queryParams.user._id }});
}
// Clean up any empty arrays
if (query.$or.length === 0) {
delete query.$or;
}
if (query.$and.length === 0) {
delete query.$and;
}
return query;
};
Obviously this is specific to my case but you get the idea. This is the only place where I have any if statements.
Related
I'm using this library
https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.full.js">
I know there are a lot of examples out there and I've tried them all most recent:
var $client_id = $("#client_id").select2({
dropdownParent: $('#categoryForm'),
ajax: {
quietMillis: 300,
url: apiPath,
xhrFields: {
withCredentials: true
},
crossDomain: true,
type: "GET",
data: function (params) {
var queryParameters = {
search: params.term
}
return queryParameters;
},
processResults: function (data) {
return {
results: $.map(data.data, function (item) {
return {
text: item.client_name,
id: item.client_id
}
})
};
}
}
});
$client_id.val(6).trigger('change');
As you can see at the bottom I'm trying to select the value using the (valid) ID. I have been successfull using this method:
var option = new Option(data.customer_name, data.customer_id, true, true);
customerSelect.append(option).trigger('change');
But I'd rather just use the ID if it's possible
I'm using loopback with express session to store cartId.
But I need to inject cartId on request session in order to make my tests work.
So on my remote method I have
Cart.get = function (req, cb) {
Service.getCart(req, req.session.cartId)
.then(function (result) {
cb(null, result);
})
.catch(cb);
};
Cart.remoteMethod(
'get',
{
accepts: { arg: 'req', type: 'object', 'http': { source: 'req' } },
returns: { arg: 'cart', type: 'object', root: true },
http: { path: '/', verb: 'get' }
}
);
How can I force req.session.cartId for my tests?
Thanks
If I understand your case correctly, you can do something similar to the code below, you would just add another param (cardId) to your get method definition:
Cart.remoteMethod('get',{
accepts: [
{ arg: "caseId", type: "number", http: {source:'path'} },
{ arg: 'req', type: 'object', http: { source: 'req' } }
],
returns: { arg: 'cart', type: 'object', root: true },
http: { path: '/:caseId/getCart', verb: 'get' }
});
You can simply use "get" remote method and pass cartId through URL or if you have concern about cartId visibility on URL then you can use post method as following code.
Use following cart.js file and explore in loopback api.
module.exports = function (Cart) {
Cart.getCart = function (cartId, cb) {
Cart.findOne({
where: { cartId : cartId }
}, function (err, cart) {
cb(null, users);
});
};
Cart.remoteMethod('getCart', {
accepts: {
arg: "id",
type: "string",
required: true
},
returns: {
arg: 'cart',
type: 'object'
},
http: {
path: '/:cartId/getcart',
verb: 'get'
}
});
};
get call : http://HOST:IP/cart/YourID/getcart
You will retrieve cart by Id.
Hope this will work.
I have a dropdown with multiple options to select. When I select value1 (company), autocomplete should use the service call. When I select value2, lookup should be used.
How can I implement this?
$('#qckSearchKeyword').autocomplete({
serviceUrl: function() {
var option = $('#qck-unspsc').val();
if (option == "country") {
// when country selected through drop down i should use lookup rather then service call
serviceloc = "getCountries";
localStorage.option = "country";
}
if (option == "industry") {
serviceloc = "getSicCode";
localStorage.option = "sicCode";
}
return serviceloc;
},
onSelect: function(suggestion) {
localStorage.tmpSelectedTxt = $.trim($('#qckSearchKeyword').val());
$('#selectFromSuggestions').val("true");
$('#qckSearchKeyword').focus();
},
paramName: "searchTerm",
delimiter: ",",
minChars: 3,
transformResult: function(response) {
// alert(response);
return {
suggestions: $.map($.parseJSON(response), function(item) {
return {
value: item.suggesCode,
data: item.suggesString
};
})
};
}
});
Split up the options for the different autocomplete calls.
Use a data-type on the options you select.
Switch the data-type and extend the proper options
Init autocomplete with proper options
I simply copy/pasted some configuration I've done in the past for this functionality:
...
ajaxOptionsFlight: {
url: '/api/autocomplete/airport/',
type: 'get',
dataType: 'xml'
},
ajaxOptionsHotel: {
url: '/api/locations/hotel/',
type: 'get',
dataType: 'xml'
},
ajaxOptionsCitytrip: {
url: 'http://budapest.onlinetravel.ch/destfinder',
dataType: 'jsonp',
data: {
vendors: 'merger',
client: 'conbe',
filter: 'IATA',
format: 'json',
language: 'en'
}
},
ajaxOptionsCar: {
url: '/api/locations/car/',
dataType: 'json'
},
ajaxOptionsSubstitute: {
url: 'http://gd.geobytes.com/AutoCompleteCity',
dataType: 'jsonp'
},
autocompleteOptions: {
autoFocus: true,
minLength: 1
},
....
After that I make sure I can switch on data-type and hook it on the source parameter of the autocomplete options:
autocompleteOptions = $.extend({}, autocompleteOptions, {
source: type === 'citytrip' ? function (request, response) {
ajaxOptions = $.extend(true, {}, ajaxOptionsCitytrip, {
data: {
name: $.trim(request.term),
language: cookieLanguage
},
success: function (d) {
response($.map(d.Destinations, function (item) {
return {
label: item.name + ', ' + item.country,
value: item.name,
code: item.olt_id
};
}));
}
});
$.ajax(ajaxOptions);
} : type === 'flight' ? function (request, response) {
ajaxOptions = $.extend({}, ajaxOptionsFlight, {
url: ajaxOptionsFlight.url + $.trim(request.term),
success: function (d) {
response($.map($(d).find('airport'), function (item) {
return {
label: $(item).children("displayname").text(),
value: $(item).children("displayname").text(),
code: $(item).children("code").text()
};
}));
}
});
$.ajax(ajaxOptions);
} : type === 'hotel' ? function (request, response) {
// and so on ...
}
});
Not the most elegant way of writing, I admit. But it's basically a simple mapping between data-type and configuration options to provide for autocomplete.
In the end I only call:
input.autocomplete(autocompleteOptions);
And we're done. Hope that makes sense.
I have installed the jsrouting-bundle, and this is my code:
Javascript:
$(document).ready(function () {
$(".pmcontents").hide();
$(".pmbox").click(function () {
$(this).css("font-weight", "normal");
$(this).next().toggle();
var myValue = $('this').attr('id');
var DATA = 'sentValue=' + myValue;
$.ajax({
type: "POST",
url: Routing.generate('isread'),
data: DATA,
cache: false,
success: function (data) {
alert("database has been updated");
}
});
});
});
Controller:
public function isreadAction() {
$request = $this->get('request');
if ($request->isXmlHttpRequest()) {
var_dump($request->request->get('sentValue'));
$em = $this->getDoctrine()->getEntityManager();
$pm = $this->getDoctrine()
->getRepository('LoginLoginBundle:Privatemessage')
->findBypmid($request->request->get('sentValue'));
$pm->setIsRead(true);
$em->flush();
return new Response();
}
}
Routing:
isread:
path: /game/isread
defaults: { _controller: LoginLoginBundle:Default:isread }
requirements:
_method: POST
I get the following error in my console:µ
Error: The route "isread" does not exist.
So along with the errors that I get on the image below this should be my problem, however I don't know what I have done wrong.
You need to expose the route, like:
isread:
path: /game/isread
defaults: { _controller: LoginLoginBundle:Default:isread }
requirements:
_method: POST
options: # < add these two
expose: true # < lines
» manual
Given the following service:
vdgServices.factory('UserService', ['$resource',
function($resource) {
return $resource('api/users/:id', {}, {
doGet: {
method: 'GET',
params: { id: '#userId' }
},
doPost: {
method: 'POST',
params: { id: '#userId' }
},
doPut: {
method: 'PUT',
params: { id: '#userId' }
},
doDelete: {
method: 'DELETE',
params: { id: '#userId' }
}
});
}]);
I observe the following requested URLs:
var params = { userId: 42 };
var onSuccess = function() { console.log("OK"); };
var onError = function() { console.log("KO"); };
UserService.doGet(params, onSuccess, onError);
// requests api/users?userId=42
UserService.doPost(params, onSuccess, onError);
// requests api/users/42
UserService.doPut(params, onSuccess, onError);
// requests api/users/42
UserService.doDelete(params, onSuccess, onError);
// requests api/users?userId=42
Can anybody explain why the :id URL parameter gets sometimes replaced by 42, sometimes not?
Ideally, I would like it to be replaced for any method, i.e. that the requested URL becomes "api/users/42" everytime.
AngularJS $resource
If the parameter value is prefixed with # then the value of that parameter will be taken from the corresponding key on the data object (useful for non-GET operations).
You have put params in the wrong place, you should implement like this
.factory('UserService', function($resource) {
return $resource('api/users/:id', { id: '#id' }, {
doGet: {
method: 'GET'
},
doPost: {
method: 'POST'
},
doPut: {
method: 'PUT'
},
doDelete: {
method: 'DELETE'
}
});
});
Lets test it
describe('userApp', function () {
var UserService
, $httpBackend
;
beforeEach(function () {
module('userApp');
});
beforeEach(inject(function (_UserService_, _$httpBackend_) {
UserService = _UserService_;
$httpBackend = _$httpBackend_;
}));
describe('User resource - api/users', function () {
it('Calls GET – api/users/{id}', function() {
$httpBackend.expectGET('api/users/42').respond(200);
UserService.doGet({id: 42});
$httpBackend.flush();
});
it('Calls POST - api/users/{id}', function() {
$httpBackend.expectPOST('api/users/42').respond(200);
UserService.doPost({id: 42});
$httpBackend.flush();
});
it('Calls PUT - api/users/{id}', function() {
$httpBackend.expectPUT('api/users/42').respond(200);
UserService.doPut({id: 42});
$httpBackend.flush();
});
it('Calls DELETE - api/users/{id}', function() {
$httpBackend.expectDELETE('api/users/42').respond(200);
UserService.doDelete({id: 42});
$httpBackend.flush();
});
});
});
jsfiddle: http://jsfiddle.net/krzysztof_safjanowski/vbAtL/