Parameters for paging while http post in extjs - extjs

Hello I'm working on a extjs screen that has paging and the method to be used in the request must respond by HTTP POST verb.
I configured my store, so that all the read calls are posts. Realized that, extjs has simply passing the query string for the request payload, and I thought it would be possible to have the parameters separated, just as it would if it uses the params load of a store.
So I wonder if it's possible to have something like {params: {start: 0, page: 1, limit: 20}} in the request payload instead of the query string start = 0 & page = 1 & limit = 20.
I use Extjs 4.2 and Java with RESTEasy.

There isn't any built in functionality for this, but you can extend the store's proxy with the following:
Ext.define('Ext.ux.proxy.ModifiedAjax', {
extend: 'Ext.data.proxy.Ajax',
alias: 'proxy.modifiedajax',
defaultParams: 'param',
removeDefaultParams: true,
buildRequest: function(operation) {
var me = this,
request,
defaultParams = me.getParams(operation);
me.extraParams = me.extraParams || {};
if (me.defaultParams && defaultParams) {
me.extraParams[me.defaultParams] = me.applyEncoding(defaultParams);
}
var params = operation.params = Ext.apply({}, operation.params, me.extraParams);
if (me.removeDefaultParams != true) {
Ext.applyIf(params, defaultParams);
}
request = new Ext.data.Request({
params : params,
action : operation.action,
records : operation.records,
operation: operation,
url : operation.url,
proxy: me
});
request.url = me.buildUrl(request);
operation.request = request;
return request;
}
});
and in the store you need to set the proxy's type to 'modifiedajax'.

Related

EXTJS 6 - Store.Proxy.Sync - ExtraParams for Update but not Create

I have a store that I have added records to, and edited existing records in.
Now I want to sync that data back to the server.
Using store.sync()
This fires off separate requests for each of the sync types (C,R,U,D) (using the proxy api values)
For each sync type, I need to pass a dynamic extraParam (lets make it simple and say extraParam = {type: "Update"} for updates and extraParam = {type: "Add"} for adding), though in application this will be something more complex, like passing a JSON object of user details or params based on the records being synced.
There must be a way to do this, without me having to manually code out a sync function.
Can someone give an example of this if it is possible, or a better approach?
Your server proxy takes an api property that contains the various URLs:
api: {
read:'MyReadEndpoint',
create:'MyCreateEndpoint',
update:'MyUpdateEndpoint',
delete:'MyDeleteEndpoint'
}
As far as I know, you can directly add GET parameters into these urls:
api: {
read:'MyEndpoint?action=read',
create:'MyEndpoint?action=create',
update:'MyEndpoint?action=update',
delete:'MyEndpoint?action=delete'
}
When bundling the different endpoints, the sync does a string comparison, and since all endpoint definitions are different, each batch is fired separately.
This was my final solution
I needed to over ride the existing sync function, and could have done so by loading a new definition into the overrides folder, but instead chose to put this in my store.
The code for that follows:
Ext.define('db_mubin.store', {
extend: 'Ext.data.Store'
,alias: 'store.db_mubin-store'
,require: 'db_mubin.model'
,model: 'db_mubin.model'
,proxy: {
type: 'ajax'
,url: '/api'
,reader: {
type: 'json'
,rootProperty: 'data'
}
,writer: {
allowSingle: false
}
,extraParams: {
calling: 'mubin'
}
}
,listeners: {
//add: function(){this.sync({})},
//update: function(){this.sync({})},
//remove: function(){this.sync({})}
}
,sync: function(options) {
var me = this,
operations = {},
toCreate = me.getNewRecords(),
toUpdate = me.getUpdatedRecords(),
toDestroy = me.getRemovedRecords(),
listeners = me.getBatchListeners();
options = options || {};
options.params = options.params || {};
//<debug>
if (me.isSyncing) {
Ext.log.warn('Sync called while a sync operation is in progress. Consider configuring autoSync as false.');
}
//</debug>
me.needsSync = false;
me.isSyncing = true;
if (toCreate.length > 0) {
options.params.fetch = 'create';
operations.create = toCreate;
me.proxy.batch(Ext.apply(options, {
operations: operations,
listeners: listeners,
params: options.params
}));
operations = {};
}
if (toUpdate.length > 0) {
options.params.fetch = 'update';
operations.update = toUpdate;
me.proxy.batch(Ext.apply(options, {
operations: operations,
listeners: listeners,
params: options.params
}));
operations = {};
}
if (toDestroy.length > 0) {
options.params.fetch = 'destroy';
operations.destroy = toDestroy;
me.proxy.batch(Ext.apply(options, {
operations: operations,
listeners: listeners,
params: options.params
}));
operations = {};
}
me.isSyncing = false;
return me;
}
});
Now I can call sync at any time, and pass in extra details, such as being able to give the API Authentication details, user details, anything that I NEED to send, I can send.

