Duplicate keys in a REST connector query in loopback - javascript

I would like to ask if you know how could I duplicate parameters in a loopback REST connector query.
I have the following code:
details: {
'template': {
'method': 'GET',
'debug': true,
'url': 'https://www.example.com/data',
'timeout': 10000,
'headers': {
'Authorization': 'Bearer {token}'
},
'query': {
q: 'PHOTOS'
q: 'DETAILS',
id: '{id}'
},
'options': {
'useQuerystring': true
},
'responsePath': '$'
},
'functions': {
'searchData': [
'token',
'id'
]
}
}
The problem for that it is that it seems that loopback override the value of the parameter q by the last one, because I get only information for the last parameter.
Any idea how to solve it?
Thank you in avance.

You just have to pass them as an array:
'query': {
q: ['PHOTOS', 'DETAILS'],
id: '{id}'
},
Note that the options key, is passed to request and here's the documentation for useQuerystring:
useQuerystring - If true, use querystring to stringify and parse querystrings, otherwise use qs (default: false). Set this option
to true if you need arrays to be serialized as foo=bar&foo=baz
instead of the default foo[0]=bar&foo[1]=baz.
So if you remove it you'll end with something like ?q[0]=PHOTOS&q[1]=DETAILS.
You can also another option there:
qsStringifyOptions - object containing options to pass to the qs.stringify method.
Alternatively pass options to the
querystring.stringify
method using this format {sep:';', eq:':', options:{}}. For example,
to change the way arrays are converted to query strings using the qs
module pass the arrayFormat option with one of
indices|brackets|repeat
So you can actually end up with the same thing adding this:
"options": {
"qsStringifyOptions": {
"arrayFormat": "repeat"
}
}
And if you want to have just the brackets(something like this ?q[]=PHOTOS&q[]=DETAILS) you can specify brackets option:
"options": {
"qsStringifyOptions": {
"arrayFormat": "brackets"
}
}

Related

NodeJS : Need Help To build object with some Brackets and Braces

In my project I use request lib () and i would like to use qsStringifyOptions for query parametre but it's to much complicated in my case :/
In their documentation they link qs module to use qsStringifyOptions like them
I would like to have this URL
http://127.0.0.1:80/endpoint?foo=bar[baz:3]&aaa=[{baa:X,caa:XX,daa:[{eaa:Z,faa:ZZ}]}]&data[B]=BB&data[C]=CC
but I have this URL:
http://127.0.0.1:80/endpoint?foo=bar[baz:3]&aaa=[%7B%22baa%22:%22X%22,%22caa%22:%22XX%22,%22daa%22:[%7B%22eaa%22:%22Z%22,%22faa%22:%22ZZ%22%7D]%7D]&data[B]=BB&data[C]=CC
With this solution, the 'foo' attribute and data[B] and data[C] work fine but 'aaa' attribut not at all :
{ // some standar param URI, methode ...
useQuerystring: false,
qsStringifyOptions : {encodeValuesOnly: true, encode: false, indices: false},
qs : {
foo: 'bar[baz:1]',
aaa:'[{"baa":"X","caa":"XX","daa":[{"eaa":"Z","faa":"ZZ"}]}]',
data: {B:'BB', C:'CC'}
}
}
what i'm doing wrong? i just want it not to parse the 'aaa' attribute
thank you in advance for your help and your time

Custom parameters for bootstrap-table server side pagination

