Can an Ext.data.JsonPStore Host (base url) be set? - extjs

Is it possible, in Ext 6.5.3, to set the JsonPStore root url so that the config parameter ‘url’ value gets automatically appended?

There are two ways to go:
Either in your store
stores: {
myStore: {
type: 'testStore',
listeners: {
beforeload: function(store, operation) {
// either this works
store.getProxy().setUrl('newUrl');
// or you can try
operation.setUrl('newUrl');
}
}
}
}
Or you can try to use a global apporach...
either via onBeforeLaunch in the Application.js
onBeforeLaunch() {
// redirect all calls to api url
Ext.Ajax.addListener('beforerequest', function (conn, options) {
options.url = Core.APIURL + options.url;
});
this.callParent(arguments);
}
or via Ext.data.Connection event beforerequest

The config parameter ‘url’ value gets automatically appended.If set JsonPStore in root url .

Try:
var store = Ext.getStore('YourStoreId');
store.getProxy().setUrl('your url');

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.

AngularJS Restangular and get a single url

I have these "methods" in my angular service that use restangular to get remote data where the respose is this:
{
"1105":{"title":"","field_nazione":{"und":[{"value":null,"format":null,"safe_value":""}]},"field_redazionale":{"und":[{"value":null}]}},
"1110":{"title":"","field_nazione":{"und":[{"value":null,"format":null,"safe_value":""}]},"field_redazionale":{"und":[{"value":null}]}}
};
function restfulService(ipCookie,Restangular) {
return {
//Setta la directory di partenza del service rest. In questo modo non devo sempre definirlo
restfulBase : function() {
return Restangular.oneUrl('rest','http://MYREMOTEHOST/rest');
},
getAllCity : function () {
return this.restfulBase().get('cities', {'all':1}, {}, {'X-CSRF-Token': tokenVar});
},
....
};
Why when I call getAllCity() the url is :
http://MYDOMAIN/rest?0=c&1=i&2=t&3=i&4=e&5=s
?
If I use this :
Restangular.oneUrl('rest','http://MYDOMAIN/rest/cities').get({all : 1});
I have no problems.
I have tried changing my app to set Restangular.setBaseUrl() in .config() method and then changing my service to use Restangular.all('cities').get() but I have an error about "strings".
If I use getAll() I have an error about "getLists() want array and not objects".
So: which is the correct way to use Restangular ? I have read online documentation and tutorial, but I have not understand how to retrieve elements in the right way. And to "post".
Thanks and sorry for this stupid question.
I believe the problem is that you set your base as "one" type of resource. The "one" method is not for setting the base urls. The way I set the base url is like this:
angular.module('app')
.config(['RestangularProvider', function (RestangularProvider) {
// Set the base URL
RestangularProvider.setBaseUrl('http://MYREMOTEHOST/rest');
}]);
And then I access each resource, depending on its type with "one" or "all", like so:
function restfulService(ipCookie,Restangular) {
return {
getAllCity : function () {
return Restangular.all('cities').getList();
},
....
};
You can also set the default params in the config phase, or per request at runtime.
The "getLists() want array and not objects" error you get when you use "all" is because it accepts only arrays as a response, therefore you need to intercept the data before and parse it in an array. In your case, you are getting an object, so you can parse it like this:
// this happens at runtime, either in your implementation code or in a more global config file, like:
Restangular.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
// If the what is set, than just grab it and return it
if (data.hasOwnProperty(what)) {
return data[what];
} else {
// Otherwise make it an array
var arr = [];
for (var key in data) {
arr.push(data[key]);
}
return arr;
});
Hope this helps.

Parameters for paging while http post in 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'.

ExtJS4 store proxy url override

I am trying to reuse a store by altering proxy url (actual endpoint rather than params). Is it possible to override proxy URL for a store instance wih the following syntax:
{
...some view config ...
store: Ext.create('MyApp.store.MyTasks',{proxy:{url:'task/my.json'}}),
}
if proxy is already well defined on the Store definition?
EDIT: AbstractStore source code sets proxy the following way
if (Ext.isString(proxy)) {
proxy = {
type: proxy
};
}
SOLUTION : store.getProxy().url = 'task/myMethod.json';
{
... some tab config ...
store: Ext.create('MyApp.store.MyTasks'),
listeners: {
afterrender: function(tab) {
tab.store.getProxy().url = 'task/myMethod.json'; //<--Saki magic :)
tab.store.load();
}
}
}
http://www.sencha.com/forum/showthread.php?149809-Reusing-Store-by-changing-Proxy-URL
You cannot override the url of a proxy alone when creating a store. You will have to pass a complete proxy. This is because, the library replaces the proxy as a whole! So, what you can do is:
{
...some view config ...
store: Ext.create('MyApp.store.MyTasks',{
proxy: {
type: 'ajax',
url : 'task/my.json',
reader: {
type: 'json',
root: 'rows'
}
}
}),
}
Now another possibility is, changing the end point after you have the instance of store. If you need to load the store from a different endpoint, you can make use of the load method.
store.load({url:'task/others.json'});
Since, in your case you are trying to re-use a store, you can pass the whole proxy. Your store's (MyApp.store.MyTasks) constructor should be capable of handling the new config and applying it to the store... Here is an example:
constructor: function(config) {
this.initConfig(config);
this.callParent();
}
Use the store.setProxy() method. Link here:
I have a BaseStore which I use to store default settings.
Ext.define('ATCOM.store.Shifts', {
extend : 'ATCOM.store.BaseStore',
model : 'ATCOM.model.Shift',
constructor : function(config) {
this.callParent([config]);
this.proxy.api = {
create : 'shifts/create.json',
read : 'shifts/read.json',
update : 'shifts/update.json',
destroy : 'shifts/delete.json',
};
}
});

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