Hey there,
I would like to be able to drag an item (bookmark) from a grid to a tree (categories) but I don't want the dropped bookmark-item to be added to the categories-tree as a new node and I don't want it to be removed from the grid. I just want to catch the dropnode-event and update the category-id of the bookmark.
How can this be done? What I've got so far is the following:
http://jsfiddle.net/suamikim/A3T6W/
Ext.onReady(function() {
// define model for tree
Ext.define('Category', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int' },
{ name: 'parentCatId', type: 'int' },
{ name: 'name', type: 'string' }
]
});
// define model for grid
Ext.define('Bookmark', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int' },
{ name: 'catId', type: 'int' },
{ name: 'title', type: 'string' },
{ name: 'url', type: 'string' }
]
});
// Create the tree-panel
var catTree = Ext.create('Ext.tree.Panel', {
itemId: 'catTree',
title: 'Categories',
flex: 0.5,
hideHeaders: true,
rootVisible: false,
allowDeselect: true,
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
dropGroup: 'bkmDDGroup',
enableDrag: false,
appendOnly: true
}
},
store: Ext.create('Ext.data.TreeStore', {
model: 'Category',
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'categories'
}
}
}),
root: [],
columns: [{
xtype: 'treecolumn',
dataIndex: 'name',
flex: 1
}],
listeners: {
afterrender: function(tree) {
var root = tree.getRootNode();
// load static data
root.appendChild([{
id: 0,
parentCatId: -1,
name: 'Cat1',
expanded: true,
categories: [{
id: 2,
parentCatId: 0,
name: 'Cat1.1',
categories: []
},{
id: 3,
parentCatId: 0,
name: 'Cat1.2',
categories: []
}]
},{
id: 1,
parentCatId: -1,
name: 'Cat2',
categories: []
}]);
// select the first item
tree.getSelectionModel().select(root.getChildAt(0));
},
selectionChange: function(model, selected, opts) {
bkmGrid.filterBookmarks((selected && selected[0]) ? selected[0].get('id') : -1);
}
}
});
// Create the grid-panel
var bkmGrid = Ext.create('Ext.grid.Panel', {
itemId: 'bkmGrid',
title: 'Bookmarks',
flex: 1,
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragGroup: 'bkmDDGroup'
}
},
store: Ext.create('Ext.data.Store', {
model: 'Bookmark',
proxy: {
type: 'memory'
},
data: [
{ id: 0, catId: 0, title: 'bkm1', url: 'http://www.url1.com' },
{ id: 1, catId: 0, title: 'bkm2', url: 'http://www.url2.com' },
{ id: 2, catId: 1, title: 'bkm3', url: 'http://www.url3.com' },
{ id: 3, catId: 1, title: 'bkm4', url: 'http://www.url4.com' },
{ id: 4, catId: 2, title: 'bkm5', url: 'http://www.url5.com' },
{ id: 5, catId: 3, title: 'bkm6', url: 'http://www.url6.com' }
]
}),
columns: [{
text: 'Title',
dataIndex: 'title',
flex: 0.7
},{
text: 'URL',
dataIndex: 'url',
flex: 1,
renderer: function(value, meta) {
meta.tdAttr = 'data-qtip="' + value + '"';
return '' + value + '';
}
}],
filterBookmarks: function(catId) {
var store = this.getStore();
store.clearFilter();
if (catId >= 0) {
store.filter('catId', catId);
}
}
});
// Create window which holds the dataview
Ext.create('Ext.window.Window', {
width: 500,
height: 300,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [ catTree, bkmGrid ]
}).show();
});
This throws the following exception after dropping a bookmark on the tree:
"Uncaught TypeError: Object [object Object] has no method 'updateInfo'"
The exception is thrown in the appendChild-method which finally shouldn't be called at all. Therefore the exception doesn't matter but how can i prevent the tree from trying to add a new node after the drop?
Thanks
I just found a solution which looks like this:
http://jsfiddle.net/suamikim/A3T6W/4/
The "magic" is to just delete the records-array in the beforedrop-listener. Before deletion i saved the array to a custom config-object of my tree (this.droppedRecords) to be able to access the data again in the drop-listener:
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
dropGroup: 'bkmDDGroup',
enableDrag: false,
appendOnly: true
},
listeners: {
beforedrop: function(node, data, overModel, dropPos, opts) {
this.droppedRecords = data.records;
data.records = [];
},
drop: function(node, data, overModel, dropPos, opts) {
var str = '';
Ext.iterate(this.droppedRecords, function(record) {
str += record.get('title') + ' (id = ' + record.get('id') + ') dropped on ' + overModel.get('name') + '\n';
});
alert(str);
this.droppedRecords = undefined;
}
}
},
That's it.
Thanks
Related
Through ViewModel stores I'm getting this JSON data;
{
"success": true,
"msg": "OK",
"count": 2,
"data": [
{
"firstname": "BLA",
"lastname": "BLALA",
"isactive": true,
...
},
{
"firstname": "BLAAA",
"lastname": "BLALAAA",
"isactive": false,
...
}
I have two grids on one panel and one of them will load data only with isactive: true field, other grid will load only with false. So where and how I need to filtering store to load specified data to grids?
Here is VM;
Ext.define('MyApp.view.ListingVM', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.listing',
requires: [...],
reference: 'loyaltyvm',
stores: {
// Should I define the filter on here?
bonusTrans: {
storeId: 'bonusTrans',
// reference: 'bonusTrans',
model: 'MyApp.model.BonusTrans',
autoLoad: true,
session: true,
pageSize: MyApp.Globals.LIST_PAGE_SIZE
}
}
});
This is panel's grid sample where defined both of Grids. I've tried several way to get store and filtering but couldn't be succes;
getColumns: function () {
var me = this;
var panelItems = [
{
xtype: 'container',
layout: {type: 'hbox', align: 'stretch', pack: 'start'},
items: [
xtype: 'bonustrans',
flex: 1,
title: 'Current Bonus',
getListCols: function () {
var me = this;
debugger;
// var activeStore = Ext.getStore('bonusTrans');
// var activeStore = me.viewModel.get('bonusTrans');
// var view = me.getView();
// var vm = view.getViewModel();
// var vm.getStore('bonusTrans')
// var activeStore = me.getViewModel().getStore('bonusTrans');
var activeStore = me.getViewModel('loyaltyvm').getStores('bonusTrans');
activeStore.filter('isactive', 'true');
var listCols = [
{
xtype: 'firstnamecol',
flex: 1
},
{
xtype: 'checkoutcol'
},
{
xtype: 'bonustotalcol'
}
];
return listCols;
}
//... other Grid is just defined below of this line and it should loads data only with 'isactive' field is false.
Use chained stores, fiddle:
Ext.application({
name : 'Fiddle',
launch : function() {
new Ext.container.Viewport({
layout: {
type: 'hbox',
align: 'stretch'
},
viewModel: {
stores: {
everything: {
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data1.json'
}
},
active: {
type: 'chained',
source: '{everything}',
filters: [{
property: 'active',
value: true
}]
},
inactive: {
type: 'chained',
source: '{everything}',
filters: [{
property: 'active',
value: false
}]
}
}
},
items: [{
flex: 1,
xtype: 'gridpanel',
title: 'Active',
bind: '{active}',
columns: [{
dataIndex: 'name'
}]
}, {
flex: 1,
xtype: 'gridpanel',
title: 'Inactive',
bind: '{inactive}',
columns: [{
dataIndex: 'name'
}]
}]
});
}
});
The way of chained stores is surely the best,
here you can see a working fiddle on classic
and here is the code:
Ext.application({
name: 'Fiddle',
launch: function () {
var storeAll = Ext.create('Ext.data.Store', {
storeId: 'storeAll',
fields: [{
name: 'firstname'
}, {
name: 'lastname'
}, {
name: 'active'
}],
data: [{
firstname: 'test1',
lastname: 'test1',
active: true
}, {
firstname: 'test2',
lastname: 'test2',
active: true
}, {
firstname: 'test3',
lastname: 'test3',
active: false
}]
}),
chainedStoreActive = Ext.create('Ext.data.ChainedStore', {
source: storeAll,
filters: [{
property: 'active',
value: true
}]
}),
chainedStoreNoActive = Ext.create('Ext.data.ChainedStore', {
source: storeAll,
filters: [{
property: 'active',
value: false
}]
});
Ext.create({
xtype: 'viewport',
layout: {
type: 'vbox',
align: 'stretch'
},
items: [{
xtype: 'gridpanel',
title: 'grid ALL',
store: storeAll,
columns: [{
text: 'First Name',
dataIndex: 'firstname'
}, {
text: 'Last Name',
dataIndex: 'lastname'
}],
flex: 1
}, {
xtype: 'gridpanel',
title: 'grid active',
store: chainedStoreActive,
columns: [{
text: 'First Name',
dataIndex: 'firstname'
}, {
text: 'Last Name',
dataIndex: 'lastname'
}],
flex: 1
}, {
xtype: 'gridpanel',
title: 'grid inactive',
store: chainedStoreNoActive,
columns: [{
text: 'First Name',
dataIndex: 'firstname'
}, {
text: 'Last Name',
dataIndex: 'lastname'
}],
flex: 1
}],
renderTo: Ext.getBody()
});
}
});
The global or the "allelements" store, need to be a global store, the chained ones can be created in a viewmodel of a view.
I have view name PurchaseReport.js
Ext.define("App.view.tabs.PurchaseReport", {
extend: "Ext.panel.Panel",
alias: "widget.PurchaseReportTab",
requires: [
"App.model.PurchaseReport", "Ext.toolbar.Toolbar"
],
border: false,
layout: "fit",
items: [
App.Util.buildBrowseConfig({}, {
controller: "PurchaseReport",
primaryKeyField: "PurchaseReportId",
stateful: true,
stateId: "App.view.windows.PurchaseReport-grid",
columns: [
{ dataIndex: "PurchaseCost", filter: true, header: "Purchase Cost", width: 150 }
],
features: [{ ftype: "filters", autoReload: false, local: true }],
store: { model: "App.model.PurchaseReport", sorters: [{ property: "Name", direction: "asc" }],
height: 200,
width: 400,
bbar: [
{
dataIndex: "PurchaseCost",
reference: 'purchaseCostField',
xtype: 'textfield',
name: 'Total',
fieldLabel: 'Total',
allowBlank: false
}
],
renderTo: Ext.getBody()
}
})
]
});
This is my controller part where my grid get bind as PurchaseReport.js,
Ext.define("App.controller.tabs.PurchaseReport", {
extend: "Ext.ux.app.BrowseController",
views: ["tabs.PurchaseReport"],
refs: [
{
ref: "myPurchaseReportGrid",
selector: "PurchaseReportTab > gridpanel"
}
],
init: function () {
this.control({
PurchaseReportTab: {
bind: function (a, c) {
**//Grid bind start**
var b = this.getMyPurchaseReportGrid();
b.getSelectionModel().deselectAll();
b.store.removeAll();
b.fireEvent("bind", b, c)
**//Grid bind End**
**//Combobox Bind start**
var combo = this.getCoachCombo(),
store = combo.store,
options = store.lastOptions || {};
options = Ext.apply({
callback: function () {
combo.select(App.coach.CoachId)
//console.log("called rajesh");
}
}, options);
store.load(options);
if (App.coach.IsAdmin) {
combo.show()
}
**//Combobox Bind end**
var abilities = App.coach.Abilities,
toolbar = this.getToolbar();
for (var x = 0; x < abilities.length; x++) {
var ability = abilities[x],
button = toolbar.query("button[tooltip=" + ability.Name + "]");
if (button.length) {
button[0].setVisible(true)
}
}
store.load(options);
var purchaseCostField = this.getReferences().purchaseCostField;
purchaseCostField.setValue(store.sum('PurchaseCost'));
}
},
"PurchaseReportTab > gridpanel": {
bind: this.bind,
itemdblclick: this.handleRecord,
selectionchange: this.selectionChange
}
})
}
});
This is my model part name as PurchaseReport.js
Ext.define("App.model.PurchaseReport", {
extend: "Ext.data.Model",
fields: [
{
name: "PurchaseCost",
type: "date"
}
],
proxy: {
type: "ajax",
url: "ControllerFactory.aspx",
extraParams: {
controller: "PurchaseReport",
operation: "GetPurchaseReportsByCoachIdAndDates"
},
reader: {
type: "json",
root: "data",
successProperty: "success"
}
}
});
The page looks like this and I want display total of PurchaseCost in Textbox like to total of PurchaseCost around 1195 as per the below Image
A quick way to do it
Add a reference to your textfield:
{
dataIndex:"PurchaseCost",
reference: 'purchaseCostField',
xtype: 'textfield',
name: 'Total',
fieldLabel: 'Total',
allowBlank: false
}
In your controller after your store load add the value to the textfield:
store.load(options);
var purchaseCostField = this.getReferences().purchaseCostField;
purchaseCostField.setValue(store.sum('PurchaseCost'));
I'm developing Exjs mvc application.
I have an Extjs model :
Ext.define('JC.model.File', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'int'},
{name: 'fileName', type: 'string'},
{name: 'fileSize', type: 'string'},
{name: 'position', type: 'string'}
]
});
and a store:
Ext.define('JC.store.Files', {
extend: 'Ext.data.Store',
model: 'JC.model.File',
proxy: {
url: JC.Util.createUrl('upload/getfiles'),
type: 'ajax',
simpleSortMode: true,
reader: {
type: 'json',
root: 'items',
totalProperty: 'totalCount'
},
api: {
create: '',
read: undefined,
update: undefined,
destroy: JC.Util.createUrl('upload/deletefile')
},
actionMethods:{create: 'POST', read: 'GET', update: 'POST', destroy: 'GET'}
}
});
and a grid panel with the following columns:
columns: [
{header: 'id', dataIndex: 'id', flex: 1},
{header: 'file name', dataIndex: 'fileName', flex: 1},
{header: 'file size', dataIndex: 'fileSize', flex: 1},
{header: 'position', dataIndex: 'position', flex: 1}, {
xtype: 'actioncolumn', items: [
{
icon: 'css/images/tree/black-trash-16.png', // Use a URL in the icon config
tooltip: 'Delete',
handler: function(grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
grid.getStore().destroy(rec);
}
}
]
}
],
at the line:
grid.getStore().destroy(rec);
an ajax request is created as below:
http://localhost:8084/myserver/deletefile?_dc=1422789950411&id=JC.model.File-6
I want the id requested for delete operation be my desired property of record i,e rec.id and I want it to be int type.I want the request to be something like this:
http://localhost:8084/myserver/deletefile?_dc=1422789950411&id=6
How can I do that?
I have setup a fiddle to replicate the issue.
I only managed to get this working by changing the actionMethod for the destory action to POST and setting an idProperty on the model.
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.define('File', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'fileName',
type: 'string'
}, {
name: 'fileSize',
type: 'string'
}, {
name: 'position',
type: 'string'
}]
});
Ext.define('Files', {
extend: 'Ext.data.Store',
model: 'File',
autoLoad: true,
proxy: {
url: 'data1.json',
type: 'ajax',
simpleSortMode: true,
reader: {
type: 'json',
rootProperty: 'items',
totalProperty: 'totalCount'
},
api: {
create: '',
read: 'data1.json',
update: '',
destroy: 'delete.json',
},
actionMethods: {
create: 'POST',
read: 'GET',
update: 'POST',
destroy: 'POST'
}
}
});
var store = Ext.create('Files');
Ext.create('Ext.grid.Panel', {
title: 'Test',
store: store,
columns: [{
header: 'id',
dataIndex: 'id',
flex: 1
}, {
header: 'file name',
dataIndex: 'fileName',
flex: 1
}, {
header: 'file size',
dataIndex: 'fileSize',
flex: 1
}, {
header: 'position',
dataIndex: 'position',
flex: 1
}, {
xtype: 'actioncolumn',
items: [{
icon: 'css/images/tree/black-trash-16.png',
tooltip: 'Delete',
width:50,
handler: function(grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
rec.erase();
}
}]
}],
height: 300,
width: 600,
renderTo: Ext.getBody()
});
}
});
// Sample JSON Data
{
"success": true,
"totalCount": 5,
"items": [{
"id": 1,
"fileName": 'file1.png',
"fileSize": 93204,
"position": 1
}, {
"id": 2,
"fileName": 'file2.png',
"fileSize": 93204,
"position": 1
}, {
"id": 3,
"fileName": 'file3.png',
"fileSize": 93204,
"position": 1
}, {
"id": 4,
"fileName": 'file4.png',
"fileSize": 93204,
"position": 1
}, {
"id": 5,
"fileName": 'file5.png',
"fileSize": 93204,
"position": 1
}]
}
I know this is an old post but you can send the model data that you wish by defining the proxy.writer in the model, in the proxy writer definition you can define the transform.fn which returns the data to send to the server as the model.data:
writer: {
type: 'json',
allDataOptions: {changes: true, critical: true},
partialDataOptions: {changes: true, critical: true},
encode: true,
rootProperty: 'group',
transform: {
fn: function(data, request, isDraft, model) {
if(request) {
if(request.getAction() == 'destroy') {
data.id = me.get('id');
data.type = me.get('type');
}else if(request.getAction() == 'create') {
delete(data.id);
}
}
return data;
}
}
},
I have the following column specified in my Ext.grid.Panel:
{text: 'Home Country', dataIndex: 'homeCountryId', width: 250, xtype: 'country-column'},
The xtype is "country-column" which is defined as:
Ext.define("RateManagement.view.Columns.CountryColumn", {
extend: 'Ext.grid.column.Column',
xtype: 'country-column',
text: 'Country',
editor: { xtype: 'country-combo', allowBlank: false, blankText: 'Country is required.'},
renderer: function(val) {
var locationStore = Ext.data.StoreManager.lookup('RateManagement.store.CountryStore');
var index = locationStore.findExact('value', val);
if (index != -1) {
var record = locationStore.getAt(index).data;
return record.label;
}
},
sortable: true
});
When I click the column header in the grid ("Home Country"), it doesn't sort at all.
How can I make it sort by the record.label to sort alphabetically?
Edit: Here is how I have changed my model:
{name:'homeLocationId', type: 'string'},
{name:'homeLocation', type: 'string', convert: function (newValue, model) {
// homeCountryId is appened for uniqueness and additional sort
return (newValue ? newValue : '' ) + '_' + model.get('homeLocationId');
}
},
Here is my grid column:
{text: 'Home Location', dataIndex: 'homeLocationId', width: 250, xtype: 'location-column'},
You can set label as dataIndex and attach renderer with display 'Home Country'
Here is working sample: http://jsfiddle.net/KLX5q/
// Monel
Ext.define('CountryModel', {
extend: 'Ext.data.Model',
fields: [
{ name:'homeCountryId', type:'int'},
{ name:'HomeCountryName', type:'string'},
{ name:'label', type:'string',
convert: function (newValue, model) {
// homeCountryId is appened for uniqueness and additional sort
return (newValue ? newValue : '' ) + '_' + model.get('homeCountryId');
}
}
]
});
// store
Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['homeCountryId', 'HomeCountryName', 'label'],
data:{'items':[
Ext.create('CountryModel',{ homeCountryId: 1, HomeCountryName: 'Australia', label:'nnnn' }),
Ext.create('CountryModel',{ homeCountryId: 2, HomeCountryName:'Germany', label:'bbbb' }),
Ext.create('CountryModel',{ homeCountryId: 3, HomeCountryName:'Russia', label:'aaaa' }),
Ext.create('CountryModel',{ homeCountryId: 4, HomeCountryName:'United States', label:'zzzz' })
]},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}
});
// gridpanel
Ext.create('Ext.grid.Panel', {
title: 'Countries',
margin: 5,
frame: true,
store: Ext.data.StoreManager.lookup('simpsonsStore'),
columns: [
{
text: 'HomeCountryName',
dataIndex: 'label',
flex: 1,
renderer: function(value, column, record){
return record.data.HomeCountryName;
}
}
//,{ text: 'homeCountryId', dataIndex: 'homeCountryId' } // uncomment if need
//,{ text: 'display label', dataIndex: 'label' }
],
height: 200,
width: 400,
renderTo: Ext.getBody()
});
I want to get an infinite scrolling grid with extjs4 and a c# backend... i am setting the proxy api in my controller..
My Model:
Ext.define('SCT.model.training.course.TrainingRequirementList', {
extend: 'Ext.data.Model',
idProperty: 'ID',
fields: [
{ name: 'ID', type: 'int', convert: null },
{ name: 'EmployeeName', type: 'string' },
{ name: 'Description', type: 'string' },
{ name: 'StatusText', type: 'string' },
{ name: 'Status', type: 'int' },
{ name: 'Priority', type: 'string' },
{ name: 'Date', type: 'string' },
{ name: 'Cost', type: 'string' },
{ name: 'CanApprove', type: 'bool' },
{ name: 'CanRequest', type: 'bool' },
{ name: 'ConfirmStatus', type: 'string' },
{ name: 'PlanId', type: 'int'}
]
});
My Grid:
{
xtype: 'gridpanel',
flex: 1,
padding: '0 10 10 10',
minHeight: 200,
verticalScroller: {
xtype: 'paginggridscroller'
},
store: {
model: 'SCT.model.training.course.TrainingRequirementList',
pageSize: 200,
autoLoad: true,
remoteSort: true,
sorters: {
property: 'Date',
direction: 'DESC'
},
proxy: {
type: 'direct',
extraParams: {
total: 50000
},
reader: {
type: 'json',
root: 'ID',
totalProperty: 'totalCount'
},
simpleSortMode: true
}
},
columns:
[{
text: Lang.Main.Employeee,
dataIndex: 'EmployeeName',
flex: 1,
filterable: true
},
{
text: Lang.Main.Course,
dataIndex: 'Description',
flex: 1,
filterable: true
},
{
text: Lang.Main.Status,
dataIndex: 'StatusText',
flex: 1,
filterable: true
},
{
text: Lang.Main.Priority,
dataIndex: 'Priority',
flex: 1
},
{
text: Lang.Main.Date,
dataIndex: 'Date',
flex: 1
},
{
text: Lang.Main.Cost,
dataIndex: 'Cost',
flex: 1,
filterable: true
},
{
text: Lang.Main.Actions,
flex: 1,
align: 'center',
xtype: 'actioncolumn',
width: 50,
items: [{
icon: 'Design/icons/cog_edit.png',
tooltip: Lang.Main.Open,
handler: function (grid, rowIndex, colIndex, item) {
this.onGridOpen(grid.getStore().getAt(rowIndex));
}
}]
}],
selModel: { mode: 'MULTI', selType: 'checkboxmodel' },
}
setting proxy in controoler:
view.grid.getStore().setProxy({
type: 'direct',
model: 'SCT.model.training.course.TrainingRequirementList',
api: { read: SCT.Service.Training.Plan.GetFilteredRequirements },
extraParams: { total: 50000 },
reader: {
type: 'json',
root: 'ID',
totalProperty: 'totalCount'
},
simpleSortMode: true
});
additional information about my view:
Ext.define('SCT.view.training.course.TrainingRequirements',
{
extend: 'Ext.panel.Panel',
require: [ 'Ext.grid.PagingScroller', 'Ext.ux.grid.FiltersFeature'],
My grid is still loading all data at once (about 8000 rows...) ...
i've searched for solutions and worked through tutorials.. i still dont get it.
please help me out... i dont get it at all...
UPDATE
this is my srv request:
and the response got 3MB (about 8k datasets... ) ..??
Your request dump shows that Ext effectively sends the limit param, so that's your server that is not handling it...
Just a piece of advice, but you should consider upgrading to last version of Ext, since buffered grid seems to have been simplified, and that will avoid you having to rework it if you eventually upgrade.