I have store which return data from server:
Ext.define('Admin.store.dashboard.NPS', {
extend: 'Ext.data.Store',
alias: 'store.nps',
autoLoad : false,
proxy : {
type: 'api',
url : SITE_URL + '/api/surveys/nps'
},
fields : [
{
type: 'float',
name: 'nps'
}
]
});
And I want to display that data in tpl of Ext.Component:
Ext.define('Admin.view.dashboard.NPSPercent', {
extend: 'Ext.Component',
xtype: 'nps-percent',
bind: {
data: {
nps_percent: '{nps}'
}
},
tpl: new Ext.XTemplate('<div class="percent">+{nps_percent.nps}</div>')
});
I tried bind data to loaded store but it dose not work.
Templates in components expect regular things like arrays, not stores. To render a template using a store as the datasource, use Ext.view.View class instead of just a component.
Related
Binding model property to a form field is pretty easy in ExtJS:
// ...skipped everything until fields config for brevity
}, {
xtype: 'textfield',
bind: '{modelInstance.someField}'
}, { // ...
In this case, modelInstance string field someField will be synchronized to textbox value, thanks to two way binding. And that is great.
What I want to achieve is to get same kind of behavior in the case when model field is not a string but an array. This is the model:
Ext.define('namespace.model.CustomModel', {
fields: ['easyField', {
name: 'hardField',
type: 'auto' // This will be an array during runtime
}],
idProperty: 'easyField'
});
I would like to do something like this:
// ...skipped everything until fields config for brevity,
// assume that viewmodel and everything else are set up as expected
}, {
xtype: 'textfield',
bind: '{modelInstance.easyField}'
}, {
xtype: 'gridfield',
bind: {
gridArray: '{modelInstance.hardField}'
}
}, { // ...
Understandably, I want gridfield component to extend Ext.grid.Panel and synchronize its store data to modelInstance field hardField.
Currently I have this:
Ext.define('namespace.form.field.GridField', {
extends: 'Ext.grid.Panel',
xtype: 'gridfield',
// skip requires for brevity
viewModel: {
stores: {
gridFieldItems: {
type: 'gridfielditems' // Simple in memory store
}
},
data: {
}
},
store: '{gridFieldItems}',
// This config enables binding to take place as it creates getters and setters,
// gridArray is set initially to '{modelInstance.hardField}' as expected
config: {
gridArray: null
},
// This is necessary for this grid-field component to update
// '{modelInstance.hardField}' back in the owners viewModel.
publishes: {
gridArray: true
},
// ???
// bind: {
// gridArray: bind gridArray to store data somehow?
// }
});
Here's the problem:
how do I inject existing modelInstance.hardField array as gridFieldItems store initial data,
how do I bind gridArray config to store data so that it is updates as we go along cruding the grid,
do all of these in an elegant MVVM way without writing a bunch of listeners trying to force syncing between JS objects.
Please provide tested solution which is known to work, I already tried a lot of different ways myself, but without success so far.
Here is a working fiddle to achieve this binding. The easy way is to bind the array field with "data" attribute of a store.
A good suggestion on the work you've done is to avoid defining a viewmodel inside a generic component (gridfield) but use viewmodels only on you application specific views.
On you generic component you should define only configuration attributes with setter/getter/update logics in order to be able to use them with bind. In this case there is no need of custom properties as the store is enough.
edit
To avoid the "easy binding" you can implement the set/get logic of the array in your girdfield component. Fore example using the "updateGridArray" method called by the setter and the "datachanged" event of the store.
The fiddle is updated and the example girdfield uses the cell editing plugin to show the 2-way binding.
fiddle: https://fiddle.sencha.com/#view/editor&fiddle/2a3b
Ext.define('Fiddle.model.CustomModel', {
extend: 'Ext.data.Model',
fields: ['easyField', {
name: 'hardField',
type: 'auto' // This will be an array during runtime
}],
idProperty: 'easyField'
});
Ext.define('Fiddle.fiddleview.CustomViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.fiddleview',
data: {
currentModel: null
}
});
Ext.define('Fiddle.form.field.GridField', {
extend: 'Ext.grid.Panel',
xtype: 'gridfield',
config: {
gridArray: null
},
publishes: [
'selection',
'gridArray'
],
selModel: 'cellmodel',
plugins: {
cellediting: {
clicksToEdit: 1
}
},
columns: [{
text: 'Column 1',
flex: 1,
editor: true,
dataIndex: 'field1'
}],
initComponent: function () {
this.store = {
fields: ['field1'],
data: [],
listeners: {
scope: this,
datachanged: function (store) {
this.setGridArray(store.getRange().map(function (record) {
return record.getData();
}));
}
}
};
this.callParent();
},
updateGridArray: function (gridArray) {
this.getStore().suspendEvent('datachanged');
if (Ext.isEmpty(gridArray)) {
this.getStore().removeAll();
} else {
this.getStore().loadData(gridArray);
}
this.getStore().resumeEvent('datachanged');
}
});
var myView = Ext.create('Ext.container.Container', {
renderTo: Ext.getBody(),
viewModel: 'fiddleview',
items: [{
xtype: 'gridfield',
bind: {
gridArray: '{currentModel.hardField}'
}
}]
});
// Bind on model's array to check two-way update
// It will execute also on cell edit
myView.getViewModel().bind('{currentModel.hardField}', function (value) {
window.alert('model\'s array changed');
});
// The binding is now active, when the "currentModel" in the viewmodel changes, grid rows are refresched
myView.getViewModel().set('currentModel', new Fiddle.model.CustomModel({
hardField: [{
field1: 'value1'
}]
}));
// Also when data changes in the "currentModel"
myView.getViewModel().get('currentModel').get('hardField').push({
field1: 'value2'
});
For some reason unknown to me, I cannot get my Ext JS store to display in my combobox
Here's my model:
Type.js
Ext.define('AM.model.Type', { //app name config is "AM"
extend: 'Ext.data.Model',
fields: [
{ name: 'field', type: "string" }
]
});
And my store:
Type.js
Ext.define('AM.store.Type', {
extend: 'Ext.data.Store',
model: 'AM.model.Type',
storeId: 'typestore',
data: [
{ field: 'Bobby' },
{ field: 'Jimbo' },
{ field: 'Craig' }
]
});
And where I call it:
app.js
{ xtype: 'combobox', padding: 5, store: Ext.getStore('typestore'), displayField: 'field'}...
Any ideas?
I don't see anything wrong here. The problem is probably elsewhere.
I have created a sample fiddle with your code slightly simplified, and it works fine.
http://jsfiddle.net/dbrin/28sX7/
I solved the problem by instantiating my store class with into a variable using Ext.Create
and setting my comboboxes queryMode to local (remote would display the data but keep on loading and loading).
I'm trying to display NestedList with json on my hard disk, but it is not displayed. What am I doing wrong? No bugs in Chrome. (Chrome open with Applications / Google \ Chrome.app / Contents / MacOS / Google \ Chrome - allow-file-access-from-files). I get a blank screen without a single error in the console. If I comment fullscreen: true, in MyPanel.js I get clear NestedList without any data.
Servlet.json
{
"stream":[{
"post_id": "1",
"post_type": "text",
"post_thumb": "bla1"
}]
}
MyPanel.js
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.dataview.NestedList',
alias : 'widget.MyPanel',
config: {
store : 'Storere',
title: 'NestedList Example',
detailCard: {
html: 'You can see detail information here!'
}
}
});
Storere.js
Ext.define('MyApp.store.Storere', {
extend: 'Ext.data.TreeStore',
config: {
model: 'MyApp.model.MyModel',
defaultRootProperty : 'stream',
proxy: {
type: 'ajax',
url: '.\/app\/Servlet.json',
reader: {
type: 'json',
rootProperty: 'stream'
}
}
}
});
MyModel.js
Ext.define('MyApp.model.MyModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name:'post_id', type: 'string' },
{name:'post_type', type: 'string' },
{name:'post_thumb', type: 'string' }
]
}
});
TheWorld.js
Ext.define('MyApp.controller.TheWorld', {
extend : 'Ext.app.Controller',
config: {
profile: Ext.os.deviceType.toLowerCase(),
control: {
'MyPanel': {
activate: 'onActivate',
leafitemtap: 'onDetailDisplay'
}
}
},
onActivate: function() {
console.log('Main container is active');
},
onDetailDisplay: function(nestedList, list, index, target, record) {
console.log('onDetailDisplay is active');
var detailCard = nestedList.getDetailCard();
},
onItemTap: function(view, list, index, target, record, event) {
console.log('Item was tapped on the Data View');
},
init: function() {
console.log('Controller initialized');
},
});
UPD:
You need to change NestedList config to following.
config: {
store : 'Storere',
//displayField:'post_type',
title: 'NestedList Example',
listConfig : {
itemTpl: '{post_type}'
},
detailCard: {
html: 'You can see detail information here!'
}
}
There is this displayField config of NestedList where you can specify which field to be used to set title and item text . By default it is set to text but you can specify it to be one of your model field. If you are overriding getItemTextTpl or getTitleTextTpl, this config will be ignored.
Plus there's listConfig config option available where you can mention itemTpl config. As json is having multiple fields with image and text nodes I assume you want to show that too.
So you can have listConfig something like following :
listConfig: {
itemTpl: '<div><img src="{post_thumb}">{post_type}</div>'
},
Reasons of list was not getting displayed might be-
Store is not loaded with proper data. ( To make sure inspect Network tab in chrome to see if Servlet.json present.
displayField and/or listConfig not mentioned.
I use ExtJs 4.1 and DeftJS. I use a grid with data from a store in a window. The data from the store should be reloaded when opening the window, and when closing it should be cleared.
However if even If I refresh the browser, and also after restarting the browser, the same old data is still in the grid. Hows that possible?
How to clear the store?
My store looks like this:
Ext.define( 'XXX.plugins.monitor.store.GridLogfiles', {
extend : 'Ext.data.Store',
mixins: [
'Deft.mixin.Injectable'
],
destroy: function() {
return this.callParent( arguments );
},
// model: Deft.Injector.resolve('modelGridLogfiles'),
model: 'XXX.plugins.monitor.model.GridLogfiles',
proxy : {
type : 'ajax',
url : 'XXX:8090/devel/phi/dev/04-presentation/von_kay/http-api/HEAD/index.php',
extraParams: {
user : 'test',
pass : 'test',
vers : 'extjs.json',
module : 'monitor',
func : 'getLogfiles'
},
reader : {
type: 'json',
root: 'list',
// root: 'list.getLogFiles',
// root: 'getLogfiles',
successProperty:false
}
}
, autoLoad: true
} );
My model like this:
Ext.define( 'XXX.plugins.monitor.model.GridLogfiles', {
extend: 'Ext.data.Model',
mixins: [
'Deft.mixin.Injectable',
],
destroy: function() {
return this.callParent( arguments );
},
fields: [ {name: 'key'}, {name: 'value'} ]
// fields: [ { name : 'value' } ]
} );
In my window I bind the store with:
,items: [{
xtype: 'grid',
itemId: 'gridlogfiles',
store: Deft.Injector.resolve('storeGridLogfiles'),
...
Problem fixed, was a mistake on root in my store.
I have created navigaton view using Sencha touch 2. Navigation view has list component which i want to load it using store and model. I created model and store as required. On running my app the list does not render any data.
It also gives warning in conolse [Ext.dataview.List#applyStore] The specified Store cannot be found . I am not sure what this error means.
Here is my mvc code,
model:
Ext.define('GS.model.BlogModel', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'title', type: 'auto'},
{name: 'author', type: 'auto'},
{name: 'content', type:'auto'}
]
}
});
store:
Ext.define('GS.store.blogs',{
extend:'Ext.data.Store',
config:{
model:'GS.model.BlogModel',
autoLoad :true,
proxy:{
type:'jsonp',
url:'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/SenchaBlog',
reader:{
type:'json',
rootProperty:'responseData.feed.entries'
}
}
}
});
view:
Ext.define('GS.view.Blog',{
extend:'Ext.navigation.View',
xtype:'blog',
requires:[
'Ext.dataview.List',
'Ext.data.proxy.JsonP',
'Ext.data.Store',
'GS.store.blogs'
],
config: {
title:'Blog',
iconCls:'star',
items:{
xtype:'list',
itemTpl:'{title}',
title:'Recent Posts',
store:'GS.store.blogs'
}
}
});
Can someone point me out what is missing/
Any help appreciated.
The store property in items for your list needs to be an instance, not the name of the class. GS.store.blogs is the class name. You need to create an instance of this class using Ext.create and pass that instance in items. Oh yeah, and your syntax for items is wrong too. Needs to be an array [] not an object {}. So something like:
var blogsStore = Ext.create("GS.store.blogs"); //put this in the items list
Ext.define('GS.view.Blog',{
extend:'Ext.navigation.View',
xtype:'blog',
requires:[
'Ext.dataview.List',
'Ext.data.proxy.JsonP',
'Ext.data.Store',
'GS.store.blogs'
],
config: {
title:'Blog',
iconCls:'star',
items:[{
xtype:'list',
itemTpl:'{title}',
title:'Recent Posts',
store: blogsStore //Store instance here. And items are in array, not Object
}]
}
});