Extjs Store field manipulation - extjs

I am trying to build a store that will generate a model based on data from the server
Eg in the form of:
{success:true,data:[item1:{},item2{}...]}
Is there any way I can over write the model of a store?
This is what I have atm:
Ext.define('Tan.data.SimpleStore', {
extend: 'Ext.data.Store',
constructor: function (config) { //Not initComponent, thx for wasting an hour...
config=this.config||{};
Ext.define('Users', { //ext base example model.
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'string'},
]
});
config.proxy= {
type: 'ajax',
url : 'server.php?c=testFunction',
reader: {
type: 'json',
root: 'data'
}//Example return: {"success":true,"data":["0":1,"2":1,"3":1,"4":1]}
}
config.model='Users';//Store breaks without this :((
this.callParent([config]); //Proto It
this.load({ // watch for the load event and then manipulate
// ( or try to atleast ) the fields
callback: function(records,operation,success){
// As expected obj is correct
var obj=Ext.decode(operation.response.responseText);
//K now wtf. Have the data but....
Ext.ModelManager.unregister(this.config.model);
Ext.define(this.config.model, {
extend: 'Ext.data.Model'
,fields: Ext.Object.getKeys(obj.data)
,url : 'server.php?c=testFunction'
,reader: {
type: 'json',
root: 'data'
}
});//yay you over wrote the model, but meh, nothing
console.log(this); //Bleh 0 items in store.data
}
});
}
});
var s= Ext.create('Tan.data.SimpleStore');
s.load();
It appears that one must have a model declared when loading a store, so I just declare a crud one, with every intention of over writing it.
Theoretically I suppose it might work by doing a callback on an ext.Ajax call as a constructor function, but I am trying to avoid it.

You can define your own reader or override Reader.read method.
I've solved similar problem in this post.

