How to pass complex search criteria to jqgrid from query string - jqgrid

I tried code below to pass filter to url which invokes jqgrid. jqGrid still shows all rows, passed filter is not passed to url to retrieve data form server.
How to force jqGrid to filter by filter passed in query string ?
window.open( '/Grid?filters=' + encodeURIComponent(
'{"groupOp":"AND","rules":[{"field":"Name","op":"cn","data":"John"}' ));

You can parse window.location.href and get all parameters which you need. If the URL contains the parameter which you need you can decode it with respect of decodeURIComponent and use like you as need.
The following code can be used for tests. It demonstrate how to decode filters parameter.
if (window.location.href.indexOf('?') < 0) {
// the code will open the current HTML page with additional
// parameter "filters" and reopen the same page with the parameters
window.location = window.location.href + '?' +
$.param({
filters: JSON.stringify({
groupOp: "AND",
rules: [
{field: "Name", op: "cn", data: "John Smith"}
]
})
});
} else {
// decode URL parameters and place in the as properties in the
// object "parameters":
var namedParameters = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'),
parameters = {},
nameAndValue,
i;
for (i = 0; i < namedParameters.length; i += 1) {
nameAndValue = namedParameters[i].split('=');
parameters[nameAndValue[0]] = decodeURIComponent(nameAndValue[1]);
if (nameAndValue[0] === "filters") {
// display the data from the "filters" parameter
var myFilters = $.parseJSON(decodeURIComponent(nameAndValue[1]));
alert(myFilters.rules[0].data);
}
}
}

Related

Does anyone understand the sorting rules for this document?

