I'm giving the code I've used..
Please help...
The JavaScript section looks like:
Ext.define('NewsInfo', {
extend: 'Ext.data.Model',
fields: [
{ name:'news_id', mapping:'news_id', type:'int' },
{ name:'news_title', mapping:'news_title', type:'string' },
{ name:'news_summary', mapping:'news_summary', type:'string' },
{ name:'news_description', mapping:'news_description', type:'string' },
{ name:'news_source', mapping:'news_source', type:'string' },
{ name:'published_on', mapping:'published_on', type:'date', dateFormat:'Y-m-d H:i:s' },
{ name:'on_skype', mapping:'on_skype', type:'string' },
{ name:'is_active', mapping:'is_active', type:'string' },
{ name:'updated_at', mapping:'updated_at', type:'date', dateFormat:'Y-m-d H:i:s' }
]/*,
validations: [{
type: 'length',
field: 'news_title',
min: 1
}, {
type: 'length',
field: 'news_summary',
min: 1
}, {
type: 'length',
field: 'news_description',
min: 1
}]*/
});
store = new Ext.data.JsonStore({
autoLoad: true,
model: 'NewsInfo',
sortInfo: { field:'news_title', direction:'ASC'},
idProperty: 'news_id',
remoteSort: true,
proxy: new Ext.data.HttpProxy({
url: $this._s_ajax_url + '/load_news_collection/true',
method: 'POST'
}),
reader: Ext.data.JsonReader({
url: $this._s_ajax_url + '/load_news_collection/true',
fields: [
{ name:'news_id', mapping:'news_id', type:'int' },
{ name:'news_title', mapping:'news_title', type:'string' },
{ name:'news_summary', mapping:'news_summary', type:'string' },
{ name:'news_description', mapping:'news_description', type:'string' },
{ name:'news_source', mapping:'news_source', type:'string' },
{ name:'published_on', mapping:'published_on', type:'date', dateFormat:'Y-m-d H:i:s' },
{ name:'on_skype', mapping:'on_skype', type:'string' },
{ name:'is_active', mapping:'is_active', type:'string' },
{ name:'updated_at', mapping:'updated_at', type:'date', dateFormat:'Y-m-d H:i:s' }
],
root: 'records',
totalProperty: 'row_count',
successProperty: 'success'
})
});
var columns = [
{
text : 'News ID',
width : 55,
sortable : true,
hideable : false,
dataIndex: 'news_id'
},
{
text : 'News Sinossi',
width : 235,
sortable : true,
hideable : true,
dataIndex: 'news_title'
},
{
text : 'Active',
width : 75,
sortable : true,
hideable : true,
dataIndex: 'is_active',
align : 'center',
renderer : function (s_val) {
if (s_val == 'YES')
{
return '<img src="' + $this.get_skin_url('images/icons/tick_circle.png') + '" alt="' + s_val + '" title="' + s_val + '" />';
}
return '<img src="' + $this.get_skin_url('images/icons/cross_circle.png') + '" alt="' + s_val + '" title="' + s_val + '" />';
}
},
{
text : 'Last Updated',
align : 'center',
width : 95,
sortable : true,
hideable : false,
renderer : Ext.util.Format.dateRenderer('d-M-Y'),
dataIndex: 'updated_at'
},
{
xtype : 'actioncolumn',
align : 'center',
hideable: false,
width : 70,
items : [{
icon : $this.get_skin_url('images/icons/pencil.png'), // Use a URL in the icon config
tooltip: 'Edit',
handler: function(grid, rowIndex, colIndex) {
var obj_rec = store.getAt(rowIndex);
$('#div_news_grid_container').slideUp(800);
$('#div_editor_content').slideDown(800, function () {
$('#news_id').val(obj_rec.get('news_id'));
$('#news_title').val(obj_rec.get('news_title'));
$('#news_summary').val(obj_rec.get('news_summary'));
tinyMCE.get('news_description').setContent(obj_rec.get('news_description'));
});
}
}, {
icon : $this.get_skin_url('images/icons/view.png'), // Use a URL in the icon config
tooltip: 'View',
handler: function(grid, rowIndex, colIndex) {
var obj_rec = store.getAt(rowIndex);
var s_description = "<div style=\"background-color:white !important; height:100%; overflow:auto;\">\
" + obj_rec.get('news_description') + "\
</div>";
var s_description_html = "<div style=\"background-color:white !important; height:100%; overflow:auto;\">\
<pre>\
" + obj_rec.get('description_html') + "\
</pre>\
</div>";
Ext.create('Ext.window.Window', {
renderTo: "main-content",
title: "Description for " + obj_rec.get('title_text'),
closeAction: 'hide',
minimizable: false,
maximizable: false,
resizable: true,
modal: true,
layout: 'border',
height: 350,
width: 550,
items: [{
region: 'center',
xtype: 'tabpanel',
items: [{
title: 'Preview',
html: s_description
}, {
title: 'HTML',
html: s_description_html
}]
}]
}).show();
}
}, {
icon : $this.get_skin_url('images/icons/cross.png'), // Use a URL in the icon config
tooltip: 'Delete',
handler: function(grid, rowIndex, colIndex) {
var obj_rec = store.getAt(rowIndex);
var s_news_title = obj_rec.get('title_text');
var i_news_id = obj_rec.get('news_id');
Ext.MessageBox.show({
title:'Confirm Delete',
msg: 'Do you really want to remove ' + s_news_title + '?',
buttons: Ext.MessageBox.YESNO,
icon: Ext.MessageBox.QUESTION,
closable: false,
fn: function (btn) {
if (btn == 'yes')
{
$this.delete_news(i_news_id);
}
}
});
}
}]
}
];
store.on('load', function () {
Ext.create('Ext.grid.Panel', {
store: store,
columns: columns,
height: 350,
width: 645,
title: 'News Management System',
renderTo: 'div_news_grid',
loadMask: true,
viewConfig: {
stripeRows: true
},
bbar: new Ext.PagingToolbar({
pageSize: 25,
store: store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display",
items:[
'-', /*{
pressed: true,
enableToggle:true,
text: 'Show Preview',
cls: 'x-btn-text-icon details',
toggleHandler: function(btn, pressed){
var view = grid.getView();
view.showPreview = pressed;
view.refresh();
}
}*/]
})
});
});
The server responds with the following:
{
"records":[
{
"news_id":"1",
"news_title":"comunicato",
"news_summary":"Un corso di lingua da seguire sempre, anche fuori sede Un problema che si riscontra frequentemente nelle",
"news_description":"<p> <\/p>\r\n <p>L\u2019estate \u00e8 alle porte e desideriamo aggiornarvi sulle attivit\u00e0 che stiamo organizzando per voi:<\/p>\r\n <p> <\/p>\r\n <p>Per i bambini e i ragazzi dai 4 ai 19 anni proponiamo un programma ricco di giochi, attivit\u00e0 pratiche, laboratori e tanto divertimento! Un\u2019occasione in pi\u00f9 per mettere in pratica le conoscenze linguistiche in un contesto diverso da quello prettamente scolastico favorendo anche il lavoro di gruppo.<\/p>\r\n <ul class=\"list01\">\r\n <li>Si pu\u00f2 scegliere di fare 1 o 2 settimane<\/li>\r\n <li>I corsi si svolgono dal 13 giugno al 1 luglio (7 \u2013 19 anni) e dal 4 al 15 luglio (4 \u2013 6 anni), dal luned\u00ec al venerd\u00ec, dalle 8.30 alle 12.30<\/li>\r\n <li>2 settimane: \u20ac 280,00<\/li>\r\n <li>1 settimana: \u20ac 150,00<\/li>\r\n <li>I gruppi verranno attivati al raggiungimento di minimo 5 partecipanti e massimo 10<\/li>\r\n <li>Al raggiungimento di 10 partecipanti ci sar\u00e0 uno sconto del 20% per ogni studente, quindi se avete amici o parenti interessati avvertiteli!<\/li>\r\n <li>Sar\u00e0 disponibile un servizio di pre e post accoglienza <\/li>\r\n <\/ul>\r\n <p>Infine vi ricordiamo che la scuola rester\u00e0 aperta per tutta l\u2019estate (eccetto dal 1 al 22 agosto) per lezioni individuali, recupero crediti scolastici e mini-gruppi.<\/p>\r\n <p> <\/p>",
"is_active":"YES",
"published_on":"2011-03-01 15:53:36",
"updated_at":"2011-05-25 20:19:12"
}
],
"row_count":1,
"success":true
}
This is tagged with extjs4, so I think this might just be a matter of changing your object configurations to match the new config options:
You have both fields and a model defined on the store. You only need the model.
idProperty is defined as part of the model now, you have it on the store
readers are defined as part of the proxy now, you have it on the store
the specialized store types are deprecated (or at least, undocumented)
Your autoLoad might be finishing before your on('load') gets registered.
sortInfo should be defined as sorters
I highly recommend always referring to the official API to determine the "appropriate" configurations. For stores: http://docs.sencha.com/ext-js/4-0/#/api/Ext.data.Store
Here is a modified (but untested) version of your code with examples of the changes to make:
Ext.define('NewsInfo', {
extend: 'Ext.data.Model',
idProperty: 'news_id',
// The rest of this should be right
});
The store configuration is pretty different, and is probably at the root of your data not loading:
var store = new Ext.data.Store({
autoLoad: {
callback: function() {
Ext.create('Ext.grid.Panel', {
// The rest of this should be right, too, pulled up from listener
});
}
},
model: 'NewsInfo',
sorters: [{ property:'news_title', direction:'ASC'}],
remoteSort: true,
proxy: {
type: 'ajax',
url: $this._s_ajax_url + '/load_news_collection/true',
method: 'POST',
reader: {
type: 'json',
root: 'records',
totalProperty: 'row_count',
successProperty: 'success'
}
})
});
I finally found my problem, its not json version.
This may seem stupid, but I was working locally on my Desktop and I was doing a Json request to the server (www.domain.com/json.php).
You can create your interface without been on server. But if you use form and submit.
Your website must also be on a server.
Related
I have a custom grid that displays open tasks filtered by (Owner = some-user#company.com).
I would like to include the last revision for each task in a custom grid, but the Revision column is not available on the settings dialog. How to traverse from Revision History to individual revisions?
It can't be done with a custom grid, but can be done with a custom code. Here is an app example that populates a grid based on a selection in the UserSearchComboBox , and then displays the last revision of a selected task on a click event.
You may copy the html file into a custom page from this github repo:
Here is the js file:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
var context = this.getContext ();
var currentProject = context.getProject()._ref;
var panel = Ext.create('Ext.panel.Panel', {
layout: 'hbox',
itemId: 'parentPanel',
componentCls: 'panel',
items: [
{
xtype: 'rallyusersearchcombobox',
fieldLabel: 'SELECT USER:',
project: currentProject,
listeners:{
ready: function(combobox){
this._onUserSelected(combobox.getRecord());
},
select: function(combobox){
if (this.down('#c').html !== 'No task is selected') {
Ext.getCmp('c').update('No task is selected');
}
this._onUserSelected(combobox.getRecord());
},
scope: this
}
},
{
xtype: 'panel',
title: 'Tasks',
width: 600,
itemId: 'childPanel1'
},
{
xtype: 'panel',
title: 'Last Revision',
width: 600,
itemId: 'childPanel2'
}
],
});
this.add(panel);
this.down('#childPanel2').add({
id: 'c',
padding: 10,
maxWidth: 600,
maxHeight: 400,
overflowX: 'auto',
overflowY: 'auto',
html: 'No task is selected'
});
},
_onUserSelected:function(record){
var user = record.data['_ref'];
if(user){
var filter = Ext.create('Rally.data.QueryFilter', {
property: 'Owner',
operator: '=',
value: user
});
filter = filter.and({
property: 'State',
operator: '<',
value: 'Completed'
});
filter.toString();
Ext.create('Rally.data.WsapiDataStore', {
model: 'Task',
fetch: [ 'DragAndDropRank','FormattedID','Name','State','RevisionHistory'],
autoLoad: true,
filters : [filter],
sorters:[
{
property: 'DragAndDropRank',
direction: 'ASC'
}
],
listeners: {
load: this._onTaskDataLoaded,
scope: this
}
});
}
},
_onTaskDataLoaded: function(store, data) {
var customRecords = [];
Ext.Array.each(data, function(task, index) {
customRecords.push({
_ref: task.get('_ref'),
FormattedID: task.get('FormattedID'),
Name: task.get('Name'),
RevisionID: Rally.util.Ref.getOidFromRef(task.get('RevisionHistory')),
});
}, this);
this._updateGrid(store,data);
},
_updateGrid: function(store, data){
if (!this.down('#g')) {
this._createGrid(store,data);
}
else{
this.down('#g').reconfigure(store);
}
},
_createGrid: function(store,data){
var that = this;
var g = Ext.create('Rally.ui.grid.Grid', {
id: 'g',
store: store,
enableRanking: true,
columnCfgs: [
{text: 'Formatted ID', dataIndex: 'FormattedID'},
{text: 'Name', dataIndex: 'Name'},
{text: 'State', dataIndex: 'State'},
{text: 'Last Revision',
renderer: function (v, m, r) {
var id = Ext.id();
Ext.defer(function () {
Ext.widget('button', {
renderTo: id,
text: 'see',
width: 50,
handler: function () {
console.log('r', r.data);
that._getRevisionHistory(data, r.data);
}
});
}, 50);
return Ext.String.format('<div id="{0}"></div>', id);
}
}
],
height: 400,
});
this.down('#childPanel1').add(g);
},
_getRevisionHistory: function(taskList, task) {
this._task = task;
this._revisionModel = Rally.data.ModelFactory.getModel({
type: 'RevisionHistory',
scope: this,
success: this._onModelCreated
});
},
_onModelCreated: function(model) {
model.load(Rally.util.Ref.getOidFromRef(this._task.RevisionHistory._ref),{
scope: this,
success: this._onModelLoaded
});
},
_onModelLoaded: function(record, operation) {
record.getCollection('Revisions').load({
fetch: true,
scope: this,
callback: function(revisions, operation, success) {
this._onRevisionsLoaded(revisions, record);
}
});
},
_onRevisionsLoaded: function(revisions, record) {
var lastRev = _.first(revisions).data;
console.log('_onRevisionsLoaded: ',lastRev.Description, lastRev.RevisionNumber, lastRev.CreationDate );
this._displayLastRevision(lastRev.Description,lastRev.RevisionNumber, lastRev.CreationDate );
},
_displayLastRevision:function(desc, num, date){
Ext.getCmp('c').update('<b>' + this._task.FormattedID + '</b><br/><b>Revision CreationDate: </b>' + date +'<br /><b>Description:</b>' + desc + '<br /><b>Revision Number:</b>' + num + '<br />');
}
});
Example
I've been looking into getting this to work but so far instead of a dropdown I get and empty textbox which doesn't do anything.
Below is my present code:-
#section js {
<script type="text/x-kendo-template" id="template">
<div class="toolbar">
<label class="category-label" for="external">Show checks by ex:</label>
<input type="search" id="external" style="width: 230px"></input>
</div>
</script>
<script type="text/javascript">
var theGrid;
$().ready(function () {
$('#listDiv').kendoGrid({
dataSource: {
type: 'json',
serverPaging: true,
pageSize: 10,
transport: {
read: {
url: '#Url.Action("_IList", "Entry", new { #ExId = Model.ExId })',
data: { ignore: Math.random() }
}
},
schema: {
model: {
id: 'Id',
fields: {
Id: { type: 'number' },
Name: { type: 'string' },
Ex: { type: 'string' },
Date: { type: 'string' },
Check1: { type: 'string' },
Check2: { type: 'string' },
Check3: { type: 'string' },
Check4: { type: 'string' },
Check5: { type: 'string' },
Edit: { type: 'string' }
}
},
data: "Data",
total: "Count"
}
},
scrollable: false,
toolbar: kendo.template($("#template").html()),
columns:
[
{
field: 'Name'
},
{
field: 'Ex'
},
{
field: 'Date'
},
{
template: '#=Template1#' + sitePath + '#=Patient1#',
field: 'Patient1',
title: 'Patient 1',
width: 50
},
{
template: '#=Template2#' + sitePath + '#=Patient2#',
field: 'Patient2',
title: 'Patient 2',
width: 50
},
{
template: '#=Template3#' + sitePath + '#=Patient3#',
field: 'Patient3',
title: 'Patient 3',
width: 50
},
{
template: '#=Template4#' + sitePath + '#=Patient4#',
field: 'Patient4',
title: 'Patient 4',
width: 50
},
{
template: '#=Template5#' + sitePath + '#=Patient5#',
field: 'Patient5',
title: 'Patient 5',
width: 50
}
],
pageable: true
});
var dropDown = grid.find("#external").kendoDropDownList({
dataTextField: "ExName",
dataValueField: "ExId",
autoBind: false,
optionLabel: "All",
dataSource: {
type: "json",
severFiltering: true,
transport: {
url: '#Url.Action("_Ex", "Entry")',
data: { ignore: Math.random() }
}
},
change: function () {
var value = this.value();
if (value) {
grid.data("kendoGrid").dataSource.filter({ field: "ExId", operator: "eq", value: parseString(value) });
} else {
grid.data("kendoGrid").dataSource.filter({});
}
}
});
theGrid = $('#listDiv').data('kendoGrid');
});
</script>
<style scoped="scoped">
#grid .k-toolbar
{
min-height: 27px;
}
.external-label
{
vertical-align: middle;
padding-right: .5em;
}
#external
{
vertical-align: middle;
}
.toolbar {
float: right;
margin-right: .8em;
}
</style>
}
<h2>Check Lists</h2>
<div id="listDiv"></div>
<br />
It works to display all check lists for each Ex which I can select on a previous page and pass in the string Id to this one but I'd like to be able to figure out what's wrong with with the toolbar template as having the functionality on 1 page rather than spread over 2 is far more desirable.
Any help/guidance will be much appreciated.
Edit:
I did also find someone else who encountered the problem except they didn't get a forum response.
Example 2
You mention that somebody else encountered the problem and didn't receive a response, however the linked forum thread does contain a response and an answer to this issue. In that particular case a Javascript error had occurred on the page which prevented the dropdown from initializing correctly and I believe this is also the case for yourself.
Although not completely working because there isn't a valid datasource, I took your example code and dumped it into a jsFiddle and (after fixing some JS errors) you can see that the dropdown appears absolutely fine.
In particular, there were errors regarding grid and sitePath not being defined that prevented the dropdown from initializing.
var grid;
var sitePath = '';
$().ready(function () {
grid = $('#listDiv').kendoGrid({
dataSource: {
type: 'json',
serverPaging: true,
pageSize: 10,
transport: {
read: {
url: '',
data: { ignore: Math.random() }
}
},
schema: {
model: {
id: 'Id',
fields: {
Id: { type: 'number' },
Name: { type: 'string' },
Ex: { type: 'string' },
Date: { type: 'string' },
Check1: { type: 'string' },
Check2: { type: 'string' },
Check3: { type: 'string' },
Check4: { type: 'string' },
Check5: { type: 'string' },
Edit: { type: 'string' }
}
},
data: "Data",
total: "Count"
}
},
scrollable: false,
toolbar: kendo.template($("#template").html()),
columns:
[
{
field: 'Name'
},
{
field: 'Ex'
},
{
field: 'Date'
},
{
template: '#=Template1#' + sitePath + '#=Patient1#',
field: 'Patient1',
title: 'Patient 1',
width: 50
},
{
template: '#=Template2#' + sitePath + '#=Patient2#',
field: 'Patient2',
title: 'Patient 2',
width: 50
},
{
template: '#=Template3#' + sitePath + '#=Patient3#',
field: 'Patient3',
title: 'Patient 3',
width: 50
},
{
template: '#=Template4#' + sitePath + '#=Patient4#',
field: 'Patient4',
title: 'Patient 4',
width: 50
},
{
template: '#=Template5#' + sitePath + '#=Patient5#',
field: 'Patient5',
title: 'Patient 5',
width: 50
}
],
pageable: true
});
var dropDown = grid.find("#external").kendoDropDownList({
dataTextField: "ExName",
dataValueField: "ExId",
autoBind: false,
optionLabel: "All",
dataSource: {
type: "json",
severFiltering: true,
transport: {
url: '#Url.Action("_Ex", "Entry")',
data: { ignore: Math.random() }
}
},
change: function () {
var value = this.value();
if (value) {
grid.data("kendoGrid").dataSource.filter({ field: "ExId", operator: "eq", value: parseString(value) });
} else {
grid.data("kendoGrid").dataSource.filter({});
}
}
});
theGrid = $('#listDiv').data('kendoGrid');
});
How do I find the row index in a gridpanel that has comboboxes in on of the columns and is used to update the store/database through and ajax proxy? I'm using Ext.grid.plugin.CellEditing. Here's my code. Thanks for looking at it!
Ext.Loader.setConfig({
enabled: true
});
Ext.Loader.setPath('Ext.ux', '/extjs4/examples/ux');
Ext.require([
'Ext.layout.container.Fit',
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.panel.*',
'Ext.selection.CellModel',
'Ext.state.*',
'Ext.form.*',
'Ext.ux.CheckColumn'
]);
Ext.define('Ext.app.HirePlanGrid', {
extend: 'Ext.panel.Panel',
alias: 'widget.hirePlangrid'
,hireplanstoreId: 'hireplanstore'
,hiremonthstoreId: 'hiremonthstore'
,renderMonth : function (value, p, record) {
var fkStore = Ext.getStore(this.up('hirePlangrid').hiremonthstoreId);
var rec = fkStore.findRecord("MONTH_ID", value);
//return rec.get("ABBREVIATED_MONTH");
}
,initComponent: function() {
this.editing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 2
});
var objMonthStore = Ext.getStore(this.hiremonthstoreId);
objMonthStore.load();
var objStore = Ext.getStore(this.hireplanstoreId);
objStore.setProxy( {
type: 'ajax',
url: 'hireplan.cfc?method=getEmployees'
});
objStore.load();
var onDeleteClick = function(field, value, options) {
// var objPanel = this.down('gridpanel');
var selection = Ext.getCmp('grid').getSelectionModel().getSelection();
alert(selection);
// var selection = getView().getSelectionModel().getSelection()[r];
if (value) {
alert(value);
objStore.remove(value);
objStore.sync();
}
};
var onUpdateClick = function(field, value, options) {
alert('field= ' + field + ' value= '+ value+ 'options= '+ options);
objStore.update(objStore.getAt(value));
onSync();
};
Ext.apply(this, {
layout: 'fit',
width: 800,
//height: 1500,
items: [{
xtype: 'grid',
id : 'gridgrid',
//height: 300,
store: objStore,
selModel: { selType: 'cellmodel' },
selType : 'rowmodel',
plugins: [this.editing],
// plugins: [cellEditing],
columnLines: true,
viewConfig: {stripeRows: true},
//loadMask: true,
disableSelection: true,
listeners: {
selectionchange: function(selModel, selected) {
var selection = Ext.getCmp('gridgrid').getSelectionModel().getSelection();
}
},
columns: [
{ header: 'rowid', hidden: true, dataIndex: 'ROWID'},
{
header: 'Indicator',
id: 'chkcolumn',
xtype: 'checkcolumn',
dataIndex: 'CHK_COL',
editor: {
xtype: 'checkbox',
cls: 'x-grid-checkheader-editor'
},
listeners : checkchange : function(column, recordIndex, checked)
{
alert('checked rindex= ' + recordIndex);
onDeleteClick(column, recordIndex, checked);
//or send a request
}
}
},
{
id: 'employeeid',
header: 'employeeid',
width: 80,
hidden: false,
sortable: true,
dataIndex: 'EMPLOYEEID',
flex: 1
},
{
id: 'NATIONALIDNUMBER',
header: 'NATIONALIDNUMBER',
width: 80,
sortable: true,
dataIndex: 'NATIONALIDNUMBER',
flex: 1
},
{
id: 'MARITALSTATUS',
header: 'MARITALSTATUS',
width: 80,
sortable: true,
dataIndex: 'MARITALSTATUS',
flex: 1
},
{
id: 'PotentialforInsourcingKV',
header: 'Potential for Insourcing',
width: 30,
sortable: true,
dataIndex: 'POTENTIAL_FOR_INSOURCING',
flex: 1,
editor: {
id: 'thiscombo',
xtype: 'combobox',
typeAhead: true,
triggerAction: 'all',
selectOnTab: true,
store: [
['1', 'Yes'],
['0', 'No']
],
lazyRender: true,
listClass: 'x-combo-list-small',
listeners: { 'select' : function(r){
var selval = Ext.getCmp("thiscombo").getValue();
//var recval = Ext.getCmp("grid").getValue();
//var selection = getView().getSelectionModel().getSelection()[r]
alert(selval + ' ' + rowIdx);
// onUpdateClick(editor, rowIdx, value );
}
},
}
},
{
id: 'ABBREVIATED_MONTH',
header: 'ABBREVIATED_MONTH',
width: 80,
sortable: true,
dataIndex: 'ABBREVIATED_MONTH',
flex: 1,
renderer: this.renderMonth,
field: {
xtype: 'combobox',
store: Ext.getStore(this.hiremonthstoreId),
typeAhead: true,
lazyRender: true,
queryMode: 'local',
displayField: 'ABBREVIATED_MONTH',
valueField: 'MONTH_ID',
listClass: 'x-combo-list-small'
}
},
{
id: 'SALARIEDFLAG',
header: 'SALARIEDFLAG',
width: 80,
sortable: true,
dataIndex: 'SALARIEDFLAG',
flex: 1
}],
features: [{
ftype: 'rowbody'
}]
}]
});
this.callParent(arguments);
//this.getSelectionModel().on('selectionchange', this.onSelectChange, this);
}, //initComponent
getSelectedRowIndex : function(){
var r, s;
r = this.getView().getSelectionModel().getSelection();
s = this.getStore();
return s.indexOf(r[0]);
},
onSelectChange: function(selModel, selections){
this.down('#delete').setDisabled(selections.length === 0);
},
onSync: function() {
objStore.sync();
},
viewConfig: {},
});
I read in another post that what I needed to do was add a listener to this.cellediting and use the 'beforeedit' event to find the row index, and then set to variables:
var rIdx = '';
var cIdx = '';
this.cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1,
listeners: {
'beforeedit': function(e){
var me = this;
var allowed = !!me.isEditAllowed;
if (!me.isEditAllowed)
Ext.Msg.confirm('confirm', 'Are you sure you want edit?', function(btn){
if (btn !== 'yes')
return;
me.isEditAllowed = true;
me.startEditByPosition({
row: e.rowIdx,
column: e.colIdx
});
});
rIdx = e.rowIdx;
cIdx = e.colIdx;
alert('rIdx= ' + rIdx + ' cIdx = ' + cIdx);
return allowed;
},
'edit': function(e){
this.isEditAllowed = true;
}
}
});
I'm trying to update my store and then database after using cellediting and a combobox in a gridpanel to update a record. The update operation.action in the ajax proxy is firing correctly, it just that the store and the grid aren't syncronizing, and the post tab in firebug says my json looks like this: 'data []'. How do I get the store record to create the json and update the record? Thanks for looking at this in advance...
Ext.Loader.setConfig({
enabled: true
});
Ext.Loader.setPath('Ext.ux', '/extjs4/examples/ux');
Ext.require([
'Ext.layout.container.Fit',
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.panel.*',
'Ext.selection.CellModel',
'Ext.state.*',
'Ext.form.*',
'Ext.ux.CheckColumn']);
Ext.define('Ext.app.HirePlanGrid', {
extend: 'Ext.panel.Panel',
alias: 'widget.hirePlangrid',
hireplanstoreId: 'hireplanstore',
hiremonthstoreId: 'hiremonthstore'
,
renderMonth: function (value, p, record) {
var fkStore = Ext.getStore(this.up('hirePlangrid').hiremonthstoreId);
var rec = fkStore.findRecord("MONTH_ID", value);
//return rec.get("ABBREVIATED_MONTH");
}
,
initComponent: function () {
var rIdx = '';
var cIdx = '';
this.editing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1,
listeners: {
'beforeedit': function (e) {
var me = this;
var allowed = !! me.isEditAllowed;
if (!me.isEditAllowed) Ext.Msg.confirm('confirm', 'Are you sure?', function (btn) {
if (btn !== 'yes') return;
me.isEditAllowed = true;
me.startEditByPosition({
row: e.rowIdx,
column: e.colIdx
});
});
rIdx = e.rowIdx;
cIdx = e.colIdx;
// alert('rIdx= ' + rIdx + ' cIdx = ' + cIdx);
return allowed;
},
'edit': function (e) {
this.isEditAllowed = true;
}
}
});
var objMonthStore = Ext.getStore(this.hiremonthstoreId);
objMonthStore.load();
var objStore = Ext.getStore(this.hireplanstoreId);
objStore.setProxy({
type: 'ajax',
url: 'hireplan.cfc?method=getEmployees'
});
objStore.load();
var onDeleteClick = function (field, value, options) {
// var objPanel = this.down('gridpanel');
var selection = Ext.getCmp('grid').getSelectionModel().getSelection();
// alert(selection);
//var selection = getView().getSelectionModel().getSelection()[r];
if (value) {
//alert(value);
objStore.remove(value);
objStore.sync();
}
};
var onUpdateClick = function (field, value, options) {
alert('field= ' + field + ' value= ' + value + 'options= ' + options);
objStore.update(this.hireplanstoreId, value, 'update', options);
onSync();
};
var onSync = function () {
objStore.sync();
};
Ext.apply(this, {
layout: 'fit',
width: 800,
//height: 1500,
items: [{
xtype: 'grid',
id: 'gridgrid',
//height: 300,
store: objStore,
selModel: {
selType: 'cellmodel'
},
selType: 'rowmodel',
plugins: [this.editing],
// plugins: [cellEditing],
columnLines: true,
viewConfig: {
stripeRows: true
},
//loadMask: true,
disableSelection: true,
columns: [{
header: 'rowid',
hidden: true,
dataIndex: 'ROWID'
}, {
header: 'Indicator',
id: 'chkcolumn',
xtype: 'checkcolumn',
dataIndex: 'CHK_COL',
editor: {
xtype: 'checkbox',
cls: 'x-grid-checkheader-editor'
},
listeners: {
checkchange: function (column, recordIndex, checked) {
alert('checked rindex= ' + recordIndex);
onDeleteClick(column, recordIndex, checked);
//or send a request
}
}
}, {
id: 'employeeid',
header: 'employeeid',
width: 80,
hidden: false,
sortable: true,
dataIndex: 'EMPLOYEEID',
flex: 1
}, {
id: 'NATIONALIDNUMBER',
header: 'NATIONALIDNUMBER',
width: 80,
sortable: true,
dataIndex: 'NATIONALIDNUMBER',
flex: 1
}, {
id: 'MARITALSTATUS',
header: 'MARITALSTATUS',
width: 80,
sortable: true,
dataIndex: 'MARITALSTATUS',
flex: 1
}, {
id: 'PotentialforInsourcingKV',
header: 'Potential for Insourcing',
width: 30,
sortable: true,
dataIndex: 'POTENTIAL_FOR_INSOURCING',
flex: 1,
editor: {
id: 'thiscombo',
xtype: 'combobox',
typeAhead: true,
triggerAction: 'all',
selectOnTab: true,
store: [
['1', 'Yes'],
['0', 'No']
],
lazyRender: true,
listClass: 'x-combo-list-small',
listeners: {
scope: this,
'select': function () {
var selval = Ext.getCmp('thiscombo').getValue();
var row = rIdx;
//alert(selval + ' ' + rIdx);
onUpdateClick('thiscombo', rIdx, selval);
}
}
}
}, {
id: 'ABBREVIATED_MONTH',
header: 'ABBREVIATED_MONTH',
width: 80,
sortable: true,
dataIndex: 'ABBREVIATED_MONTH',
flex: 1,
renderer: this.renderMonth,
field: {
xtype: 'combobox',
store: Ext.getStore(this.hiremonthstoreId),
typeAhead: true,
lazyRender: true,
queryMode: 'local',
displayField: 'ABBREVIATED_MONTH',
valueField: 'MONTH_ID',
listClass: 'x-combo-list-small'
}
}, {
id: 'SALARIEDFLAG',
header: 'SALARIEDFLAG',
width: 80,
sortable: true,
dataIndex: 'SALARIEDFLAG',
flex: 1
}],
features: [{
ftype: 'rowbody'
}]
}]
});
this.callParent(arguments);
}, //initComponent
onSelectChange: function (selModel, selections) {
this.down('#delete').setDisabled(selections.length === 0);
},
viewConfig: {},
});
// JavaScript Document
// JavaScript Document
hireplanstore = Ext.create("Ext.data.Store", {
model: 'HiringPlan',
//autoLoad: true,
//autoSync: true,
buffered: true,
storeId: 'hireplanstore',
remoteFilter: true
,
proxy: {
type: 'ajax',
simpleSortMode: true,
api: {
read: 'hireplan.cfc?method=GetEmployees',
update: 'hireplan.cfc?method=upEmployees',
destroy: 'hireplan.cfc?method=delEmployees'
},
reader: {
type: 'json',
messageProperty: 'message',
successProperty: 'success',
root: 'data'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
listeners: {
exception: function (proxy, response, operation) {
Ext.MessageBox.show({
title: 'ERROR from store',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}
}
});
//hireplanstore.pageSize = 10000;
Ext.define('HiringPlan', {
extend: 'Ext.data.Model',
fields: [{
name: 'ROWID',
type: 'string'
}, {
name: 'EMPLOYEEID',
type: 'string'
}, {
name: 'NATIONALIDNUMBER',
type: 'string'
}, {
name: 'MARITALSTATUS',
type: 'string'
}, {
name: 'GENDER',
type: 'string'
}, {
name: 'POTENTIAL_FOR_INSOURCING',
type: 'integer'
}, {
name: 'ABBREVIATED_MONTH',
type: 'string'
}, {
name: 'SALARIEDFLAG',
type: 'string'
}, {
name: 'CHK_COL',
type: 'bool'
}]
});
In order to update correctly your ajax or rest call have to return an array containing the updated records, even if it's a single record, you have to return it inside an array, a sample json response (for the rest proxy) should be like this:
[{'id': 1, 'name': 'test', 'foo': 'bar'}]
I am implementing Extjs 4 ( MVC) example given here with rails 3.x.
I have the following structure:
in Public dir,
Manager
-> mainapp
- controller
-> Dragdrops.js
- model
-> Dragdrop.js
- store
-> FirstDragdrops.js
-> SecondDragdrops.js
- view
-dragdrop
-> DragdropList.js
View ( DragdropList.js ) has a panel that contains 2 grids.
/* -- View - Drag n Drop list grid -- */
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.dd.*'
]);
Ext.define('mainapp.view.dragdrop.DragdropList', {
extend: 'Ext.panel.Panel',
alias : 'widget.dragdroplist',
title : 'Drag Drop List',
layout: 'hbox',
initComponent: function() {
this.items = [
{
xtype: 'grid',
title: 'First Grid',
id: 'firstgrid',
store: 'FirstDragdrops',
flex: 1, enableDragDrop : true,
ddGroup: 'mydd',
ddText: 'Shift Row',
columns : [
{text: "Item Name", sortable: true, dataIndex: 'name'},
{text: "Quantity", sortable: true, dataIndex: 'qty'},
{text: "Amount", sortable: true, dataIndex: 'amt'}
],
singleSelect:true,
listeners: {
beforerowselect: function(sm,i,ke,row){
//grid.ddText = title_str(row.data.title, null, row);
},
selectionchange: function(){
alert("Row Selected! " + this.ddText);
//grid.ddText(row.data.title, null, row);
}
}
},
{
xtype: 'grid',
title: 'Second Grid',
id: 'secondgrid',
store: 'SecondDragdrops',
flex: 2,
singleSelect: true,
enableDragDrop : true,
stripeRows: true,
columns : [
{text: "Item Name", sortable: true, dataIndex: 'name'},
{text: "Quantity", sortable: true, dataIndex: 'qty'},
{text: "Amount", sortable: true, dataIndex: 'amt'}
]
}
]
this.callParent(arguments);
}
});
But I m not able to implement the drag and drop functionality in extjs 4 (WITHOUT PLUGIN).
Any suggestions??
I think this is not perfect way, but it works in my project:
Add listener to elements you want to drag or/adn drop:
listeners: {
render: initializeDD
}
Implement d&d configuretaion method (reordering of components in my case):
function initializeDD (v) {
var el = Ext.get(v.getEl().id);
el.on('dblclick', function() {
var component = Ext.ComponentManager.get(v.getEl().id).getComponent(0);
component.focus();
}, this);
v.dragZone = Ext.create('Ext.dd.DragZone', v.getEl(), {
ddGroup: 'blankAttsReorder',
getDragData: function(e) {
var sourceEl = e.getTarget(v.itemSelector, 10), d;
if (sourceEl) {
d = sourceEl.cloneNode(true);
d.id = Ext.id();
return v.dragData = {
sourceEl: sourceEl,
repairXY: Ext.fly(sourceEl).getXY(),
ddel: d,
originalid: v.getEl().id
};
}
},
getRepairXY: function() {
return this.dragData.repairXY;
}
});
v.dropZone = Ext.create('Ext.dd.DropZone', v.el, {
ddGroup: 'blankAttsReorder',
getTargetFromEvent: function(e) {
return e.getTarget('.blankbuilder-attribute');
},
onNodeOver : function(target, dd, e, data){
// specific code there
var targetN = Ext.Array.indexOf(blank.items, Ext.ComponentManager.get(target.id), 0);
var sourceN = Ext.Array.indexOf(blank.items, Ext.ComponentManager.get(data.originalid), 0);
if (targetN!=sourceN) {
blank.move(sourceN, targetN);
}
return Ext.dd.DropZone.prototype.dropAllowed;
},
onNodeDrop : function(target, dd, e, data){
Ext.ComponentManager.get(target.id).getComponent(0).blur();
}
});
}
P. S. Example of drag one type of components to another type of components (contain some project specific code):
function initializeAttributeDragZone (v) {
v.dragZone = Ext.create('Ext.dd.DragZone', v.getEl(), {
ddGroup: 'attsToBlank',
getDragData: function(e) {
var sourceEl = e.getTarget(v.itemSelector, 10), d;
if (sourceEl) {
d = sourceEl.cloneNode(true);
d.id = Ext.id();
return v.dragData = {
sourceEl: sourceEl,
repairXY: Ext.fly(sourceEl).getXY(),
ddel: d,
attributeData: v.getRecord(sourceEl).data
};
}
},
getRepairXY: function() {
return this.dragData.repairXY;
}
});
}
// Добавляем возможность дропать атрибуты из списка на бланк
function initializeBlankDropZone (v) {
v.dropZone = Ext.create('Ext.dd.DropZone', v.el, {
ddGroup: 'attsToBlank',
getTargetFromEvent: function(e) {
return e.getTarget('.blankbuilder-attribute-new');
},
onNodeEnter : function(target, dd, e, data){
Ext.fly(target).addCls('blankbuilder-attribute-new-hover');
},
onNodeOut : function(target, dd, e, data){
Ext.fly(target).removeCls('blankbuilder-attribute-new-hover');
},
onNodeOver : function(target, dd, e, data){
return Ext.dd.DropZone.prototype.dropAllowed;
},
onNodeDrop : function(target, dd, e, data){
// some code
}
});
}