This was oddly simple.
this.add({key:'value});
Registers the field.
Ext.define('Tan.data.SimpleStore', {
extend: 'Ext.data.Store',
constructor: function (config) {
config=this.config||{};
Ext.define('Users', {
extend: 'Ext.data.Model',
fields: [
]
});
config.proxy= {
type: 'ajax',
url : 'server.php',
reader: {
type: 'json',
root: 'users'
}
}
config.model='Users';
this.callParent([config]);
this.load({
callback: function(records,operation,success){
var obj=Ext.decode(operation.response.responseText);
this.add({data:obj}) //this is the magic
console.log(this.getRange());
console.log(this.max('data'));//yay it logs my array, looks like the handlers are in place
}
});
}
});
var s= Ext.create('Tan.data.SimpleStore');
s.load();

I've asked a similar question in Sencha's forums, but I haven't got a response.
Sorry I'm not giving you a direct answer.

Related

How to access other Store records from Model's convert method in ExtJS6?

I am trying to have a calculated field inside a Model that looks something like value (maxValue), where maxValue is the maximum value among all other records currently loaded (think current page of a Grid).
Model:
Ext.define('MyApp.model.Example', {
extend: 'Ext.data.Model',
fields: [
{name: 'id'},
{name: 'value'},
{name: 'calculated_value', convert: function(value, record){
//how to access all the records here, not just the current one?
}}
]
});
A model is not aware of records, it just represents a single record, and the convert method is intended to allow you to convert the value, or combine other fields into a single value (note unless you define "depends" to reference other fields in this instance the convert is only called when the data is loaded and not if the fields it depends on change).
When you create a grid, the grid uses a store, the store contains a collection of records, and this would be the place to do this.
Within the config for your store you could add a listener for 'datachanged' which will fire whenever records are added or removed from the store, from here you could work through all the records in the store, work out a max value, and update records with it.
Ext.create('Ext.data.Store', {
model: 'Example',
proxy: {
type: 'ajax',
url : 'example.json',
reader: {
type: 'json'
}
},
listeners:{
datachanged:function(store){
var maxValue=store.max('value');
store.beginUpdate();
store.each(function(record){
record.set('calculated_value',maxValue);
});
store.endUpdate();
}
}
});
If you are loading the store from a server, then you will be implementing a reader, this would possibly be an even better place to do this.
Ext.create('Ext.data.Store', {
model: 'Example',
proxy: {
type: 'ajax',
url : 'example.json',
reader: {
type: 'json',
transform: {
fn: function(data) {
var maxValue=0;
Ext.each(data.items,function(item){
if(item.value>maxValue) maxValue=item.value;
});
Ext.each(data.items,function(item){
item.calculated_value=maxValue;
});
return data;
},
scope: this
}
}
},
});
Its also worth clarifying if you really need to duplicate this value, I presume you then want to reference somehow within the grid, perhaps in a renderer, instead you could just set the value once on the store:
Ext.create('Ext.data.Store', {
model: 'Example',
proxy: {
type: 'ajax',
url : 'example.json',
reader: {
type: 'json'
}
},
listeners:{
datachanged:function(store){
store.maxValue=store.max('value');
}
}
});
Then within your grid column config, add/update a renderer (in this example I display value as a percentage of maxValue):
{
dataIndex:'value',
renderer:function(value, metaData, record, rowIndex, colIndex, store, view){
return Math.round((100/store.maxValue)*value)+'%';
}
}

Store.load() does not execute after setting a new model

I want to reconfigure a GridPanel using myGridPanel.reconfigure(store,columns). I can't use metachange event for this because I need to make a separate call for metadata (back-end constraint).
I make the call for metadata, I receive the metadata that I need and then create a new model with a new set of fields and a new proxy (new url). I set the model to the existing store (which is bind to my gridPanel) and then I call store.loadPage(1) (because I use a bufferedStore) and myGridPanel.reconfigure(store,meta.columns).
My problem is that store.loadPage(1) is not happening. I don't know what I am missing...
My store looks like this:
Ext.define('Foo.store.Results', {
extend: 'Ext.data.BufferedStore',
requires: [
'Foo.model.ResultRecord'
],
config: {
remoteFilter: true
},
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
pageSize: 50,
storeId: 'Results',
autoLoad: false,
model: 'Foo.model.ResultRecord',
leadingBufferZone: 50,
trailingBufferZone: 10
}, cfg)]);
}
});
I create a new model like this:
createResultModel: function(url,fields) {
console.log('createResultsModel called');
return Ext.define('Foo.model.ResultsModel'+Ext.id(), {
extend: 'Ext.data.Model',
fields: fields,
proxy: {
type: 'ajax',
url: url,
useDefaultXhrHeader: false,
reader: {
type: 'json',
rootProperty: 'data'
}
}
});
}
And I change the model and reconfigure grid like this:
myStore.setModel(me.createResultModel('resources/data/results.json',meta.fields));
myStore.loadPage(1);
resultsGrid.reconfigure(myStore,meta.columns);
Thank you!
It seems that the store.load() was called but with the wrong url.... . I don't know if that is the desired functionality but it seems that the proxy from the old model was set to the store and when I set the new model, the proxy remained the old one.

Cannot add listeners to store in ExtJS Controller