I did not understand the document below.
First,sort the strings that require to be signed according to the parameter names(first compare the first letter of all parameter names and sort them based on alphabetical order; in case that the first letter of more than one parameters is the same, sort these parameters based on the second letter of their names according to alphabetical order, and so on).
enter image description here
The above document tells us to sort, but we didn't use sort in the example.
An example is:
enter image description here
(
If the above image and description are not enough, I would appreciate it if you read the readme on github.)
(https://github.com/Hotbit-Korea/HOTBIT-KOREA-API-DOCS)
Below is the documentation for the rules for the REST API.
(https://github.com/Hotbit-Korea/HOTBIT-KOREA-API-DOCS/blob/master/rest_api.md#orderput_limit)
With the above example, did I understand what other sort I should use when the parameter name is balance.query and order.put_limit ?
The example is set as a string that is a mixture of strings and numbers.
For example: C88F04701D3349D0A93A0164DC5A4CD9
The documentation you linked explains the process, but as it seems to have confused you, I'll try rewording it. As you haven't specified a language, I'm going to use JavaScript for the code examples.
First, let's pick an endpoint, such as order.pending.
This endpoint takes the following parameters (excluding the signature): api_key (string), market (string), offset (32bit Integer), limit (32bit Integer).
Let's say I wanted to make a request to this endpoint for the first 100 pending orders on the "ETH/BTC" market, I would need these parameters:
const params = {
market: "ETH/BTC",
offset: 0,
limit: 100
}
As the request also requires our API key as api_key, we'll add that in too:
// elsewhere:
// const HOTBIT_API_KEY = "5eae7322-6f92-873a-e9bc214fd61517ec";
params.api_key = HOTBIT_API_KEY;
// params.api_key = "5eae7322-6f92-873a-e9bc214fd61517ec"
To get this params object as a string that the server understands, we can use the URLSearchParams class:
const paramString = (new URLSearchParams(params)).toString();
// paramString = "market=ETH%2FBTC&offset=0&limit=100&api_key=5eae7322-6f92-873a-e9bc214fd61517ec"
As the request must contain an MD5 signature as sign, we must take our string of parameters, append our secret_key to it and then calculate its md5 hash:
// elsewhere:
// const HOTBIT_SIGNING_SECRET = "de8063ea6e99bc967ba6395d06fabf50";
const signature = md5(paramString + "&secret_key=" + HOTBIT_SIGNING_SECRET);
// signature = "2156c177bf5373b67d0f86771f6f6581"
Next we need to add the uppercased signature to our query parameters:
params.sign = signature.toUpperCase();
// params.sign = "2156C177BF5373B67D0F86771F6F6581"
Then make our request:
fetch("https://api.hotbit.co.kr/api/v2/order.pending", {
method: "POST",
body: (new URLSearchParams(params)).toString(),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then((response) => { /* do something */ })
.catch((error) => { /* handle error */ });
But wait! We got back an "invalid signature" error with our request! What went wrong? This is because we didn't sort the parameters the same way the server did and we calculated different signatures.
In our request, we calculated the signature using the following parameter string:
"market=ETH%2FBTC&offset=0&limit=100&api_key=5eae7322-6f92-873a-e9bc214fd61517ec"
Here, the parameters were given in the order: market, offset, limit, api-key
The server expected the (alphabetical) order: api-key, limit, market, offset
At least in JavaScript, we can correct this mistake by following these steps:
Collect our parameters into an object called params:
const params = {
market: "ETH/BTC",
offset: 0,
limit: 100
api_key: HOTBIT_API_KEY
}
Convert our params object into an array of name-value pairs:
const paramPairs = Object.entries(params);
// paramPairs = [
// ["market", "ETH/BTC"],
// ["offset", 0],
// ["limit", 100]
// ["api_key", "5eae7322-6f92-873a-e9bc214fd61517ec"],
// ]
Sort the pairs array by each parameter's name, alphabetically:
paramPairs.sort(([nameA], [nameB]) => String(nameA).localeCompare(nameB))
// paramPairs = [
// ["api_key", "5eae7322-6f92-873a-e9bc214fd61517ec"],
// ["limit", 100]
// ["market", "ETH/BTC"],
// ["offset", 0],
// ]
Convert the pairs to a parameter string (using URLSearchParams again):
const paramString = (new URLSearchParams(paramPairs)).toString();
// paramString = "api_key=5eae7322-6f92-873a-e9bc214fd61517ec&limit=100&market=ETH%2FBTC&offset=0"
Combine it with our secret and calculate the signature:
const signature = md5(paramString + "&secret_key=" + HOTBIT_SIGNING_SECRET);
// signature = "63d87ee1ef3094b0e34d71ec8d512d83"
Add the uppercased signature to our parameters:
params.sign = signature.toUpperCase();
// params.sign = "63D87EE1EF3094B0E34D71EC8D512D83"
Make our request:
fetch("https://api.hotbit.co.kr/api/v2/order.pending", {
method: "POST",
body: (new URLSearchParams(params)).toString(),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then((response) => { /* do something */ })
.catch((error) => { /* handle error */ });
Now we don't get the invalid signature error!
In your language of choice, I recommend building some functions you can reuse for this:
function getSignedParameterString(params) {
const pairs = Object.entries(params)
.sort(([nameA], [nameB]) => String(nameA).localeCompare(nameB));
const paramString = (new URLSearchParams(pairs)).toString;
const signature = md5(paramString + "&secret_key=" + HOTBIT_SIGNING_SECRET)
.toUpperCase();
return paramString + "&sign=" + signature;
}
function makeHotbitPOSTRequest(endpoint, params) {
return fetch(`https://api.hotbit.co.kr/api/v2/${endpoint}`, {
method: "POST",
body: getSignedParameterString(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
}
Edit: As this API seems to ignore the standards of the application/x-www-form-urlencoded content type, you'll need to swap out using URLSearchParams for this function:
function getHotbitParamString(params) {
if (!params || typeof params !== "object") {
throw new TypeError("params must be a truthy object");
}
const paramsArray = Array.isArray(params)
? params
: Object.entries(params);
return paramsArray.map(([name, value]) =>
Array.isArray(value)
? `${name}=${JSON.stringify(value)}`
: `${name}=${value}`
);
}
Then you'll change this code:
(new URLSearchParams(params)).toString()
to
getHotbitParamString(params);

Create a django url with ajax results

I am using AJAX to refresh a table in my template by using dataTable.
When I get the results from the AJAX call (json) I'm using 'columns' to set every row. In one of the rows, I want to create a Django URL to another view.
What I have tried so far doesn't seem to work
function refreshData(event_ref) {
var table = $('#datatable').dataTable({
'processing': true,
'serverSide': false,
'responsive': true,
'destroy': true,
'ajax': {
'type': "GET",
'url': "{% url 'events:index' %}",
'dataSrc': ""
},
'columns': [
{ "data": "pk", render: function (pk) { return '<input type="checkbox" id="check_' + pk + '" name="check_all">'} },
{ "data": "fields.date_time" },
{ "data": "pk", render: function (pk) { return "<a href='{% url 'events:event' " + pk + "%}'>Click me</a>" }}
],
'order': [[ 2, "desc" ]],
'columnDefs': [ {
'targets': [0, 8], // column index (start from 0)
'orderable': false, // set orderable false for selected columns
}],
'scroller': {
loadingIndicator: true
}
});
}
The problem is in the line
{ "data": "pk", render: function (pk) { return "<a href='{% url 'events:event' " + pk + "%}'>Click me</a>" }}
and what I get is this,
Reverse for 'event' with arguments '(' + pk + ',)' not found. 1 pattern(s) tried: ['events/event/(?P[0-9]+)/']
My urls.py file is this
url('event/(?P<event_id>[0-9]+)/', views.event, name='event'),
and my view.py is this
def index(request):
latest_event_list = events.objects.order_by('-date_time')
if request.is_ajax():
json = serializers.serialize('json', latest_event_list)
return HttpResponse(json, content_type='application/json')
template = loader.get_template('events/index.html')
context = {
'app_name': "events",
'page_name': "real-time",
'latest_event_list': latest_event_list,
'total_events': len(latest_event_list)
}
return HttpResponse(template.render(context, request))
def event(request, event_id):
latest_event_list = events.objects.order_by('-date_time')[:5]
template = loader.get_template('events/event.html')
context = {
'app_name': "events",
'page_name': "archive",
'latest_event_list': latest_event_list,
}
return HttpResponse(template.render(context, request))
How can I create a Django URL with a value from AJAX call?
First of all, passing arguments to the {% url %} template tag isn't done by appending a string, to get the url you want in a template, you do:
{% url 'events:event' event_id=pk %}
Second, any template tag you use in your HTML is interpreted in the back-end once by Django when the HTML page is rendered. That is, before it gets to the browser and javascript starts running (the front-end). So what you're doing makes no sense, because you want javascript to dynamically change the url in the button.
If you look at the source of your HTML in your browser you'll see there's no template tag.
So you have to construct the url in javascript. What you could do is create a javascript variable in your template that is "{% url 'events:event' event_id=1 %}" (which in the HTML file parsed by the browser would be events/event/1 and then using string manipulation replace the "1" with the value of pk.
you catch the error because call tag when the pk is not defined, so you can fix it by using some base url and then replace pk by current value, for example:
{
var base_url = "{% url 'events:event' 0 %}";
var url = base_url.substring(0, base_url.lastIndexOf('/') +1 ) + pk;
return "<a href='" + url + "'>Click me</a>"
}

Clean up Django Ajax JSON GET Request

So I'm trying to use AJAX to load some data. I can get the data to load but it's stuck in json. How do I make it so it's cleaner & more human readable?
//jquery
$.get("/get_artwork", function(data) {
var obj = jQuery.parseJSON(data)
$('.result').append("<br/> " + data + " ");
});
#Views.py
def get_artwork(request):
if request.is_ajax():
artwork = Artwork.objects.all()[1:]
if request.method == 'GET':
data = serializers.serialize("json", artwork, fields=('name','updated'), indent=2, use_natural_keys=True)
return HttpResponse(data,mimetype='application/javascript')
elif request.method == 'POST':
message = "This is an XHR POST request"
# Here we can access the POST data
print request.POST
else:
message = "Hello"
return HttpResponse(message)
and this is what renders:
[ { "pk": 3, "model": "artworks.artwork", "fields": { "updated": "2013-01-20T06:46:24Z" } }, { "pk": 2, "model": "artworks.artwork", "fields": { "updated": "2013-01-17T23:44:26Z" } }, { "pk": 1, "model": "artworks.artwork", "fields": { "updated": "2013-01-17T23:43:22Z" } } ]
How would I make this more human-readable? Thanks!
Based on the comments you've left.. it seems your issue is downstream in the client (e.g. web browser). It is not clear what you mean by stuck in JSON. If you are using JavaScript to parse the JSON, you will need to use JSON.parse() to turn it into a native JavaScript object. If you are using jQuery and the $.ajax() method, you will need to set the mimetype to application/json for it to automatically parse it as JSON.
UPDATE
If you want to control how the JSON data is rendered in the browser, I suggest you parse the JSON response into a native JavaScript object and then iterate over objects and fields you want to render in the page. As an example, using jQuery:
$.ajax({
url: '/some-url/',
dataType: 'json',
success: function(resp) {
var i, k, li, obj, fields;
for (i = 0; i < resp.length; i++) {
obj = resp[i];
// render obj pk or model name here... now iterate over fields
fields = obj.fields;
for (k of obj.fields) {
li = $('<li>').text(k + ': ' + obj.fields[k]);
// append the li to some element..
}
}
}
});

jqGrid change search filters on submit

I would like to alter the search filters after a user has submitted them. Normally jqGrid returns name in colmodel as the value for field, I would like to change this behavior for a specific column:
I would like to change:
{"groupOp":"AND","rules":[{"field":"available","op":"eq","data":"true"}]}
to
{"groupOp":"AND","rules":[{"field":"s.trait.available","op":"eq","data":"true"}]}
I have tried altering the submitted form in the ways below; firebug shows that the functions are never being called.
var searchOptions = {
multipleSearch:true, multipleGroup:false, closeOnEscape:true, closeAfterSearch:true,
sopt:['ge', 'eq', 'le'],
beforeSubmit:function (params, postdata) {
//alterations would be here
}
,
onclickSubmit:function (params, postdata) {
//alterations would be here
}
}
This approach works for editOptions and delOptions, I am not sure why I cannot get this to work for searching.
If you use the searching toolbar you can use beforeSearch callback to modify the postData.filter. In case of Singe Field searching or Advanced Searching you can use onSearch.
In the answer you can see how the postData.filter can be modified.
UPDATED: You did something wrong in your tests. The only problem is that the current implementation of searching don't initialize this to the grid, but it's not explicitly documented somewhere.
I created the demo for you which demonstrate that you do can modify the filter before relaoding of the grid will be started. If you would search in the grid for 'Client' equal to 300 the search request will be modified to 'amount' equal to 300 and you would see the results
The corresponding code is
$('#list').jqGrid('navGrid', '#pager', {add: false, edit: false, del: false}, {}, {}, {},
{
multipleSearch: true,
overlay: 0,
onSearch: function () {
var i, l, rules, rule, $grid = $('#list'),
postData = $grid.jqGrid('getGridParam', 'postData'),
filters = $.parseJSON(postData.filters);
if (filters && typeof filters.rules !== 'undefined' && filters.rules.length > 0) {
rules = filters.rules;
for (i = 0; i < rules.length; i++) {
rule = rules[i];
if (rule.field === 'name') {
// make modifications only for the 'contains' operation
rule.field = 'amount';
}
}
postData.filters = JSON.stringify(filters);
}
}});

jqGrid display default "loading" message when updating a table / on custom update

I have a case where I need to update a jqgrid based on some search criteria which the user selects. I can get the data to update , but I would want the loading message to show while the new data is being fetched. Can someone please let me know how to get that working ?
Current code follows
var ob_gridContents = $.ajax( {
url : '/DisplayObAnalysisResults.action?getCustomAnalysisResults',
data : "portfolioCategory="+ $('#portfolioCategory').val()
+"&subPortfolioCategory="+ $('#subPortfolioCategory').val()
+ "&subportfolio=" + $('#subportfolio').val(),
async : false
}).responseText;
var ob_Grid = jQuery('#OBGrid')[0];
var ob_GridJsonContents = eval('(' + ob_gridContents + ')');
$('#ob_Grid').trigger("reloadGrid");
ob_Grid.addJSONData(ob_GridJsonContents);
ob_Grid = null;
ob_GridJsonContents = null;
}
If I correct understand what you will, I can recommend you to use jQuery blockUI plugin (http://malsup.com/jquery/block/). Then you don’t need more to use "async : false" parameter of $.ajax function and do something like following:
var WaitMsg = function () {
jQuery('#main').block({ message: '<h1>Die Daten werden vom Server geladen...</h1>' });
};
var StopWaiting = function () {
jQuery('#main').unblock();
};
WaitMsg();
$.ajax({url : '/DisplayObAnalysisResults.action?getCustomAnalysisResults',
data: jQuery.param({portfolioCategory: $('#portfolioCategory').val(),
subPortfolioCategory: $('#subPortfolioCategory').val(),
subportfolio: $('#subportfolio').val()}),
complete: function (data, status) {
if (status === "success" || status === "notmodified") {
var ob_GridJsonContents = jQuery.parseJSON(data.responseText);
...
}
StopWaiting();
},
error: function (xhr, st, err) {
// display error information
StopWaiting();
}
});
I recommend you don’t build parameters with the way like
"portfolioCategory="+ $('#portfolioCategory').val()
+"&subPortfolioCategory="+ $('#subPortfolioCategory').val()
+ "&subportfolio=" + $('#subportfolio').val()
because you can receive encoding problems, if data returned by .val() have some special characters. You could use JavaScript function encodeURIComponent in such cases (like encodeURIComponent($('#portfolioCategory').val()))
or jQuery.param function if you construct a string like p1=val1&p2=val2&...pN=valN.
Best regards
Oleg

Resources