I have a service created with spring boot, for which I am trying to display its data using the bootstrap-table library.
My service allows pagination with the query parameters ?page=x&size=y, where page starts at 0.
The response for the query returns something that looks like this:
{
"_embedded": {
"catalogueOrders": [ .... ]
},
"page": {
"size": 20,
"totalElements": 11,
"totalPages": 1,
"number": 0
}
}
Where _embedded.catalogueOrders contains all the data, and page contains the totals.
I tried configuring my table as following:
$('#orderTable').bootstrapTable({
url: "http://localhost:8088/catalogueOrders?orderStatus=" + orderState,
columns: [
{
field: 'orderId',
title: 'Order ID'
},
{
field: 'priority',
title: 'Priority'
}
],
pagination: true,
sidePagination: 'server',
totalField: 'page.totalElements',
pageSize: 5,
pageList: [5, 10, 25],
responseHandler: function(res) {
console.log(res)
return res["_embedded"]["catalogueOrders"]
}
})
This is able to retrieve and display the data, however it returns all the results, clearly due to it not knowing how to apply the pagination. Total elements doesn't seem to be retrieved either, as the table displays Showing 1 to 5 of undefined rows. Also, if I replace the responseHandler with dataField: '_embedded.catalogueOrders', it's no longer displaying the data.
How do I configure the query parameters needed for pagination?
And am I doing anything wrong when I try and configure dataField and totalField?
Figured it out:
Not sure what was wrong with the dataField and totalField, but it seems to not work with nested fields. To resolve this, I formatted the response into a new object inside responseHandler:
dataField: 'data',
totalField: 'total',
responseHandler: function(res) {
return {
data: res["_embedded"]["catalogueOrders"],
total: res["page"]["totalElements"]
}
}
As for the query parameters, by default, bootstrap-table provides the parameters limit and offset. To customize that and convert to size and page like in my case, the queryParams function can be provided:
queryParams: function(p) {
return {
page: Math.floor(p.offset / p.limit),
size: p.limit
}
}
one, yes, it doesn’t work with nested fields. if you want to use nested fields, try on sass code (get the compiler, just search up on web, there’s plenty of posts on the web).
two, i’m not exactly sure what you’re talking about, but you can set up a css variable
:root{
/*assign variables*/
—-color-1: red;
—-color-2: blue;
}
/*apply variables
p {
color: var(-—color-1):
}
you can find loads of info on this on the web.

Select2 - Pass back additional data via ajax call

Ok, I feel like I'm going crazy here. I'm using the select2 jquery plugin (version 4), and retrieving data via ajax. So you can type in a name, and it will return that contact information. But I also want to return what organization that contact is a part of.
Here is my select2 initialization:
$('#contact_id').select2({
ajax: {
url: 'example.com/contacts/select',
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term,
page: params.page
};
},
processResults: function (data) {
return {
results: data
};
},
cache: true
},
minimumInputLength: 3,
maximumSelectionLength: 1
});
And here is the data I'm returning (laravel framework):
foreach($contacts as $con) {
$results[] = [
'id' => $con->contact_id,
'text' => $con->full_name,
'org' => [
'org_id' => $con->organization_id,
'org_name' => $con->org_name
]
];
}
return response()->json($results);
So isn't 'org' supposed to be attached to either the created option or select element by select2? So I could do something like $('#contact_id').select2().find(':selected').data('data').org or $('#contact_id').select2().data('data').org or something like that?
Idealistically, this would look like:
<select>
<option value="43" data-org="{org_id:377, org_name:'Galactic Empire'}">Darth Vader</option>
</select>
I swear I confirmed this worked last week, but now it's completely ignoring that org property. I have confirmed that the json data being returned does include org with the proper org_id and org_name. I haven't been able to dig anything up online, only this snippet of documentation:
The id and text properties are required on each object, and these are the properties that Select2 uses for the internal data objects. Any additional paramters passed in with data objects will be included on the data objects that Select2 exposes.
So can anyone help me with this? I've already wasted a couple hours on this.
EDIT: Since I haven't gotten any responses, my current plan is to use the processResults callback to spawn hidden input fields or JSON blocks that I will reference later in my code. I feel like this is a hacky solution given the situation, but if there's no other way, that's what I'll do. I'd rather that than do another ajax call to get the organization. When I get around to implementing it, I'll post my solution.
Can't comment for now (low reputation).. so... answering to slick:
Including additional data (v4.0):
processResults: function (data) {
data = data.map(function (item) {
return {
id: item.id_field,
text: item.text_field,
otherfield: item.otherfield
};
});
return { results: data };
}
Reading the data:
var data=$('#contact_id').select2('data')[0];
console.log(data.otherfield);
Can't remember what I was doing wrong, but with processResults(data), data contains the full response. In my implementation below, I access this info when an item is selected:
$('#select2-box').select2({
placeholder: 'Search Existing Contacts',
ajax: {
url: '/contacts/typeahead',
dataType: 'json',
delay: 250,
data: function(params){
return {
q: params.term,
type: '',
suggestions: 1
};
},
processResults: function(data, params){
//Send the data back
return {
results: data
};
}
},
minimumInputLength: 2
}).on('select2:select', function(event) {
// This is how I got ahold of the data
var contact = event.params.data;
// contact.suggestions ...
// contact.organization_id ...
});
// Data I was returning
[
{
"id":36167, // ID USED IN SELECT2
"avatar":null,
"organization_id":28037,
"text":"John Cena - WWE", // TEXT SHOWN IN SELECT2
"suggestions":[
{
"id":28037,
"text":"WWE",
"avatar":null
},
{
"id":21509,
"text":"Kurt Angle",
"avatar":null
},
{
"id":126,
"text":"Mark Calaway",
"avatar":null
},
{
"id":129,
"text":"Ricky Steamboat",
"avatar":null
},
{
"id":131,
"text":"Brock Lesnar",
"avatar":null
}
]
}
]

Links (relations) to REST resources in AngularJS

I have a REST API, which returns User object, where its roles are specified via link to another object. So at localhost/project/api/users/27/ is JSON object:
{
"id": 42,
"name": "John",
"prijmeni": "Doe",
"login": "johndoe",
"nickname": null,
"grade": 1.3,
"roles": {
"href": "http://localhost/project/api/users/1716/roles/"
}
}
What I'm trying to do is to get roles in controller. My User service looks like this:
projectServices.factory('User', ['$resource', 'UserRoles',
function($resource, UserRoles, Role) {
var User = $resource('http://localhost/project/api/users/:id', {}, {
'query': {
method: 'GET',
isArray: true
}
});
return User;
}
]);
and I tried to add (to that resource code block):
User.prototype.roles= function(){
return UserRoles.get({id:42});
};
this one freezes browser when called in ngRepeat. So I tried
User.prototype.roles = UserRoles.get({id:42});
this works. Then I tried
User.prototype.roles = $resource(this.roles.href, {}, {
'get': {
method: 'GET',
isArray: true
}
});
says, that roles is undefined. I also tried to add transformResponse param to User service GET action, but that function was never called.
The second option works just perfectly fine - except, that I have to hardcode the user ID. Suitable solution would be with somehow getting the user ID for me (i tried this.id, but that didn't work).
Perfect solution would be creating resource from given href, but as I can't access roles in prototype, I don't know how.
Thanks for any advice.
This should do the trick
projectServices.factory('UserRoles', function(){
return $resource('http://localhost/project/api/users/:id', {id: #id},
{'query': {
method: 'GET',
isArray: true
})
}
Now you can call it with
UserRoles.get({id:42})
// this makes the request : http://localhost/project/api/users/42
The #id tells angular to use the id key from the parameter passed.

How to alter the data returned by $resource in Angular.js?

I'm using an API that returns JSON data in this format:
{
paging: {
previous: null,
next: null
},
data: [
{ title: 'First Item' },
{ title: 'Second Item' },
...
]
}
I'm using Angular's $resource service to fetch this data.
My code - which is located in a controller - goes something like this:
var Entity = $resource('/api/entities');
var entities = $scope.entities = Entity.get();
And then, in the view, I can display the data like this:
<ul>
<li ng-repeat="entity in entities.data">{{entity.title}}</<li>
</ul>
It all works fine, but:
I'd rather expose only the contents of entities.data to the view, instead of the whole entities object. How can I intercept the data returned by the GET request to modify it before it populates $scope.entities?
Correlated question: since I am fetching an array of data, it would be cleaner to use Entity.query() instead of Entity.get(). But if I use Entity.query() in the code above, I get an error "TypeError: Object # has no method 'push'". This makes sense, since the API is returning an object instead of an array (hence, no 'push' method on the object). Again, if I could extract the .data attribute from the response, I'd have an array.
Following these indications by Dan Boyon, I managed to customize the default $resource service and to override the .get() or .query() methods, but I'm not sure where to go from there.
I don't think you need to modify the get or query defaults. Just use the success callback to do what you want. It should be more robust as well.
Entity.get(
{}, //params
function (data) { //success
$scope.entities = data.data;
},
function (data) { //failure
//error handling goes here
});
Html will be cleaner, too:
<ul>
<li ng-repeat="entity in entities">{{entity.title}}</<li>
</ul>
By the way, I usually declare services for my resources and then inject them into my controllers as I need them.
myServices.factory('Entity', ['$resource', function ($resource) {
return $resource('/api/entities', {}, {
});
}]);
You can use the Response Transformer (transformResponse) like this:
$resource('/api/entities', {}, {
query: {
method: 'GET',
responseType: 'json',
isArray: true,
transformResponse: function (response) {
return response.data;
}
}
});
This code modifies the "query" method behaviour, you can do the same for "get" ... !

Categories

Resources