In my application I have a button in a toolbar. If I click on this button to open a window following code is executed:
[...]
onClick: function() {
this.windowControl = this.getController('attributesearch.Window');
this.windowControl.init();
this.windowControl.showWindow();
}
[...]
This window contains some inputfields and a combobox with a store:
Ext.define('EM.store.AttributeQuery', {
requires: ['EM.model.AttributeQuery'],
model: 'EM.model.AttributeQuery',
proxy: {
type: 'ajax',
url: './app/configuration/AttributeQueries.json',
reader: {
type: 'json',
root: 'queries'
}
},
autoLoad: true
});
Within the init method of my window controller I want to add one onLoad-listener I try to add this listener to the store:
init: function() {
this.getAttributeQueryStore().on('load', this.onStoreLoad, this);
this.control({
'attributeSearchWindow': {
afterrender: this.onWindowRendered
}
});
},
The first line in the init method this.getAttributeQueryStore().on('load', this.onStoreLoad, this); produces the following error:
Uncaught TypeError: Object [object Object] has no method 'on' app/controller/attributesearch/Window.js:9.
It seems the store is not fully (or correct) instantiated. What am I missing?
Edit:
The console output for this.getAttributeQueryStore() is this:
constructor {self: function, superclass: Object, config: emptyFn, initConfigList: Array[0], initConfigMap: Object…}
__proto__: TemplateClass
$className: "EM.store.AttributeQuery"
autoLoad: true
config: emptyFn
configMap: TemplateClass
initConfigList: Array[0]
initConfigMap: Object
model: "EM.model.AttributeQuery"
proxy: Object
requires: Array[1]
self: function constructor() {
superclass: Object
__proto__: Object
}
Why don't you just define the store's listener as part of the store's definition?
Ext.define('EM.store.AttributeQuery', {
requires: ['EM.model.AttributeQuery'],
model: 'EM.model.AttributeQuery',
proxy: {
type: 'ajax',
url: './app/configuration/AttributeQueries.json',
reader: {
type: 'json',
root: 'queries'
}
},
autoLoad: true,
listeners: {
load: function(store, records, options) {
EM.getApplication().getController('attributesearch.Window').onStoreLoad(store, records, options);
}
}
});
It is my own fault.
If you have a closer look at my store definition, you will see that i forgot to insert the extent: 'Ext.store.Store'. Thats it. Now i can add and remove listeners like i expected to.
Thank you everyone.

EXTJS - How to bind save click of a form.Panel to my Model

Ext.define("Imobfusion.data.User",{
extend: "Ext.data.Model",
fields:[
{name: "name",type: "string"},
{name: "email",type: "email"},
{name: "password",type: "password"}
],
proxy: {
type: 'ajax',
api: {
read: '/user/read',
create: '/user/create',
update: '/user/update',
destroy: '/user/destroy'
},
reader: {
type: 'json'
},
writer: {
type: 'json'
}
}
});
Have a simplist way to bind model with form like this?:
Ext.define('Imobfusion.window.UserForm', {
extend: 'Ext.form.Panel',
model: 'Imobfusion.data.User' //This is my need (XD)
});
You can use loadRecord() method witch loads an Ext.data.Model into this form by calling setValues with the record data and on save use updateRecord() witch persists the values in this form into the passed Ext.data.Model object in a beginEdit/endEdit block. If the record is not specified, it will attempt to update (if it exists) the record provided to loadRecord. or just use getRecord() and getValues() to update the record.
You can load record to form. After editing (record.set()) the record data is sent to the server. You need an example?

ExtJS 4.1 - Changing value of JsonStore

I use ExtJS 4.1. Here's my model and store:
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: ['status', 'data', 'data1', 'data2']
});
var store1 = Ext.create('Ext.data.JsonStore', {
model: 'MyModel',
proxy: {
type: 'ajax',
url : 'actionJsonServlet'
},
autoLoad: true
});
After loading the store by Ajax, I want to change value of first "status" (just for first row) of the JsonStore.
I tried lines below but it doesn't work (record is undefined at line 2):
var record = store1.getAt(0);
record.set("status", "Waiting");
I have this error:
Cannot call method 'set' of undefined
Most likely your issue is due to asynchronous nature of store load. Depending on how your code is written you maybe attempting to do store operations too early, before the store is loaded even though you have autoLoad turned on.
The best approach is to set up a load event listener on the store and perform your operation then.
Her is an example:
Ext.define('MyApp.store.Drafters', {
extend:'Ext.data.Store',
model:'MyApp.model.User',
autoLoad:true,
proxy:{
type:'ajax',
url:'user/drafters.json',
reader:{
type:'json',
root:'data'
}
},
listeners:{
load:function (store, recs) {
store.insert(0, {uid:'', name:''}); //adding empty record to enable deselection of assignment
}
}
});

Resources