ExtJS4 Changing data store parameters - javascript

If I have a data store on a grid like so:
store = Ext.create('Ext.data.Store', {
fields: [{
name: 'id'
}, {
name: 'filename'
}
// other fields here ...
],
proxy: {
type: 'ajax',
url: 'http://myniftyurl.com/blah',
simpleSortMode: true,
reader: {
type: 'json',
totalProperty: 'total',
root: 'result'
},
extraParams: {
'limit': Ext.get('itemsPerPage').getValue(),
'to': Ext.get('to_date').getValue()
// other params
}
},
model: 'Page',
remoteFilter: true,
remoteSort: true
});
The 'limit' and 'to' value will change based on user input, therein lies the problem. The data store keeps using the original parameters instead of the new inputs. How can I fix this?
Thanks in advance!

I normally load my grids manually by executing the store.load() in the controller.
That way prior to it I can change the store's params like so:
//getForm() retrieves the Ext.basic.Form (from Ext.panel.Form)
var params = this.getForm().getValues();
//Write over
grid.getStore().getProxy().extraParams = params;
//load
grid.getStore().load();
I'm using buffered grids which required a decent amount of rework to get completely working in 4.0.7. But that should work for you.
Another options is to use a beforeload listener but I'm not sure if changing the extraParams by then will do anything. You may be able to modified the Ext.data.Operation object that gets passed to the event handler?
Let me know how that works out for you.
Good luck!

Related

How to save, load and delete from database using a single ExtJS model?

