Let's say we follow an original article http://www.sencha.com/learn/the-mvc-application-architecture and have such store:
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data/users.json',
reader: {
type: 'json',
root: 'users',
successProperty: 'success'
}
}
});
And we decided to implement an infinite scrolling grid. To do that we need to remove autoLoad: true and invoke store.guaranteeRange(...) manually.
So what is the best place for doing so?
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
remoteSort: true,
buffered: true,
pageSize: 100,
proxy: {
type: 'ajax',
url: '/postdata/list',
limitParam: 'size',
startParam: undefined,
reader: {
type: 'json',
root: 'data',
successProperty: 'success'
}
}
});
Demo here http://ext4all.com/post/extjs-4-1-grid-infinite-scroll-in-mvc
Somewhere where you render your grid. You can overwrite afterRender() method, or if it's modal grid/dialog - load the store before presenting it.
Couple side note (I'm trying to make a point that autoLoad usually is false for all stores:
if you ever will use any authentication in your application - you
will have to disable autoLoad on all stores.
if you have more then couple stores (say 5-10+?) it's highly recommended to disable that too. You don't want all of them loading at the same time when application is starting.
very often you need to have guarantee that something happened after the store is loaded and then again you disable autoLoad, subscribe to load event and load() the store manually.
Related
Following scenario:
{
xtype: 'combo',
displayField: 'LANGTEXT',
valueField: 'KURZTEXT',
store: {
remoteSort: false,
autoLoad: false,
pageSize: 999999,
fields: [
{ name: 'KURZTEXT', type: 'string' },
{ name: 'LANGTEXT', type: 'string' }
],
proxy: {
type: 'ajax',
url: 'callHandler.cfc',
actionMethods: { read: 'POST' },
reader: {
type: 'json',
rootProperty: 'DATA.ROWS',
totalProperty: 'TOTALCOUNT'
}
},
listeners: {
load: function(store, records, successful, operation, eOpts ){
//is something like this possible?
var combo = store.getCombo()
}
}
}
}
Is it possible to get the combobox reference from the store with something like this: store.getCombo()? I know that normally you can only get the store reference from the combobox. But I thought maybe it works also the other way around, if the store is created in the combobox?
You may want to check the combobox afterQuery template method.
It's a configuration available for the combobox component that works almost similar to the store's load event. Here you have access to both the combobox component and the store.
I think the drawback is: it only gets called when the combo trigger is clicked or a value is typed in the combo's textfield. I believe this would already be help if you want to do your post-processing after these events.
{
xtype: 'combo',
displayField: 'LANGTEXT',
valueField: 'KURZTEXT',
store: {
remoteSort: false,
autoLoad: false,
pageSize: 999999,
fields: [
{ name: 'KURZTEXT', type: 'string' },
{ name: 'LANGTEXT', type: 'string' }
],
proxy: {
type: 'ajax',
url: 'callHandler.cfc',
actionMethods: { read: 'POST' },
reader: {
type: 'json',
rootProperty: 'DATA.ROWS',
totalProperty: 'TOTALCOUNT'
}
}
},
afterQuery: function (queryPlan) {
var combo = queryPlan.combo; // I guess `var combo = this;` should work too..
var store = combo.getStore();
// always return queryPlan
return queryPlan;
}
}
Let me know if you have any issue or questions.
The only solution I could think of was to write a custom matcher function.
You could do this by overriding the Ext.Component and adding the matcher function like this:
Ext.override(Ext.Component, {
hasStoreId: function (storeId) {
if (Ext.isFunction(this.getStore) && this.getStore().storeId) {
return this.getStore().storeId === storeId;
}
return false;
}
});
Now that you have a matcher function for every component you can search for all components with given storeId like this:
Ext.ComponentQuery.query("{hasStoreId('mystore')}");
You can also be more precise and only search for combos that match the criteria like this:
Ext.ComponentQuery.query("combo{hasStoreId('mystore')}");
Now that you have all combos with the given storeId you should easily be able to retrieve the combo you need.
Here a Sencha fiddle with a working example:
example code
I'm upgrading an app to ExtJS 5, and I can't seem to get a grid using RowEditing to POST the edited record back to my server.
Ext.define("MyRecordDef", { extend: "Ext.data.Model" });
var MyEditor = Ext.create('Ext.grid.plugin.RowEditing', { clicksToEdit: 1 });
var MyStore = new Ext.data.Store({
model: "MyRecordDef",
autoSync: true,
proxy: {
type: "ajax",
url: "ajaxurl.aspx",
batchActions: false,
extraParams: { Command: 'Save' },
reader: { type: "json", rootProperty: "rows" },
writer: { type: "json", encode: true, writeAllFields: true }
}
});
var MyGrid = new Ext.grid.GridPanel({
store: MyStore,
plugins: [ MyEditor ],
columns: [
{
id: "fieldtoedit",
dataIndex: "fieldtoedit",
editor: new Ext.form.NumberField()
}
]
});
The row editor comes up, I'm able to change the value and click the Update button, but then nothing happens. No request is made, no errors logged in the console.
I added the following:
MyGrid.on('edit', function (e) {
alert('You are Editing ' + e.context.record.id);
MyStore.sync(); // attempt to force a sync
});
I get the alert with the correct record number, but still no AJAX request. It's like ExtJS is completely ignoring the writer.
I don't have different endpoints for each CRUD operation, so I'm not using the api config option, it should be using the url.
First of all you must define rootProperty on writer when you use encode: true.
Then after adding fields to MyRecordDef requests are sended.
Working sample: http://jsfiddle.net/jjVwR/3/ (saving don't work, but you can see on console that request is send)
I am trying to link my grid with a store, which is using a proxy to connect to some outside source. This is how I have set it up :
Ext.define('js.dmwf.PackageStore', {
extend: 'Ext.data.JsonStore',
model: 'js.model.Package',
remoteFiler : false,
remoteSort: false,
autoLoad: true,
proxy: {
type: 'json',
url : 'mock/GetPackageListBB.json',
reader: {
type: 'json'
},
} });
However I am getting an error. Which is happening in the parseNamespace function in ext-all-debug.
Uncaught TypeError: Cannot read property 'substring' of undefined
ext-all-debug.js:5043
Ext.ClassManager.parseNamespace ext-all-debug.js:5043
I have a feeling that I am missing an import or two. However i think i have everything :
Ext.require([
'Ext.data.*',
'Ext.data.proxy.*',
'Ext.data.reader.*',
'Ext.grid.*',
'Ext.tree.*',
'Ext.ux.grid.FiltersFeature',
'Ext.toolbar.Paging',
'Ext.ux.form.SearchField',
'Ext.util.*',
'Ext.state.*'
// 'Ext.ux.grid.Search'
]);
I have a fiddle too :
https://fiddle.sencha.com/#fiddle/6jq
Proxy type needs to be 'ajax'.
proxy: {
type: 'ajax',
...
}
I'm faced with problem in ExtJS 4.2, that store.load() method doesn't load data from server, only retrieve json.
My js/itfx/resources/genres.json file:
[{"name":"Action & Adventure","code":"ACTION-ADVENTURE-00"},{"name":"African","code":"AFRICAN-00"},{"name":"Anime","code":"ANIME-00"},{"name":"Bollywood","code":"BOLLYWOOD-00"},{"name":"Classics","code":"CLASSICS-00"},{"name":"Comedy","code":"COMEDY-00"},{"name":"Concert Films","code":"CONCERT-FILMS-00"},{"name":"Documentary","code":"DOCUMENTARY-00"},{"name":"Drama","code":"DRAMA-00"},{"name":"Foreign","code":"FOREIGN-00"},{"name":"Holiday","code":"HOLIDAY-00"},{"name":"Horror","code":"HORROR-00"},{"name":"Independent","code":"INDEPENDENT-00"},{"name":"Kids & Family","code":"KIDS-FAMILY-00"},{"name":"Made for TV","code":"MADE-FOR-TV-00"},{"name":"Middle Eastern","code":"MIDDLE-EASTERN-00"},{"name":"Music Documentaries","code":"MUSIC-DOCUMENTARIES-00"},{"name":"Music Feature Film","code":"MUSIC-FEATURE-FILMS-00"},{"name":"Musicals","code":"MUSICALS-00"},{"name":"Regional Indian","code":"REGIONAL-INDIAN-00"},{"name":"Romance","code":"ROMANCE-00"},{"name":"Russian","code":"RUSSIAN-00"},{"name":"Sci-Fi & Fantasy","code":"SCIFI-FANTASY-00"},{"name":"Short Films","code":"SHORT-FILMS-00"},{"name":"Special Interest","code":"SPECIAL-INTEREST-00"},{"name":"Sports","code":"SPORTS-00"},{"name":"Thriller","code":"THRILLER-00"},{"name":"Turkish","code":"TURKISH-00"},{"name":"Urban","code":"URBAN-00"},{"name":"Western","code":"WESTERN-00"}]
My model:
Ext.define('ITFX.model.films.info.FilmGenre', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'},
{name: 'code', type: 'string'}
]
});
My store:
Ext.define('ITFX.store.films.info.FilmGenre', {
extend: 'Ext.data.Store',
model: 'ITFX.model.films.info.FilmGenre',
proxy: {
type: 'ajax',
url : 'js/itfx/resources/genres.json',
reader: {
type: 'json'
}
}
});
So, after execute code abowe:
var allFilmGenresStore = Ext.create('ITFX.store.films.info.FilmGenre');
allFilmGenresStore.load();
Methods
allFilmGenresStore.getCount(); //0
allFilmGenresStore.getTotalCount(); //0
will return, that store have nothing loaded
What I'm doing wrong?
Thanks in advance
Yes, thanks for assist, the rout cause was, that store data loaded asynchronously. Code for load data, should be:
allFilmGenresStore.load({
callback : function(records, options, success) {
// some custom logik
}
});
You have to change reader
reader: {
type: 'json',
root: 'root'
}
and to send json_encode('root' => $data);
I hope it will help you
I've a ScriptTagProxy and I'm able to receive the data, but now I wanted to update a record. I've specified an url but only one url. Do I have to handle all the actions (read, update, create, delete) with this url?
If yes: how does the action is applied to the url?
If not: how I can specify more urls?
Here is the code I have so far:
app.stores.entries = new Ext.data.Store({
model: "app.models.Entry",
storeId: 'app.stores.entries',
proxy: {
type: 'scripttag',
url: 'http://myurl.de/getEntries.php',
extraParams: {
username: Ext.util.JSON.decode(window.localStorage.getItem('settings')).username,
password: Ext.util.JSON.decode(window.localStorage.getItem('settings')).password
},
reader: {
type: 'json'
},
writer: {
type: 'json'
}
}
});
I've read in the docs that you can pass an config object to the save function of a model to configurate the proxy.
So I tried following:
entry.save({
url: 'http://mysite.com/updateEntry.php',
extraParams: {
username: Ext.util.JSON.decode(window.localStorage.getItem('settings')).username,
password: Ext.util.JSON.decode(window.localStorage.getItem('settings')).password,
entry: entry
},}
As you see there is a url specified.
But I still get the error:
Uncaught Error: You are using a ServerProxy but have not supplied it with a url.
);
Same behaviour when using AjaxProxy or RestProxy for example :(
Hering,
With your first block of code you ask:
Question 1) "Do I have to handle all the actions (read, update, create, delete) with this url?"
The answer is yes.
Question 2) "If yes: how does the action is applied to the url?"
According to the Sencha source code you need to define the actionMethods like so:
myApp.stores.Things = new Ext.data.Store({
model: "Things", proxy: {
type: 'ajax',
actionMethods: {
create: 'POST',
read: 'GET',
update: 'PUT',
destroy: 'DELETE'
},
url: 'jsontest.json',
reader: {
type: 'json',
root: 'things'
}
},
autoLoad: true
});
If you delete, create or edit a record you must call:
store.sync();
There is also a "autoSave" property but it only syncs on edits, not removes.
This will send over the things that have changed or been deleted as part of the request payload, it is your responsibility to parse the json and handle it.
Hering,
I was reading the documentation here, I found this example in the Model class:
Ext.regModel('User', {
fields: ['id', 'name', 'email'],
proxy: {
type: 'rest',
url : '/users'
}
});
But above you don't show your Model for app.models.Entry, have you tried that?