Make GET call to REST service with parameters in Angular 2

I am trying to make a GET call to the YouTube Web API but I cannot figure out how to pass parameters using the http.get function. I have used fiddler and made sure the request is being made. I am currently getting a 400 error saying that I am missing a the parameter "Part". How can I modify my code to include the required parameters in my request?
private _url = 'https://www.googleapis.com/youtube/v3/';
private _key = '';
getPlaylistVideos(playlistId, pageToken){
var url = this._url + "playlistItems";
var options = { part: 'snippet', maxResults: 50, playlistId: playlistId, key: this._key, pageToken: pageToken }
return this.http.get(url, options);
}
You need to include the search params in to your request. I think this will work for you:
getPlaylistVideos(playlistId, pageToken) {
let url = `${this._url}playlistItems`,
options = { part: 'snippet', maxResults: 50, playlistId: playlistId, key: this._key, pageToken: pageToken },
params = URLSearchParams();
for (let key in options) params.set(key, options[key);
return this.http.get(url, {search: options});
}
You create the URLSearchParams using the set method you can find the full documentation here
Please have a look at the already asked & solved question regarding AngularJS & YouTube V3 API. See here thanks to #Sandeep Sukhija.
Anyhow, about the missing parameter part, add it to the request ex: part: 'snippet'
Example code :
function getPlaylistVideos(playlistId, pageToken) {
// pass the page token as a parameter to the API
$.get('https://www.googleapis.com/youtube/v3/playlistItems', { part: 'snippet', maxResults: 50, playlistId: playlistId, key: key, pageToken: pageToken })
}
How to use the part parameter
The part parameter is a required parameter for any API request that
retrieves or returns a resource. The parameter identifies one or more
top-level (non-nested) resource properties that should be included in
an API response. For example, a video resource has the following
parts:
snippet contentDetails fileDetails player processingDetails
recordingDetails statistics status suggestions topicDetails

How to pass query param to parse-rest-api from angularjs $http service?

I'm learning AngularJS , i set-up a development environment using sublime-text as editor and parse.com-rest-api used as back-end layer.
I came across a scenario where, I have to fetch data based on an attribute.
Below given code from the service layer of angularjs has fetch all records from table 'filim'.
var config = {
headers: {
'X-Parse-Application-Id': 'bNtp8FUfr0s1UsAwJr7MFjabCI31HytIuC3gCaJ2',
'X-Parse-REST-API-Key': 'g18cAoH7QkrBZenPqH0pynMKsn6pj4MyfDyIy6X1',
}
};
return {
getFilims: function(callback) {
var filims;
var resp = $http.get('https://api.parse.com/1/classes/filim', config).success(function(data) {
callback(data.results);
});
}
}
I have modified above url to send query-parameter to filter the output, but did not work.
I refer parse.com api doc [ https://www.parse.com/docs/rest#queries ] to modify url to send query - param.
Modified code is given below,
var params = {"where": {"status" : "CLOSED" } }
var resp = $http.get('https://api.parse.com/1/classes/filim?%s' % params, config).success(function(data) {
callback(data.results);
});
But this did not work.
Is this the way to use query-parameter ?
Regards
Ajil
'https://api.parse.com/1/classes/filim?%s' % params
This is a python pattern for interpolating strings and will not work in javascript.
The correct way of combining strings in javascript is:
'https://api.parse.com/1/classes/filim?' + params
Even still, that will probably not work because you'll end up with something like:
'https://api.parse.com/1/classes/filim?[Object object]
What you need to do for parse.com is to JSON encode the query, so try this:
var whereQuery = {"status" : "CLOSED"};
var url = 'https://api.parse.com/1/classes/filim?where=' + encodeURI(JSON.stringify(whereQuery));
var resp = $http.get(url, config).success(function(data) {
callback(data.results);
});

How to set common request headers for every ajax request in ext5?

I have to set customized headers for every ajax request, is there a way to do this only once without having to config it manually in every ajax proxy.
proxy: {
headers: {
token: 'xyz' // this token that every proxy should contain to communicate with our remote server.
}
}
In jQuery i can accomplish this by using "ajaxPrefilter" like following:
jQuery.ajaxPrefilter(function(options, originalOptions, jqXHR) {
jqXHR.setRequestHeader('token', 'xyz');
}
But i don't known how to do it properly in extjs, please help!
Ext.Ajax.setDefaultHeaders({
'Accept':'application/json'
});
how about overriding Ext.data.proxy.Ajax like this
Ext.override(Ext.data.proxy.Ajax, {
headers: {
token: 'xyz' // this token that every proxy should contain to communicate with your remote server.
}
});
Ext.Ajax is a singleton, so you should be able to do this:
Ext.Ajax.defaultHeaders = {
token: 'xyz'
};
Place it at the beginning of your app, or where you see fit, and then each subsequent Ajax request will have this token.
Below code adds CSRF header and token to every ajax request made. Note beforerequest
Ext.Ajax.on('beforerequest', function(conn, options) {
var x = document.getElementsByTagName("META");
var token = "";
var headerVal = "";
var i;
for (i = 0; i < x.length; i++) {
if (x[i].name == "_csrf")
{
token = x[i].content;
}else if (x[i].name=="_csrf_header"){
headerVal = x[i].content;
}
}
//Ext.Ajax.defaultHeaders = Ext.apply(Ext.Ajax.defaultHeaders || {}, { headerVal : token });
Ext.Ajax.setDefaultHeaders({
headerVal : token
});
});

extjs4 - is there a non json/xml writer for proxies?

I'm building some models to interact with an existing API from a previous project.
The API relies on standard POST methods to save the data.
I've configured a model and proxy up to the point where it does push the data onto the server but there only seems to be two writer types, json & xml.
proxy: {
/* ... */
reader: {
type: 'json',
root: 'results'
},
writer: {
type: '???' // <-- can only see json or xml in the docs
}
}
Isn't there a standard POST writer that simply submits data in post fields?
I'm surprised that wouldn't be a standard writer type.
(Parsing the json format wouldn't be too hard to implement but that would mean updating a lot of the old api files.)
Ok, I was able to create that writer quite easily by checking the existing writers' source code.
One thing those existing writers are able to do - and that may be why the dev team only implemented a json and xml version - is that they can push multiple records at once.
That could be implemented in POST but would be a bit more complicated.
This writer will work if you're trying to push a single model to an api using POST:
Ext.define('Ext.data.writer.SinglePost', {
extend: 'Ext.data.writer.Writer',
alternateClassName: 'Ext.data.SinglePostWriter',
alias: 'writer.singlepost',
writeRecords: function(request, data) {
request.params = data[0];
return request;
}
});
and the use this for the writer in the proxy:
writer: {
type: 'singlepost'
}
Based on Ben answer I've implemented my own writer that will collect all properties of all models into arrays.
For example if you have model like with some fields:
fields:[
{name:'id', type:'int'}
{name:'name', type:'string'}
{name:'age', type:'date'}
]
A request string will be
id=1&id=2&id=...&name=oleks&name=max&name=...&age=...
Code:
Ext.define('Ext.data.writer.SinglePost', {
extend: 'Ext.data.writer.Writer',
alternateClassName: 'Ext.data.SinglePostWriter',
alias: 'writer.singlepost',
writeRecords: function(request, data) {
if(data && data[0]){
var keys = [];
for(var key in data[0]){
keys.push(key);
}
for(var i=0;i<keys.length;i++){
request.params[keys[i]] = [];
for(var j=0;j<data.length;j++){
request.params[keys[i]].push((data[j])[keys[i]]);
}
}
}
return request;
}
});
For Sencha touch 2.0, change the writeRecords method to:
writeRecords: function (request, data) {
var params = request.getParams() || {};
Ext.apply(params, data[0]);
request.setParams(params);
return request;
}
Here's my version, adapted from answers above:
// Subclass the original XmlWriter
Ext.define('MyApp.utils.data.writer.XmlInAPostParameter', {
extend : 'Ext.data.writer.Xml',
// give it an alias to use in writer 'type' property
alias : 'writer.xml_in_a_post_parameter',
// override the original method
writeRecords : function(request, data) {
// call the overriden method - it will put the data that I
// want into request.xmlData
this.callParent(arguments);
// copy the data in request.xmlData. In this case the XML
// data will always be in the parameter called 'XML'
Ext.apply(request.params, {
XML: request.xmlData
});
// Already copied the request payload and will not send it,
// so we delete it from the request
delete request.xmlData;
// return the modified request object
return request;
}
});
Ext.define("MyApp.model.MyModel", {
extend : "Ext.data.Model",
requires : [
'MyApp.utils.data.writer.XmlInAPostParameter'
],
fields : [ 'field_A', 'field_B' ],
proxy : {
type : 'ajax',
api : {
read : '/mymodel/read.whatever',
update : '/mymodel/write.whatever'
},
reader : {
type : 'xml'
},
writer : {
// use the alias we registered before
type : 'xml_in_a_post_parameter'
}
}
});

Resources