Can u help me with rest store, please. I want my store become REST, I saw some samples where HttpProxy was used and tried to do the same, but it dosn't work.
As i noticed in samples store was always created like: var store = Ext.create...
If problem in this, then i don't know where to invoke Ext.create, and previously I always used storeId in grid and it worked well.
P.S. why grid couldn't be created without store data just with blank fields?
Here is my 'TestStore' code:
Ext.define('MVC.store.Notes', {
extend : 'Ext.data.Store',
requires : [
'MVC.model.Note'
],
storeId : 'TestStore',
model : 'MVC.model.Note',
autoLoad: true,
proxy: {
type: 'rest',
url: 'rest/notes',
reader: {
type: 'json',
rootProperty: 'data'
},
writer: {
type: 'json'
}
}
});
And Grid:
Ext.define('MVC.view.NotesGrid', {
extend: 'Ext.grid.Panel',
xtype: 'notesGrid',
title: 'Note-list',
// store: 'Notes',
store: 'TestStore',
columns: [
{
text: 'Name',
dataIndex: 'name',
flex: 1
},
{
text: 'Creation Date',
xtype: 'datecolumn',
format: 'd-m-Y',
dataIndex: 'createDate',
flex: 1
},{
text: 'Last Modified',
xtype: 'datecolumn',
format: 'd-m-Y',
dataIndex: 'modifiedDate',
flex:1
}, {
text: 'Text',
dataIndex: 'noteText',
flex: 3
}
]
});
Not answering the main question, only your side question:
When you Ext.define() a store, you define the class.
When you Ext.create() a store, you define the instance.
The class won't be able to hold any data, only an instance can.
If you add your store's class name to the stores array in your application definition in the main Application.js file, you tell your application to create one global store instance of that class.
From a store class with a fixed store Id, you can only create one instance per application; from a store class without a fixed storeId, you can create multiple instances (e.g. one per grid).
Related
I'm just getting started with ExtJS and am looking to create a grid which will populate based on data it will receive from the server as a json. I'm having trouble understanding the architecture and how to separate information to correctly display on the grid view, since it seems much more complex and involved than if I were working in something like vanilla Javascript.
I currently have it working when the data has been hardcoded into the view here:
Ext.define('MyApp.view.main.Main', {
extend: 'Ext.container.Viewport',
requires: [
'MyApp.view.main.MainController',
'MyApp.view.main.MainModel',
'Ext.panel.Panel',
'Ext.grid.Panel'
],
/*
...Other containers and panels here
*/
xtype: 'grid',
width: '99%',
flex: 1,
store: {
fields:['name', 'email', 'address', 'hobby', 'notes'],
data:[
{ name: 'Rate', email: "rate#example.com",
address: "382 Kilmanjaro", hobby: "tennis", notes: "Lorem ipsum dolor.."},
{ name: 'Jimjam', email: "jim#example.com",
address: "889 McKinley", hobby: "none"}
],
proxy: {
type: 'memory'
}
},
columns: [
{ text: 'Name', dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email'},
{ text: 'address', dataIndex: 'address' },
{ text: 'hobby', dataIndex: 'hobby'},
{ text: 'Notes', dataIndex: 'notes', flex: 1, cellWrap: true}
]
}]
But I'd like to move the store and data out of the view, and ideally read from a json file (and later a GET request). Other questions I've seen have had a bunch of different methods to approach this but I find them all rather confusing and none seem to work for me, especially with different versions (I'm using ExtJS 5.1.2).
I'd appreciate any pointers in the right direction as to where to place my store and data and how to bind it correctly to the view. I think my main issues lie with usage of the associated Controller.js, Model.js, and Store.js files, and what kind of information goes in them.
Just updating that I got it working! I checked out the kitchen sink examples and old documentation from ExtJS4 to understand how the architecture worked.
My main issue was being new to ExtJS and attempting to create something while learning it at the same time, so I hope any other newbies can wrap their heads around this!
The basic idea is that there is a Model, Store, and View, and I've understood it as a Model being a class, a Store being a Collection of those objects, and the view being a display. A Store depends on a Model, and a View (at least, the grid I was building) depends on a Store. I tried to avoid separating too many views, writing javascript functions and overriding initComponent, but this was exactly what I had to do to get it working.
So I've written architecture like this:
model/Person.js:
Ext.define('MyApp.model.Person', {
extend: 'Ext.data.Model',
fields:['name', 'email', 'address', 'hobby', 'notes'],
proxy: {
type: 'ajax',
url: 'data/UserResponse.json',
reader: {
type: 'json',
rootProperty: 'results',
}
}
store/Persons.js:
Ext.define('MyApp.store.Persons', {
extend: 'Ext.data.Store',
/*Model for the store*/
requires: 'MyApp.model.Person',
model: 'MyApp.model.Person'
});
view/main/Main.js:
Ext.define('MyApp.view.main.Main', {
extend: 'Ext.container.Viewport',
requires: [
'Ext.panel.Panel',
'Ext.grid.Panel',
'MyApp.view.main.PersonGrid'
],
xtype: 'container',
controller: 'main',
viewModel: {
type: 'main'
},
layout: {
type: 'vbox',
align: 'center'
},
width: '100%',
items:
[{
xtype: 'panel',
flex: 1,
border: false,
width: '98%',
layout: {
type: 'vbox',
align: 'stretch'
},
items:
[{
xtype: 'panel',
height: 30,
margin: '5 5 1 5',
flex: 1,
width: '98%',
layout: {
type: 'vbox',
align: 'center'
},
title: 'Users - USA',
collapsible: true,
items: [
{
xtype: 'person-grid',
rootVisible: true,
store: 'Persons'
}]
}]
}]
});
view/main/PersonGrid.js:
Ext.define('MyApp.view.main.PersonGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.person-grid',
xtype: 'grid',
width: '99%',
flex: 1,
columns: [
{ text: 'Name', dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email'},
{ text: 'address', dataIndex: 'address' },
{ text: 'hobby', dataIndex: 'hobby'},
{ text: 'Notes', dataIndex: 'notes', flex: 1, cellWrap: true}
],
initComponent: function() {
//initComponent taken from http://examples.sencha.com/extjs/5.1.0/examples/kitchensink/#xml-grid
var me = this;
this.callParent();
this.on('afterlayout', this.loadStore, this, {
delay: 1,
single: true
});
},
loadStore: function() {
this.getStore().load();
}
});
data/UserResponse.json:
{
"success": true,
"results":[
{ name: 'Rate', email: "rate#example.com",
address: "382 Kilmanjaro", hobby: "tennis", notes: "Lorem ipsum dolor.."},
{ name: 'Jimjam', email: "jim#example.com",
address: "889 McKinley", hobby: "none"}
]
}
app/Application.js:
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
models: ['Person'],
stores: ['Persons'],
launch: function () {
// TODO - Launch the application
}
});
The main difference from what I was attempting before was to separate the grid into its own view, and edit the initComponent function here to load the store (which I wasn't doing earlier)! Earlier, I had the grid and its configurations nested within the items{} array of other components and trying to autoLoad the store, or utilize storeId and other methods of binding store to grid.
The above architecture works perfectly for me, and I am able to read data from my json file and mock responses from server! :)
In our application we have a lot of name/value stores, and they are created at load time and put into a JSONStore like so :
Ext.create("Ext.data.JsonStore", {
data: data,
model: 'EM.model.controlUnit.CodeList',
storeId: "cl_" + tableId,
sorters: [{
sorterFn: aSorterFunction
}],
});
The model is pretty simple and looks like this :
Ext.define('EM.model.controlUnit.CodeList', {
extend: 'Ext.data.Model',
fields: [{
name: 'value', type: 'int'
}, {
name: 'label', type: 'string'
}, {
name: 'description', type: 'string'
}]
});
I thought stores were pretty interchangeable so I decided to use the store in the combo (There is no special combo store so I thought a JSONStore must be as good as a SimpleStore). I get the store like so :
var msDataStore = Ext.getStore("cl_t_cl_maritalstatus");
And use the store like so :
{
xtype: 'combo',
fieldLabel: 'Marital Status',
displayField: "label",
valueField: "value",
store: msDataStore
}
The combo is filled with the values from the store when I run the application, however, when I pop down the combo box, this error is thrown :
ext-debug-w-comments.js:9951 Uncaught
Ext.data.proxy.Server.buildUrl(): You are using a ServerProxy but have
not supplied it with a url.
I do not want any server proxy. These are simple locally stored name value collections.
Can JSONStores be used with combos?
If not. What is the best way to convert a JSONStore into something acceptable for the combo. I can chop, change, restructure the store object. But I just want to know if there is something simpler that I can do before going on some kind of long and pointless journey.
This problem is related 'proxy' property. Default proxy for JsonStore is 'ajax';
proxy: {
type : 'ajax',
reader: 'json',
writer: 'json'
}
You should override with 'memory' like that;
proxy: {
type: 'memory'
}
Your final store is;
Ext.create("Ext.data.JsonStore", {
data: data,
model: 'EM.model.controlUnit.CodeList',
storeId: "cl_" + tableId,
proxy: {
type: 'memory'
}
sorters: [{
sorterFn: aSorterFunction
}],
});
A JsonStore without URL is completely acceptable, but you have to make sure the combo does not trigger a load operation when clicking on the dropdown. This is done by adding to the combo definition the config option queryMode:'local':
{
xtype: 'combo',
fieldLabel: 'Marital Status',
displayField: "label",
valueField: "value",
queryMode: 'local',
store: msDataStore
}
I am working on an app where loading all data from the beginning is not really an inconvenient.
I am getting json data from a server through Ajax, and my store for doing that is pretty simple:
Ext.define('MODIFE.store.CentroBeneficio', {
extend : 'Ext.data.Store',
requires : [
'MODIFE.model.CentroBeneficio'
],
storeId : 'CentroBeneficio',
model : 'MODIFE.model.CentroBeneficio',
page-size: 10,
proxy :{
//type: 'memory',
type: 'ajax',
enablePaging: true,
url: 'http://'+MODIFE.Global.ip+'/CentroBeneficio/GetCentroBeneficios'
},
autoLoad: true
});
This is my model:
Ext.define('MODIFE.model.CentroBeneficio', {
extend: 'Ext.data.Model',
storeId: 'CentroBeneficio',
pageSize: 10,
fields: [
{name:'IdCentroBeneficio', type:'int'},
{name:'CompaniaCodigo', type:'int'},
{name:'codigo', type:'string'},
{name:'description', type:'string'},
{name:'complete_description', type:'string', convert : function(v, record) {return record.data.codigo+' - '+record.data.description;}},
{name:'status', type:'int', convert : function(v, record) {return (record.data.status == 1) ? 'Activo' : 'Inactivo';}},
{name:'name_compania', type:'string'},
{name:'pais', type:'string'},
{name:'IdPais', type:'int'}
]
});
What I would like to achieve is paging the already loaded data. I tried specifying the type to 'memory' which didn't load anything as well as 'pagingmemory', wich caused the browser to die (I don't know why).
I have already the paging bar set up on my view:
{
xtype: 'grid',
id: 'centroBeneficioGrid',
title: getLabelByKey('CentroBeneficio_SearchGridTitle_Listado'),
store: 'CentroBeneficio',
columns: [
{ text: getLabelByKey('CentroBeneficio_SearchColumnGrid_Pais'), dataIndex: 'pais', flex: 2},
{ text: getLabelByKey('CentroBeneficio_SearchColumnGrid_Company'), dataIndex: 'name_compania', flex: 3},
{ text: getLabelByKey('CentroBeneficio_SearchColumnGrid_CentroBeneficio'), dataIndex: 'codigo', flex: 2},
{ text: getLabelByKey('CentroBeneficio_SearchColumnGrid_Descripcion'), dataIndex: 'description', flex: 4},
{ text: getLabelByKey('CentroBeneficio_SearchColumnGrid_Estatus'), dataIndex: 'status', flex: 2}
],
listeners: {
itemdblclick: 'CBSelectedGrid'
},
dockedItems: [{
xtype: 'pagingtoolbar',
store: 'CentroBeneficio',
dock: 'bottom',
displayInfo: true
}],
}
It shows up correctly but it just loads all data on the first page. Thanks in advance.
Paging of already loaded data is achieved with Ext.data.proxy.Memory configured with enablePaging: true. So what you need is to use two stores:
"Remote" store to merely load data from the server side;
Local paging store configured with memory proxy. The data will be loaded from the remote store once it loads itself:
pagingStore.getProxy().setData(remoteStore.getRange());
pagingStore.load();
Full working example: https://fiddle.sencha.com/#fiddle/pim
I don't know if this is a configuration issue in my app because I have done the same thing on one server which works perfectly. On a different web server I am trying to set up I am just trying to get an example working and I'm running into some extremely odd behavior. For some reason whenever the store loads it does a get request for a file that has the same name as the model name of the store. I don't understand why it's requesting a model file when the model is defined in the same file!? I didn't always have the model or store defined in the same file, they were in the proper directory structure but I moved them into one file to troubleshoot this issue and rule out possibilities but it's the same result, so for simplicity it's in the same file:
Ext.define('FPTModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'f1', type: 'int'},
{name: 'f2', type: 'string'},
]
});
Ext.define('appName.view.main.Main', {
extend: 'Ext.container.Container',
requires: [...my controller and viewModel are here...],
xtype: 'app-main',
initComponent: function() {
var myStore = Ext.create('Ext.data.Store', {
model: 'FPTModel',
data: [
{f1: 1, f2: 'someData'},
{f1: 2, f2: 'some more data'},
],
autoLoad: true
});
this.testStore = myStore;
this.callParent();
},
controller: 'main',
viewModel: {
type: 'main'
},
layout: {
type: 'border'
},
items: [{
region: 'center',
xtype: 'tabpanel',
items: [{
title: 'tab 1',
xtype: 'container',
layout: 'vbox',
items: [{
xtype: 'grid',
height: 300,
width: '100%',
columns: [
{header: 'Field 1', dataIndex: 'f1' },
{header: 'Field 2',dataIndex: 'f2'},
],
store: this.testStore
}]
}]
}]
});
When the page loads everything is fine and there are no errors. Whenever the store loads I see a GET request go out for https://my.site/FPTModel?_dc=1432862899334&page=1&start=0&limit=25
I know this is happening when the store loads because when I remove the autoLoad it doesn't send the get request and if I call testStore.load anywhere it does the get request.
This get request returns 404 obviously because that file doesn't exist. I don't understand why it's trying to load the model file from the server's root directory, or at all, when it's already defined. When I had this defined in it's proper directory structure (appName.model.FPTModel) then the get request was for .../appName.model.FPTModel...
I have been using extjs for about 2 years now and I have never seen anything like this.... Hoping someone out there can shed some light on this as it's driving me crazy. I hope there is something simple that I am missing somewhere...
This is because you do an Ext.define on the model.
Then Extjs is going to look in namespace of your app and tries to find the model FPTModel as an FPTModel.js file, because you used just "FPTModel", in the root of your app.
You should use Ext.create to create the model as a variable result and use that variable (containing the model object) in in your store. Or you should create an additional file with the model description in folder: appName/model/ and refer to it in the store.
But then you have to add a require config setting in your store to the model. Something like
require: ['appName.model.FPTModel']
You don't have to do this if you have add the model and store to the requires of your application.js in your app.
If you have no further needs for the model I would include the fields in the store definition.
I have done some restructuring of your object (not complete). I have added some panels for clarity. Don't use a border layout if you don't need one and avoid overdoing layouts and unneccessary nesting of panels.
I have added the function getGridStore which you can call with this.getGridStore(), to avoid functions like this.teststore = myStore.
So if you have to reload the store you simply do: this.getGridStore().load(), or in the application or view controller something like: this.getMainPanel.getGridStore().load().
The autoLoad config is not required, because the store already holds the data. It is only required if you load the data from a proxy (server).
Ext.define('appName.view.main.Main', {
extend: 'Ext.panel.Panel',
layout: 'border',
requires: [],
xtype: 'app-main',
controller: 'main',
viewModel: {
type: 'main'
},
initComponent: function () {
var myModel = Ext.create('Ext.data.Model', {
fields: [
{name: 'f1', type: 'int'},
{name: 'f2', type: 'string'},
]
});
var myStore = Ext.create('Ext.data.Store', {
model: myModel,
data: [
{f1: 1, f2: 'someData'},
{f1: 2, f2: 'some more data'},
],
autoLoad: true
});
Ext.applyIf(this, {
items: [{
region: 'center',
title: 'Center Panel',
flex: 3,
xtype: 'tabpanel',
items: [{
title: 'tab 1',
xtype: 'gridpanel',
layout: 'fit', // maybe not even neccessary
columns: [
{header: 'Field 1', dataIndex: 'f1'},
{header: 'Field 2', dataIndex: 'f2'},
],
store: myStore
}, {
xtype: 'panel',
html: 'Some other tab',
layout: 'fit'
}]
}, {
xtype: 'panel',
region: 'east',
flex: 1,
html: 'East panel',
title: 'East Panel'
}]
});
this.callParent();
},
getGridStore: function() {
return this.down('gridpanel').getStore();
}
});
Because you're specifying autoLoad, which is triggering the store to send a load request. Since you've not provided a URL for the proxy, it defaults to the name of the model. Remove autoLoad, it's redundant.
As part of my EXTJS 4 learning process, I am trying to establish a simple process of database connection - loading a value in a data Store - taking the value and placing it in a dataField.
The data is loaded fine from the php script and placed into the Store via a json call. (as confirmed through FireBug)
However, the dataField, does not seem to be able to load the value.
Here is what I have so far:
//Model definition
Ext.define('FingerModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'}
]
});
//Store Definition
var est_data = new Ext.data.Store({
model: 'FingerModel',
proxy: {
type: 'ajax',
url: 'finger.php',
extraParams: {opt: 'getName'},
reader: {
type: 'json',
root: 'results',
totalProperty: 'total'
}
},
autoLoad: true,
// turn off remote sorting
remoteSort: false
});
//Form definition
var fingerForm = Ext.create('Ext.form.Panel', {
width: 500,
title: 'Finger',
waitMsgTarget: true,
items: [{
xtype: 'fieldset',
title: 'Finger Form',
items: [{
xtype:'textfield',
fieldLabel: 'Location Name',
name: 'name'
}]
}]
});
fingerForm.getForm().loadRecord(FingerModel);
Anybody see anything obvious that I'm doing wrong?
Thanks in advance.
M.
Ext.form.field.Text does not have a 'store' property. How would it know which row of the store to use?
You should use Form.loadRecord() to load the model into the form, and it will set form fields with the same name as the model field names.