Using ExtJS 6 one can have a store bind to the model and use the methods sync to save or load to load data.
I imagine that if a data is removed from store, upon calling sync the data will be removed from database too.
In my use case, I have different URLs and mandatory Ajax query fields for each action of create/update, load and delete data.
I have only seen examples showing load or save to storage, how can I declare the load, save and delete using Ajax in the same model?
Another doubt I have is that stores themselves can have a proxy, so they can perform those operations too, at least the load operation that I have seen in use. What's the difference between having these on the model or store? What's the best practice?
Example model from Sencha docs (is this only for read?):
Ext.define('MyApp.model.Base', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}],
schema: {
namespace: 'MyApp.model', // generate auto entityName
proxy: { // Ext.util.ObjectTemplate
type: 'ajax',
url: '{entityName}.json',
reader: {
type: 'json',
rootProperty: '{entityName:lowercase}'
}
}
}
});
Another example I found on https://examples.sencha.com/extjs/6.0.1/examples/classic/writer/writer.html using the proxy config, this seems more like what I would need as it specifies a URL for each operation:
var store = Ext.create('Ext.data.Store', {
model: 'Writer.Person',
autoLoad: true,
autoSync: true,
proxy: {
type: 'ajax',
api: {
read: 'app.php/users/view',
create: 'app.php/users/create',
update: 'app.php/users/update',
destroy: 'app.php/users/destroy'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show({
title: 'REMOTE EXCEPTION',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}
},
listeners: {
write: function(proxy, operation){
if (operation.action == 'destroy') {
main.child('#form').setActiveRecord(null);
}
Ext.example.msg(operation.action, operation.getResultSet().message);
}
}
});
I believe I can have something like this in my case (this is just an example not tested!):
Ext.define('My.Person.Model', {
proxy: {
type: 'ajax',
api: {
read: 'http://myapiserver/getuser',
create: 'http://myapiserver/upsertuser',
update: 'http://myapiserver/upsertuser',
destroy: 'http://myapiserver/removeuser'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
// How can I have the parameters for each one?
extraParams : {
isuserUnderage : ' '
, query : '%'
}
}
});
I have no idea how to do this, specially specifying parameters for each type of Ajax request (read, create, update, destroy), I can have an upsert request that will send all fields, but the remove request will require only the ID, the get request can have optional fields for filtering, like filtering persons by name.
Example to be more clear of the problem.
Example data:
[
{
"id": "1",
"name": "Fred",
"age": 21,
"sex": "m"
},
{
"id": "2",
"name": "Susan",
"age": 12,
"sex": "f"
},
{
"id": "3",
"name": "Marcus",
"age": 22,
"sex": "m"
},
{
"id": "4",
"name": "Alex",
"age": 32,
"sex": "m"
}
]
Endpoints example:
Endpoints have parameters, these are mandatory, this means that calling an enpoint without a parameter will cause a server error, also passing a parameter that is not specified will cause a server error! If a parameter is not necessary one can pass a string with a single whitespace .
To read:
Endpoint: http://myapiserver/getuser?query={query}
Name is a filter by name, for example http://myapiserver/getuser?query=fred will bring users with name that has the string fred.
To write, we usually have an upsert, so it works for both insert and update:
Endpoint: http://myapiserver/upsertuser?id={id}&name={name}&age={age}&sex={sex}
So to update we can pass the ID: http://myapiserver/upsertuser?id=1&name=Frederick&age=21&sex=m and to insert we pass an empty string for ID: http://myapiserver/upsertuser?id= &name=Maurice&age=41&sex=m
To remove:
Endpoint: http://myapiserver/removeuser?id={id}
Example: http://myapiserver/removeuser?id=1, removes person with ID 1.
Because you say it's mandatory to use GETs with query params, I would encourage you to rethink your tech stack because the RESTful verbs really make it more clear what your action is, and you remove the actual action from your URL routes. However, I know sometimes this is totally out of our control, so I'll try my best here... I have to say, I've never experienced something like this, so I don't know if what I'm showing here is a best practice.
I can't show a true implementation because Sencha Fiddle is a simple sandbox, not meant for actual server-side implementations. I'm also assuming that you're using the classic toolkit, but if you need it in modern, it's a fairly easy port that you can do.
I prefer the proxy inside of the model for several reasons... if I need to use this model in several different stores throughout my app, then each store will inherit the same proxy. If I want to use the same model, but I don't want its proxy, I can simply override it when defining the store. Also, if the proxy doesn't exist on the model, then the framework assumes what your URL should be, which doesn't work when I want to use models individually.
I think I've come up with what you're asking for in this Fiddle. Really the core of what you want is in GETUser.js.
// We need to create our own proxy that will handle this for us
Ext.define('AjaxGet', {
extend: 'Ext.data.proxy.Ajax',
alias: 'proxy.ajaxGet',
// Per your requirement, we want to send individual requests
batchActions: false,
createOperation: function (action, config) {
// This means we're doing an action against one of our records
if (config && config.records) {
if (action === 'destroy') {
config.params = config.records[0].getDeleteParams();
} else if (action === 'create' || action === 'update') {
config.params = config.records[0].getUpsertParams();
}
}
return this.callParent(arguments);
}
});
// This is the desired, "GET" User model that uses GETs and query params for all actions
Ext.define('GETUser', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [{
name: 'Name',
type: 'string'
}, {
name: 'Id',
type: 'int'
}, {
name: 'Age',
type: 'int'
}, {
name: 'Sex',
type: 'string'
}],
proxy: {
type: 'ajaxGet',
api: {
read: 'Users',
create: 'upsertuser',
update: 'upsertuser',
destroy: 'removeuser'
},
actionMethods: {
create: 'GET',
update: 'GET',
destroy: 'GET'
}
},
getUpsertParams: function () {
const data = this.getData();
// Means this record hasn't been saved, so we're in the CREATE state
if (this.phantom) {
// We don't want to send the ID with what the framework sets as the ID
data.Id = undefined;
}
return data;
},
getDeleteParams: function () {
return {
Id: this.get('Id')
};
}
});
So what I ended up doing was creating a custom proxy that overrides the createOperation method to check which operation we're doing... based on that operation, we use the methods in the model to retrieve the params we want to send to the API. You need actionMethods in the proxy because otherwise, they default to POSTs.

How to get data from xml by using URL

I have a grid where I am loading the data from the data store. Bu using some url. Code is something like that.
var store = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({
method: 'GET',
url: SomeURL
}),
remoteSort:true,
method: 'GET',
baseParams: {start: 0, limit: 25},
sortInfo:{
field: 'UPDATEDON',
direction: 'DESC'
},
reader: new Ext.data.XmlReader({
totalProperty:'#Total',
record: 'ITEM'
}, [ {name:'name',type:'string', mapping:'#name',SortType:"asUCString"},
{name:'value', mapping:'#value'}
]),
grid:this,
listener : {
load:function(){
}
}
This is loading correctly. No problem in grid. I need to access grid data at some other place in my code. so for that I am call
`var xyz = new MyGrid({val:1,newval:2});`
val and newVal are the two para for grid. But I am not getting store and store value here. Is there anyway I can get store here or get the xml value by using the same url again.
You can set in your store autoLoad: true - if it is already binded/set with this new Grid.
Or just say xyz.store.reload();
Reloads the store using the last options passed to the load method.
You can get the data form xyz.store.
How to get the information from a store depends on you and what you have there stored. You can use 'find', 'findBy', 'each' and so on (senscha doc extjs V3.4)

Ext JS dynamic store insert Cannot read property 'isModel' of undefined

I dynamically create my store from a model relation and attach this store to a grid.
var map = record.getCommunity().mappings();
map.load({
url: '/myUrl/mappings',
scope: this,
callback: function(records, operation, success) {
map.group('type');
//ExtJS bug https://www.sencha.com/forum/showthread.php?265674
me.getOutgoingGrid().destroy();
childGrid = Ext.create('hds.view.outgoingGrid', {
store: map
});
me.getGridHolder().add(childGrid);
me.getOutgoingGrid().getSelectionModel().select(0, false) ;
}
});
When I want to create a new model instance and insert it into this dynamic store I get the following error:
Cannot read property 'isModel' of undefined
Here is the code that triggers the error:
var newMap = Ext.create('hds.model.MappingModel', {
indetifier : "something",
});
me.getOutgoingGrid().store.insert(0, newMap);
I cannot found the reason of this problem....Any ideas?
It is hard to know what is breaking your code but here are a couple of things:
1 - You need to define the model identifier in the class prototype not in the instance.
2 - You misspelled identifier
So your model should look like:
Ext.define('hds.model.MappingModel', {
identifier : "something",
});
var newMap = new hds.model.MappingModel({
//...your config here
});
The error that you are seeing Cannot read property 'isModel' of undefined is thrown when the store tries to check if model is an instance of Ext.data.Model but the model being passed is undefined.
This can happen for several reasons but usually it's because you are trying to create a model before the prototype has been defined or because there is a typo on your code.
Please, try creating a a fiddle (https://fiddle.sencha.com) reproducing this error or it will be very hard to help you.
Regards,
If there was an fiddle, It would be more helpful. As I understand from your question, you have some data and you can't set the data to store or model correctly. If you had defined your model or store before set to grid, there would not be a problem. I added a fiddle how model proxy works with store and etc. Hope it helps. If the fiddle does not explain your problem, please change the fiddle codes. So, we can understand what your problem exactly. Here is the fiddle: https://fiddle.sencha.com/#fiddle/tvq
Ext.define('model.Users', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Name', type: 'string'},
{ name: 'City', type: 'string'},
{ name: 'Country', type: 'string'},
],
//idProperty: 'Name',
proxy: {
type: 'ajax',
rootProperty: 'records',
rootUrl: 'users', // used when updating proxy url
url: 'users',
reader: {
type: 'json',
rootProperty: 'records'
}
}
}); //model
var modelExt = Ext.create('model.Users', { Name: 'Ernst Handel'});
var storeExt = Ext.create('Ext.data.Store', {
requires: 'model.Users',
model: 'model.Users'
});
modelExt.load({
scope: this,
success: function(record) {
var colObjects = [];
Ext.each(Object.keys(record.data), function(key) {
colObjects.push({
text: key,
dataIndex: key
});
});
storeExt.loadData([record]);
//console.log(record, storeExt);
var grid = Ext.create('Ext.grid.Panel', {
store: storeExt,
columns: colObjects,
renderTo: Ext.getBody()
});
},
failure: function (err) {
}
});
Create model like this and then use.
var newMap = Ext.create('Ext.data.model', {
identifier : "something"
});
Add a new file in Model folder named like MappingModel.js and define model like this.
Ext.define('hds.model.MappingModel', {
extend: 'Ext.data.Model',
fields: [
'something'
]
});
Add this in app.js and then use MappingModel in your dynamic store.

Save nested form data back to server in ExtJS

I have a Model that contains an association to another Model. I am able to display the nested data into a form by using the mapping attribute on the field. Example:
Ext.define('Example.model.Request', {
extend: 'Ext.data.Model',
fields: [
{
name: 'id',
type: Ext.data.Types.NUMBER,
useNull: false
}
{
name: 'plan_surveyor',
mapping: 'plan.surveyor',
type: Ext.data.Types.STRING
}
],
associations: [
{type: 'hasOne', associationKey: 'plan', getterName:'getPlan', model: 'Specs.model.Plan'}
],
proxy: {
type: 'direct',
api: {
read: requestController.load,
update: requestController.update,
},
reader: {
type: 'json',
root: 'records'
},
writer: {
type: 'json',
writeAllFields: true,
nameProperty: 'mapping'
}
}
});
Using this method, I can display the plan.surveyor value in the form by reference plan_surveyor. I call Form.loadRecord(model) to pull the data from the model into the form.
However, now that I'm trying to send the data back to the server, I get the error:
Error performing action. Please report the following: "Unrecognized field "plan.surveyor"
I am attempting to save to the server by first calling Form.updateRecord(model), then model.save(). Is there a way to have the Writer understand that 'plan.surveyor' is not a property name but instead to properly handle nesting?
Am I doing this the right way to start with, or should I just be handling the setting of the form data and loading back into the model in a more manual fashion? It seems that nested data is not all that well supported in general - any recommendations?
Ext.define('Example.model.Request', {
extend: 'Ext.data.Model',
fields: [
{
name: 'id',
type: Ext.data.Types.NUMBER,
useNull: false
}
{
name: 'plan_surveyor',
mapping: 'plan.surveyor',//change to 'plan_surveyor'
type: Ext.data.Types.STRING
}
],
change that show in comment ,because data index is given in above format because ur give ur format thata time that is not dataindex it's a column or extjs preparatory ,so please change that may it's work well
it's not work u will send hole code

Saving the whole EditorGrid with a single Ajax request

I would like to save an ExtJS (3.3.1) editorgrid with a single Ajax request.
I've created an editorgrid, based on an ArrayStore.
var store = new Ext.data.ArrayStore({
data: arrayData,
fields: [ 'id', 'qty', 'idService', 'idSubscription',
'description', 'vat', 'amount' ]
});
[...]
var grid = {
xtype: 'editorgrid',
store: store,
view: gridView,
colModel: colModel,
selModel: selModel,
stripeRows: true,
tbar: tbar,
autoHeight: true,
width: 872,
clicksToEdit: 1
};
I've created a Save button with the following handler:
app.inv.saveButtonHandler = function () {
var myForm = Ext.getCmp("formHeader").getForm();
if (!myForm.isValid()) {
Ext.MessageBox.alert('Form Not Submitted',
'Please complete the form and try again.');
return;
}
myForm.el.mask('Please wait', 'x-mask-loading');
Ext.Ajax.request({
params: {
idCustomer: myForm.findField("idCustomer").getValue(),
issueDate: myForm.findField("issueDate").getValue(),
documentType: myForm.findField("documentType").getValue(),
documentNumber: myForm.findField("documentNumber").getValue()
},
url: 'save-sales-document-action',
method: 'POST',
success: function (response, request) {
myForm.el.unmask();
Ext.MessageBox.alert('Success', 'Returned: ' + response.responseText);
},
failure: function (response, request) {
myForm.el.unmask();
Ext.MessageBox.alert('Failed', 'Returned: ' + response.responseText);
}
});
};
In other words, I can send form elements with a simple value, but I don't know how to send the whole data grid. I would like to send the whole data grid with a single Ajax request.
I've already used before the cell-by-cell saving method, but in this case I would prefer to save the whole grid in one go. I don't need help for the server-side part, that I will do in Java, only for the client-side JavaScript.
Can someone help? Thanks!
After a night sleep and still no answers, I made further tries and I can answer my own question. I will leave the question open anyway, in case someone knows a better way.
To solve my problem, I added the property "storeId: 'gridStore'" to the ArrayStore, so I could locate the store later with Ext.StoreMgr.lookup(), then, at saving time, I proceed to re-build an Array record by record in the following way:
var gridData = new Array();
Ext.storeMgr.lookup('gridStore').each(function (record) {
gridData.push(record.data);
});
The essential part is that I don't get the whole Record, but only the data field of it.
After I've an array with the data, the easy part is add it to the params of Ajax.request:
params: {
...
gridData: Ext.encode(gridData)
},
This finally works. All the data is encoded in a single field. Of course on the server it will have to be decoded.

Categories