I have a template column in a grid which I am rendering a sparkline graph to: http://omnipotent.net/jquery.sparkline and when I sort the grid the canvas element that is rendered by the plugin is destroyed. Is there a way to stop the contents of a row being altered during a sort? I'm using ExtJS 4.2.3
Libraries:
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="//omnipotent.net/jquery.sparkline/2.1.2/jquery.sparkline.min.js"></script>
Code:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create("Ext.grid.Panel", {
store: new Ext.data.Store({
data: [
{
thing: '1'
},
{
thing: '1'
},
{
thing: '1'
},
{
thing: '1'
},
{
thing: '1'
}
],
fields: [
"thing"
]
}),
columns: [
{
text: 'Hello',
xtype: 'templatecolumn',
tpl: Ext.create('Ext.XTemplate', "<div id='1'></div>"),
flex: 1
},
{
text: 'Other',
flex: 1,
dataIndex: 'thing'
}
],
renderTo: Ext.getBody(),
listeners: {
boxready: function() {
$('#1').sparkline([1,2,3,4,5,6,7,8,9,10])
}
}
});
}
});
sortchange
listeners: {
boxready: function() {
$('#1').sparkline([1,2,3,4,5,6,7,8,9,10])
},
sortChange: function() {
// your logic here
}
}
Related
I had a extJS fiddle which will alert the user when the checkbox is clicked.
Here is the code:
Ext.application({
name : 'Fiddle',
launch : function() {
var myStore = Ext.create('Ext.data.Store',{
data: [
{
name: 'ex',
oldUser: 'Y'
},
{
name: 'ea',
oldUser: 'N'
}
],
fields: [
{
name: 'name'
},
{
name: 'oldUser'
}
]
});
Ext.create('Ext.grid.Panel', {
height: 250,
width: 579,
title: 'My Grid Panel',
renderTo: Ext.getBody(),
defaultListenerScope: true,
store: myStore,
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'Name'
},
{
xtype: 'checkcolumn',
dataIndex: 'oldUser',
text: 'OldUser',
listeners: {
// problem here!
beforecheckchange: function(checkcolumn, rowIndex, checked, eOpts) { alert("asd"); }
}
}
]
});
}
});
The beforecheckchange event will fire when I use extjs 4.2.0 and onward, but it won't fire when I used extjs 4.1.1 and versions before that.
But when I check the api doc for version 4.1.1, beforecheckchange is listed as an event I could use.
I want to know why the above example doesn't work for 4.1.1
Looks like You have to add CheckColumn manually:
var myCheckColumn = Ext.create('Ext.ux.CheckColumn',{
text: 'OldUser',
dataIndex: 'oldUser',
listeners: {
beforecheckchange: function(checkcolumn, rowIndex, checked, eOpts) { alert(checked); }
}
});
Try this fiddle:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.Loader.setConfig({enabled:true});
var myStore = Ext.create('Ext.data.Store',{
data: [
{
name: 'ex',
oldUser: true
},
{
name: 'ea',
oldUser: false
}
],
fields: [
{
name: 'name'
},
{
name: 'oldUser'
}
]
});
var myCheckColumn = Ext.create('Ext.ux.CheckColumn',{
text: 'OldUser',
dataIndex: 'oldUser',
listeners: {
beforecheckchange: function(checkcolumn, rowIndex, checked, eOpts) { alert(checked); }
}
});
Ext.create('Ext.grid.Panel', {
height: 250,
width: 579,
title: 'My Grid Panel',
renderTo: Ext.getBody(),
defaultListenerScope: true,
store: myStore,
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'Name'
},
myCheckColumn
]
});
}
});
But, there can be a problem to render checkbox. Change background-image in CheckHeader.css or create new and add it into application.
CheckHeader.css:
.x-grid-checkheader {
height: 14px;
background-image: url('images/unchecked.gif');
background-position: 50% -2px;
background-repeat: no-repeat;
background-color: transparent;
}
.x-grid-checkheader-checked {
background-image: url('images/checked.gif');
}
.x-grid-checkheader-editor .x-form-cb-wrap {
text-align: center;
}
I have a grid panel which shows all my users from my database.
I want my grid items(rows) to be clickable, as something to happen when i click on them but it doesn't seem like the listener is ok.
Ext.define('PRJ.view.Home', {
extend: 'Ext.panel.Panel',
alias: 'widget.home',
title: 'Home',
layout: 'fit',
items: [
{
xtype: 'gridpanel',
store: 'Users',
title: 'Users grid',
columns: [
{text: 'Id', dataIndex: 'id' },
{text: 'Name', dataIndex: 'name', width : 200 }
]
}
]
});
Ext.define('PRJ.controller.Menu', {
extend: 'Ext.app.Controller',
refs: [
{
ref: 'centerPanel',
selector: '#center-panel'
}
],
stores: ["Users"
],
init: function() {
this.control({
'gridpanel': {
itemdblclick: this.editUser
}
});
},
editUser: function() {
alert('User double clicked');
},
});
This may just be as simple as changing itemdblclick to rowdblclick.
I have created a fiddle here showing a slightly different approach (by adding listeners in the config). Code below:
Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: Ext.data.StoreManager.lookup('simpsonsStore'),
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
listeners: {
rowdblclick: function(grid, record, tr, rowIndex, e, eOpts) {
alert(record.get("name"));
}
},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
You should also look at Selection Model and Row Editing.
You can use cell editing plugin to make cells editable on click.
Include something like this in your grid conf :
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1,
pluginId: 'cellEditor'
})
]
I found out what the problem was.
The answers I got were not helping, because I needed to keep the listener in the controller instead of moving it to the view.
The problem was that I needed to put the listener on home gridpanel like
init: function() {
this.control({
'home gridpanel': {
itemdblclick: this.editUser
}
});
},
Now it works like charm.
My problem is very similar to this question:
ExtJS4 gridPanel data not showing
but in a bit difference in syntax & behaviour, I've spent day(s) to solve by trying in many ways but failed.
Please note that: i must keep the SharpKit.NET generation behavior by calling parent constructor instead of json field construction, like the code bellow
Ext.define("Core.Scripts.model.Book", {
extend: "Ext.data.Model",
fields: ["title", "pages"] // Do not use this
});
Ext.define("Core.Scripts.model.Book", {
extend: "Ext.data.Model",
constructor: function () {
this.callParent([{ fields: ["title", "pages"] }]); // Use this
}
});
This is link to my simplified version on jsfiddle http://jsfiddle.net/thanhptr/LqXan/. Bellow is my copied code, this code still does not fix:
Ext.define("Core.Scripts.model.Book", {
extend: "Ext.data.Model",
constructor: function () {
this.callParent([{ fields: ["title", "pages"] }]);
}
});
Ext.define("Core.Scripts.store.Store", {
extend: "Ext.data.Store",
constructor: function () {
this.callParent([{
model: "Core.Scripts.model.Book",
data: [
{ title: "book 1", pages: 10 },
{ title: "book 2", pages: 20 }
]
}]);
}
});
Ext.define("Core.Scripts.view.GridPanel", {
extend: "Ext.grid.Panel",
constructor: function () {
this.callParent([{
store: new Core.Scripts.store.Store(),
region: "center",
columns: [
{ header: "title", dataIndex: "title" },
{ header: "pages", dataIndex: "pages" }
]
}]);
}
});
Ext.define("Core.Scripts.view.DetailViewport", {
extend: "Ext.container.Viewport",
constructor: function () {
this.callParent([{
frame: true,
layout: "border",
items: [new Core.Scripts.view.GridPanel()]
}]);
}
});
Ext.onReady(function () {
var viewPort = new Core.Scripts.view.DetailViewport();
});
I couldn't get your example working either, but I changed some code up and got it to work.
Ext.define("Core.Scripts.model.Book", {
extend: "Ext.data.Model",
fields: ["title", "pages"]
});
Ext.define("Core.Scripts.store.Store", {
extend: "Ext.data.Store",
model: "Core.Scripts.model.Book",
data: [
{ title: "book 1", pages: 10 },
{ title: "book 2", pages: 20 }
]
});
Ext.define("Core.Scripts.view.GridPanel", {
extend: "Ext.grid.Panel",
region: "center",
height: '200',
store: Ext.create('Core.Scripts.store.Store'),
columns: [
{ header: "title", dataIndex: "title" },
{ header: "pages", dataIndex: "pages" }
]
});
Ext.define("Core.Scripts.view.DetailViewport", {
extend: "Ext.container.Viewport",
frame: true,
layout: "border",
initComponent: function () {
this.items = [new Core.Scripts.view.GridPanel];
this.callParent(arguments);
}
});
Ext.onReady(function () {
var viewPort = new Core.Scripts.view.DetailViewport();
});
I've read a tutorial about creating DataView with custom comonent for each element from Store. It says about mapping fields of record to components in DataItem, but my question is how to define order in which components will be added to DataItem.
For example, I have such DataItem:
Ext.define('demo.view.CottageItem', {
extend: 'Ext.dataview.component.DataItem',
requires: ['Ext.Label', 'Ext.Array', 'Ext.Img'],
xtype: 'listitem',
config: {
layout: {
type: 'hbox',
align: 'center',
pack: 'start',
},
title: {
flex: 1
},
photo: {
width: '140px',
height: '140px'
},
dataMap: {
getTitle: {
setHtml: 'title'
},
getPhoto: {
setSrc: 'photo'
}
},
styleHtmlContent: true
},
applyTitle: function(config) {
return Ext.factory(config, Ext.Label, this.getTitle());
},
updateTitle: function(newTitle, oldTitle) {
if (oldTitle) {
this.remove(oldTitle);
}
if (newTitle) {
this.add(newTitle);
}
},
applyPhoto: function(config) {
return Ext.factory(config, Ext.Img, this.getPhoto());
},
updatePhoto: function(newImage, oldImage) {
if (oldImage) {
this.remove(oldImage);
}
if (newImage) {
this.add(newImage);
}
},
});
It has layout type hbox, so I want photo to be added first and then title. So that title would be to the right of the photo. How can I achieve this?
Another question is, is there a way to add another container inside this DataItem, in which can be inserted my Label and Image?
UPDATE:
Now my layout looks like this:
|Label(title)| |Image(Photo)|
I want it look like this:
|Image(photo)| |Label(title)|
Finally I understood how to solve my problem, here is my code:
Ext.define('demo.view.CottageItem', {
extend: 'Ext.dataview.component.DataItem',
requires: ['Ext.Label', 'Ext.Array', 'Ext.Img'],
xtype: 'listitem',
config: {
layout: {
type: 'hbox',
align: 'center',
pack: 'start',
},
title: {
style: {
'font-weight': 'bold'
}
},
photo: {
width: '140px',
height: '140px'
},
desc: {},
dataMap: {
getTitle: {
setHtml: 'title'
},
getPhoto: {
setSrc: 'photo'
},
getDesc: {
setHtml: 'desc'
},
},
styleHtmlContent: true,
items: [
{
xtype: 'panel',
itemId: 'photoContainer',
},
{
xtype: 'panel',
layout: {
type: 'vbox'
},
itemId: 'textContainer',
flex: 1,
}
],
},
applyTitle: function(config) {
return Ext.factory(config, Ext.Label, this.getTitle());
},
updateTitle: function(newTitle, oldTitle) {
if (oldTitle) {
this.getComponent('textContainer').remove(oldTitle);
}
if (newTitle) {
this.getComponent('textContainer').add(newTitle);
}
},
applyPhoto: function(config) {
return Ext.factory(config, Ext.Img, this.getPhoto());
},
updatePhoto: function(newImage, oldImage) {
if (oldImage) {
this.getComponent('photoContainer').remove(oldImage);
}
if (newImage) {
this.getComponent('photoContainer').add(newImage);
}
},
applyDesc: function(config) {
return Ext.factory(config, Ext.Label, this.getDesc());
},
updateDesc: function(newDesc, oldDesc) {
if (oldDesc) {
this.getComponent('textContainer').remove(oldDesc);
}
if (newDesc) {
this.getComponent('textContainer').add(newDesc);
}
},
});
Instead of adding components to root, I defined two panels (placeholders) inside DataItem. I access them using getComponent method and add my component to desired place. The only problem here is that order of items added to textContainer is undefined, but in my case I got desired order.
Change sort order of the backend store? I'm not sure about component based DataView, but element-based matches to store sorting.
To properly set (or change) sorting you have to read Store's config sorters property or sort function
Cheers, Oleg
I'm having trouble understanding how I need to define and use the MVC model for my test EXTjs4 app. Consider the following structure.
app.js
Ext.application({
name: 'AM',
appFolder: 'app',
controllers: ['Cards', 'Fourscrum'],
launch: function () {
Ext.create('Ext.container.Viewport', {
defaults: { flex: 1 },
layout: {
type: 'hbox',
align: 'stretch',
},
items:
[
Ext.widget('Fourscrum')
]
});
Controller:
Cards.js
Ext.define('AM.controller.Cards', {
extend: 'Ext.app.Controller',
stores: ['BacklogCards', 'InprogressCards', 'ReviewCards', 'DoneCards', 'Cards', 'Priorities', 'Sizes'],
models: ['Card', 'Priority', 'Size'],
views: ['card.List', 'priority.prioritycombo', 'card.Edit'],
Fourscrum.js
Ext.define('AM.controller.Fourscrum', {
extend: 'Ext.app.Controller',
stores: ['BacklogCards', 'InprogressCards', 'ReviewCards', 'DoneCards', 'Cards', 'Priorities', 'Sizes'],
models: ['Card', 'Priority', 'Size'],
views: ['scrum.Fourscrum', 'card.List'],
view.scrum.Fourscrum.js
Ext.define('AM.view.scrum.Fourscrum', { // *** Variable
extend: 'Ext.panel.Panel',
alias: 'widget.Fourscrum', // *** Variable
width: 400,
height: 300,
layout: 'column',
title: 'Scrum', // *** Variable
items:
[
Ext.widget('cardlist',
{
alias: 'widget.backlogcardlist',
title: "Backlog",
store: 'BacklogCards'
}),
Ext.widget('cardlist',
{
alias: 'widget.backlogcardlist',
title: "Backlog",
store: 'BacklogCards'
}),
Ext.widget('cardlist',
{
alias: 'widget.inprogresscardlist',
title: "In Progress",
store: "InprogressCards"
}),
Ext.widget('cardlist',
{
alias: 'widget.reviewcardlist',
title: "Review",
store: "ReviewCards"
}),
Ext.widget('cardlist',
{
alias: 'widget.donecardlist',
title: "Done",
store: "DoneCards"
})
]
});
My ideal structure for this app is as follows:
Viewport defined (inside app.js)
which contains a Fourscrum.js view (which is just a panel)
which contains 4 different List.js views (which are just grids).
Trying to accomplish this, I currently get a few errors when i start messing with the above code:
Item undefined
namespace undefined
Does anyone know why this doesn't work?
PS. I can get this example to work if I replace my 'cardlist' widgets with panels directly defined in the Fourscrum view.
PPS. This also works properly if I forego the Fourscrum container panel all together :(
EDIT:
I felt my explanation was a little unclear so I've uploaded an image to help describe the program. I'm not sure where I need to define the stores, models, and views with this nested structure. So I've repeated it in both controllers. I hope that's not what is causing the problem.
EDIT2:
Ext.define('AM.view.card.List', {
extend: 'Ext.grid.Panel',
alias: 'widget.cardlist',
//title: 'List',
//store: 'Cards',
//multiSelect: true,
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragGroup: 'ddzone',
dropGroup: 'ddzone'
}
},
// selType: 'cellmodel',
// plugins: [
// Ext.create('Ext.grid.plugin.CellEditing', {
// clicksToEdit: 1
// })
// ],
columns: [
{
header: 'ID',
dataIndex: 'external_id',
field: 'textfield',
width: 30
},
{
header: 'Name',
dataIndex: 'name',
field: 'textfield',
width: 150
},
{
header: 'Priority',
dataIndex: 'priority_id',
renderer: function (value) {
var display = '';
Ext.data.StoreManager.get("Priorities").each(function (rec) {
if (rec.get('id') === value) {
display = rec.get('short_name');
return false;
}
});
return display;
},
width: 60,
field: { xtype: 'PriorityCombo' }
},
{
header: 'Size',
dataIndex: 'size_id',
renderer: function (value) {
var display = '';
Ext.data.StoreManager.get("Sizes").each(function (rec) {
if (rec.get('id') === value) {
display = rec.get('short_name');
return false;
}
});
return display;
},
width: 60
},
{
xtype: 'actioncolumn',
width: 16,
items: [{
icon: 'Styles/Images/zoom.png', // Use a URL in the icon config
tooltip: 'Zoom In',
handler: function (grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
alert("Edit " + rec.get('name'));
}
}]
}
]
});
I think I see a big problem in your code (if you pasted all of it).
In your view definitions if you are extending Ext components you MUST have the following function that ends in the callParent method like below.
initComponent: function() {
this.items = this.buildMyItems();
this.callParent(arguments);
},
buildMyItems: function(){
//my code
}
Robodude,
According to the Class guide on Sencha.com all widgets must be contained in properly named class files. I don't think you can simultaneously define and create your widgets in the panel definition.
Split out your definitions from the panel config. Also dont forget to enable the auto loader:
Ext.Loader.setConfig({
enabled : true
});