Related
In my extjs6 version 6.0.0.640 project, I am getting layout run failed when I populate my grid and chart.
My panel's layout is set to border. In the center region I have a fit layout. Then trying to have 3 rows, but in one of the rows I want to put in a hbox. So far my layout is like this. If I remove the hbox it works, but I want to put multiple items in one of my rows.
Ext.define('ExtApplication4.view.historical.Historical', {
extend: 'Ext.panel.Panel',
xtype: 'app-historical',
controller: 'historical',
itemId: 'historicalItemId',
requires: [
'ExtApplication4.view.historical.HistoricalController',
'ExtApplication4.util.GlobalVar',
'Ext.chart.*'
],
title: 'Historical',
layout: {
type: 'border'
},
defaults: {
split: true,
bodyPadding: 15
},
items: [
{
title: 'Accounts',
region: 'west',
margin: '5 0 0 0',
width: 100,
//html: 'this is the menu account area',
dockedItems: [
{
xtype: 'toolbar',
dock: 'left',
//cls: 'myBgCls',
style: 'padding: 0; margin: 0;'
//items: [
// {
// xtype: 'combobox',
// itemId: 'comboboxClientItemID',
// emptyText: 'Select Client...',
// editable: false,
// displayField: 'clientName',
// valueField: 'clientName',
// bind: {
// store: '{myClientListStore}',
// selection: '{selectedClientListModel}'
// },
// listeners: {
// select: 'onComboboxSelect'
// },
// queryMode: "local"
// }
//]
}
]
},
{
title: 'Main Content',
region: 'center',
layout: {
type: 'fit'
},
items: [
{
layout: {
type: 'vbox',
align: 'stretch'
},
items: [
{
xtype: 'button'
},
{
flex: 1,
title: 'Sector',
xtype: 'grid',
ui: 'featuredpanel-framed',
itemId: 'attributionSectorGridID',
cls: 'custom-grid',
margin: '0px 0px 0px 0px',
bind: {
store: '{myAttributionGroupedStore}'
},
columns: [
{
header: 'Sector',
dataIndex: 'Sector',
flex: 1
},
{
header: 'P&L',
dataIndex: 'DailyPL',
renderer: function (value) {
var newVal;
var calc = value.toFixed(0).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
if (value > 0) {
newVal = '<span style="color:green">' + "$" + calc + '</span>';
} else if (value < 0) {
newVal = '<span style="color:red">' + "$" + calc + '</span>';
} else {
newVal = "$" + calc;
}
return newVal;
},
align: 'right',
flex: 1
}
]
},
{
xtype: 'panel',
flex: 3,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [
{
title: 'Winners',
xtype: 'grid',
ui: 'featuredpanel-framed',
itemId: 'attributionWinnersGridID',
cls: 'custom-grid',
margin: '5px 0px 0px 0px',
bind: {
store: '{myAttributionWinnersStore}'
},
columns: [
{
header: 'Sector',
dataIndex: 'Sector',
flex: 1
},
{
header: 'Market',
dataIndex: 'ShortDesc',
flex: 1
},
{
header: 'P&L',
dataIndex: 'DailyPl',
renderer: function (value) {
var newVal;
var calc = value.toFixed(0).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
if (value > 0) {
newVal = '<span style="color:green">' + "$" + calc + '</span>';
} else if (value < 0) {
newVal = '<span style="color:red">' + "$" + calc + '</span>';
} else {
newVal = "$" + calc;
}
return newVal;
},
align: 'right',
flex: 1
}
]
}
]
}
]
}
]
}
]
});
If "Layout Run Failed" after adding a hbox layout, check all items of the container you added the hbox layout on. The items in an hbox layout require a width, either as fixed width, as percentage or using flex (the latter only works if the width of the container can be derived from somewhere).
In your case, the grid seems not to have a width. Usually, the grid width would be calculated by adding up all the column widths (the default width of a column being 100), but since at least one column has a flex set, this does not work in your case.
Similarly, if it failed after adding a vbox layout, one of the items of the container with said layout does not have a height.
i have a grid panel and i want checked the row same as the value of text field.
anyone can help me.?
this is my code:
var check = new Ext.selection.CheckboxModel({
checkOnly : true,
listeners: {
change: function(checkbox, value) {
}
}
});
Ext.create('Ext.form.Panel', {
renderTo: "example-grid",
bodyStyle: 'padding: 5px 5px 0 5px;',
items: [
{
xtype: 'textfield',
fieldLabel: 'Group Fields ',
value:'a',
readOnly: true,
inputId: 'group'
}]
});
var grid1 = Ext.create('Ext.grid.Panel', {
title: 'Group Fields',
id:'gridPanel',
selModel: check,
store: Ext.data.StoreManager.lookup('tes'),
columns: [{
text: 'Field',
dataIndex: 'field',
flex: 1
}],
viewConfig: {
markDirty: false
},
height: 200,
width: 200
});
my fiddle example:
http://jsfiddle.net/y0uzha/f73kx37e/1/
Looks like you just need one-way binding so I would suggest to apply a selectionchange listener to the selectionModel to set the value of the groupField. See grid1#listeners#viewready. Note: I added an id to the form panel so that you can get a handle on it.
Generally speaking you should not use the id propery on child components, so they can be reusable. It would be better practice to use a viewport or a global parent container that has an id. Also, it would be best practice to use a controller to wire all this business logic together. Enjoy!
var check = new Ext.selection.CheckboxModel({
checkOnly: true
});
Ext.create('Ext.form.Panel', {
id: 'formPanel',
renderTo: "example-grid",
bodyStyle: 'padding: 5px 5px 0 5px;',
items: [{
itemId: 'groupField',
xtype: 'textfield',
fieldLabel: 'Group Fields ',
readOnly: true,
inputId: 'group'
}]
});
var grid1 = Ext.create('Ext.grid.Panel', {
title: 'Group Fields',
id: 'gridPanel',
selModel: check,
store: Ext.data.StoreManager.lookup('tes'),
columns: [{
text: 'Field',
dataIndex: 'field',
flex: 1
}],
viewConfig: {
markDirty: false
},
listeners: {
viewready: function() {
var selModel = this.getSelectionModel();
//Bind the groupField's value to the selected records
selModel.on('selectionchange', function(selModel, selections, eOpts) {
var groupField = Ext.getCmp('formPanel').queryById('groupField'),
groupValues = Ext.pluck(Ext.pluck(selections, 'data'), 'field');
groupField.setValue(Ext.Array.sort(groupValues).toString());
});
//Initially selects the first item in the grid
selModel.selectRange(0, 0);
}
},
height: 200,
width: 200
});
I have 2 combo box inside grid. The second combo box value will be change base on first combo box.
For example the combo has 3 item : America, Europe, Asia. If in the first combo box Europe is selected, then in the second combo box, Europe is not appear again.
I don't know which version of extjs I used, but here's the code :
MY COMBO STORE
var cb_group = Ext.create('Ext.data.Store', {
model: 'cb_group',
autoLoad: false,
proxy: {
type: 'ajax',
url: 'srv/master/group/combo',
reader: {
type: 'json',
root: 'rows'
}
}
});
MY COMBO INSIDE GRID
var set_approval_dtl = Ext.create('Ext.Window', {
title: title_approval2, width: 850, height: 395, rowdblclick: true, forceFit: true,
closeAction: "hide", store: ms_set_approval_dtl_store,
defaults: {
sortable: true, resizable: false
},
items: [
{xtype: "form", items: [
{layout: 'column', columnWidth: .5, itemId: 'set_approve', defaults: {border: false},
items: [{xtype: "panel", itemId: "set_approve_panel", height: 330, defaultType: 'textfield', margin: '0 10px 0 10px',
defaults: {labelWidth: 120, width: 850, maxLength: 200},
items: [
{xtype: "grid", itemId: "grid_items", width: 782, height: 280, margin: '0 10px 10px 10px', autoScroll: true,
plugins: Ext.create('Ext.grid.plugin.CellEditing', {clicksToEdit: 1, pluginId: 'rowEditing'}),
store: ms_set_approval_dtl_store, stripeRows: true, defaultType: "gridcolumn",
viewConfig: {forceFit: true},
columns: [
{header: grid18j, width: 150, dataIndex: 'nm_act', align: 'center'},
{header: subtitle_approval3, width: 126, dataIndex: 'level1', align: 'center',
editor: {xtype: "combobox", name: "cdgr", itemId: "cdgr1", typeAhead: true, editable: false, triggerAction: "all", forceSelection: true,
emptyText: grid8k, store: cb_group, valueField: "id", displayField: "nm",
listeners: {
expand: function(field, options, val) {
if (Ext.typeOf(field.getPicker().loadMask) !== "boolean") {
field.getPicker().loadMask.hide();
}
},
select: function(value) {
var obj = this.lastSelection[0].data;
return obj.nm;
this.lastSelection[0].hide;
cb_group.removeAt(0);
}
}},
renderer: function(val) {
var index = cb_group.findExact('id', val);
if (index !== -1) {
var rs = cb_group.getAt(index).data;
return rs.nm;
}
}
},
{header: subtitle_approval4, width: 126, dataIndex: 'level2', align: 'center', itemId: "level2",
editor: {xtype: "combobox", name: "cdgr", itemId: "cdgr2", typeAhead: true, editable: false, triggerAction: "all", forceSelection: true,
emptyText: grid8k, store: cb_group, valueField: "id", displayField: "nm",
listeners: {
expand: function(field, options) {
if (Ext.typeOf(field.getPicker().loadMask) !== "boolean") {
field.getPicker().loadMask.hide();
}
}
}
},
select: function(value) {
var obj = this.lastSelection[0].data;
return obj.nm;
},
renderer: function(val) {
var index = cb_group.findExact('id', val);
if (index !== -1) {
var rs = cb_group.getAt(index).data;
return rs.nm;
}
}
}]
}]}
]}]}
]});
I've tried this.lastSelection[0].hide; and cb_group.removeAt(0); in the first combo. But it didn't work at all. And I dont know why my select listener is not working.
please share some solution. Thanks
You can use XTemplates to manage this kind of behavior with one store and two comboboxes.
At first you have to create an XTemplate for your list of items in the combobox:
// displayfield = displayfield configured in your combobox
var template = Ext.create('Ext.XTemplate',
'<tpl for=".">',
' <tpl if="[Ext.getCmp(\'combobox1\').getValue()] != id && [Ext.getCmp(\'combobox2\').getValue()] != id">',
' <div class="x-boundlist-item">{label}</div>',
' <tpl else>',
' <tpl if="id == null || id == \'\'">',
' <div class="x-boundlist-item">{label}</div>',
' <tpl else>',
' <div class="x-boundlist-item" style="font-size:0px; height:0px;"></div>',
' </tpl>',
' </tpl>',
'</tpl>'
);
The XTemplate contains some statements to check if the specific value is already selected in one of the comboboxes. If not, then the entry will appear in the dropdown list, otherwise it will be hidden. To make it work, you have to set the template in your combobox and add some listeners to them:
// Combobox 1
{
xtype: 'combo',
id: 'combobox1',
store: 'your_store',
tpl: template,
displayField: 'label',
valueField: 'id',
listeners: {
beforeSelect: function (combo, record, index, eOpts)
{
// Check if the selected value is already selected in combobox2
var cbx2value = !!Ext.getCmp('combobox2').getValue() ? Ext.getCmp('combobox2').getValue() : '';
if (cbx2value != record.get('id') && cbx2value != record.get('id')) {
return true; // selected entry will be selected successfully
} else {
return false; // selected entry will not be selected
}
},
change: function ()
{
// Get the picker (list of items) of the other combobox and refresh it's template state
var cbx2picker = Ext.getCmp('combobox2').getPicker();
cbx2picker.refresh();
}
}
// Combobox 2
{
xtype: 'combo',
id: 'combobox2',
store: 'your_store',
tpl: template,
displayField: 'label',
valueField: 'id',
listeners: {
beforeSelect: function (combo, record, index, eOpts)
{
// Check if the selected value is already selected in combobox2
var cbx1value = !!Ext.getCmp('combobox1').getValue() ? Ext.getCmp('combobox1').getValue() : '';
if (cbx1value != record.get('id') && cbx1value != record.get('id')) {
return true; // selected entry will be selected successfully
} else {
return false; // selected entry will not be selected
}
},
change: function ()
{
// Get the picker (list of items) of the other combobox and refresh it's template state
var cbx1picker = Ext.getCmp('combobox1').getPicker();
cbx1picker.refresh();
}
}
It's not the ultimate solution, but for one of my projects it worked like a charm. I have simplified the example as good as possible to make the solution clearer.
You will need two stores, one for each combo box, both filled with the same data.
And then you will do:
combo1.on('select',function(combo, newVal) {
combo2.getStore().filterBy(function(rec){
return rec.get("value")!=newVal;
})
});
I'm pasting my updated code here. Please have a look and let me know what mistake I'm doing here. In the form itself I'm displaying the grid too.
So when I click on the record to edit, I need to populate the form where I can edit the corresponding record details and update into DB.
var grid = new Ext.grid.GridPanel({
frame: true,
store: store,
selModel: sm,
enableHdMenu: false,
stripeRows: true,
autoScroll: true,
trackMouseOver: true,
disableSelection: false,
loadMask: true,
enableColumnMove: false,
height: 350,
width: 960,
title: 'Edit Contractor Details',
columns: [{
header: "Requestor Name",
width: 75,
sortable: true,
dataIndex: 'requestorname'
}, {
header: "Start Date",
width: 85,
sortable: true,
xtype: 'datecolumn',
dataIndex: 'startdate',
dateFormat: 'n/j/Y'
}, {
header: "Supervisor",
width: 75,
sortable: true,
dataIndex: 'supervisor'
}, {
header: "Company",
width: 100,
sortable: true,
dataIndex: 'company'
}, {
header: "Last Name",
width: 75,
sortable: true,
dataIndex: 'lastname'
}, {
header: "First Name",
width: 75,
sortable: true,
dataIndex: 'firstname'
},
sm
],
tbar: [{
iconCls: 'contractor-add',
text: 'Edit Employee',
handler: function(grid, rowIndex, colIndex) {
alert("test");
var editWindow = new Ext.Window({
id: 'id_editWindow',
title: 'Edit',
closable: true,
width: 750,
height: 380,
plain: true,
layout: 'fit',
items: simple,
listeners: {
show: function EditUser(rec) {
var formpanel = Ext.getCmp('formPanel');
formpanel.getForm().loadRecord(rec);
}
}
});
editWindow.show();
}
}],
// customize view config
viewConfig: {
forceFit: true,
enableRowBody: true,
showPreview: true,
getRowClass: function(record, Index) {}
},
// paging bar on the bottom
bbar: new Ext.PagingToolbar({
store: store,
displayInfo: true,
displayMsg: 'Displaying Records {0} - {1} of {2}',
emptyMsg: "No cases to display"
})
});
//Form Creation
var simple = new Ext.form.FormPanel({
standardSubmit: true,
frame: true,
xtype: 'form',
// id: 'tabForm',
id: 'formPanel',
bodyPadding: 5,
width: 1000,
border: false,
bodyBorder: false,
fieldDefaults: {
labelWidth: 75,
msgTarget: 'side'
},
items: {
xtype: 'tabpanel',
id: 'tabpanel',
activeTab: 0,
defaults: {
bodyPadding: 10,
layout: 'anchor'
},
items: [{
title: 'New Contractor Details',
defaultType: 'textfield',
defaults: {
anchor: '100%'
},
items: [{
//Requestor Info
xtype: 'fieldset',
title: 'Requestor Details',
defaults: {
width: 150
},
fieldDefaults: {
msgTarget: 'side',
labelWidth: 300
},
defaultType: 'textfield',
layout: 'column',
labelWidth: 150,
defaults: {
anchor: '100%'
},
items: [{ // column #1
xtype: 'container',
columnWidth: .5,
layout: 'form',
items: [{
xtype: 'textfield',
fieldLabel: 'Requestor Name',
afterLabelTextTpl: required,
labelStyle: 'color:#000000',
name: 'requestorname',
id: 'requestorname',
//hasfocus:true,
anchor: '80%',
allowBlank: false,
listeners: {
afterrender: function(field) {
field.focus(false, 1000);
}
}
}, {
title: 'Manage Contractor Details',
// renderTo: bd,
// activeTab: 0, // first tab initially active
defaults: {
bodyPadding: 10
},
items: [grid]
}]
}],
buttons: [{
text: 'Submit',
formBind: true,
handler: function() {
var requestorname = Ext.getCmp('requestorname').getValue();
var form = Ext.getCmp('formPanel').getForm();
if (form.isValid()) {
//alert('Tests');
Ext.Ajax.request({
url: 'NewHireDetailsInsertion?firstname=' + firstname + '&' + 'middlename=' + middlename + '&' + 'lastname=' + lastname +
'&' + 'suffix=' + suffix + '&' + 'company=' + company + '&' + 'requestorname=' + requestorname + '&'...so on...
method: 'POST',
submitEmptyText: false
});
simple.getForm().getEl().dom.action = 'NewHireDetailsInsertion';
//Ext.Msg.maxWidth =2000;
Ext.Msg.alert('Message', "New Hire information Submitted");
simple.getForm().reset();
} else {
Ext.Msg.alert('Message', "Please enter all required fields");
}
}
}, {
text: 'Reset',
handler: function() {
simple.getForm().reset();
}
}]
}]
}]
});
});
simple.render('mydiv');
You could have provided a bit more sample code, as well as ensured that the code you provided was formatted correctly... As so, the example I'm providing should guide you in the right direction if I understand what you are trying to achieve.
It is very messy to put logic into your views, which is what I see you are doing in the code you have provided. The role of the controller in ExtJS MVC is to observe the events fired by views (or other controllers!) and react accordingly.
You can save yourself a lot of time and headache by establishing reference's (refs) on the Controller for commonly accessed components. In your scenario, both your Grid and Window would make great candidates for references.
Have a look at the Controller documentation for a more thorough explanation of ref capabilities, as well as the Controller's control function: http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.app.Controller
Ext.define('My.controller.Grid', {
extend: 'Ext.app.Controller',
/** List required views, models, stores here */
refs: [
{
name: 'grid',
selector: '',
xtype: 'my-grid' // Defined in the Grid's config i.e., alias: 'widget.my-grid'
},{
name: 'editWindow',
selector: '',
xtype: 'my-edit-window',
autoCreate: true // Automatically create this if it isn't already created
}
],
init:function(app){
/** Observe your Views by their itemId or any valid ComponentQuery selector */
'#my-grid-panel': {
itemdblclick: { fn: this.onGridRecordDoubleClick, scope: this }
},
'#my-edit-window': {
afterrender: { fn: this.editWindowDidRender, scope: this },
close: { fn: this.onWindowClose, scope: this }
}
},
onGridRecordDoubleClick: function(grid, record, element, index, event){
/** save a reference to the selected record on the controller instance */
this.selectedRecord = record;
/** Show the 'Edit' Window if possible */
if(!this.activeWindow)
this.getEditWindow(); // Magic method created by Controller Reference
},
editWindowDidRender: function(view){
/** Get the Form by its itemId */
var myForm = view.down('#my-form');
/** Load the selected record into the form */
myForm.loadRecord(this.selectedRecord);
/** Save a reference to the window, why not? */
this.activeWindow = view;
},
onWindowClose: function(){
/** remove the reference to the window and selected record */
this.activeWindow = undefined;
this.selectedRecord = undefined;
/** Clear selection on the grid */
this.getGrid().getSelectionModel().clearSelections();
this.getGrid().reconfigure();
}
});
I am trying to edit an information using editor grid. I have three fields, Interview By (combo), Date (date) and Performance (number), I get the date and the performance column, but the combo is not displaying the value initially. But when I click, then it shows the correct value. I am new to extjs and googled it for a solution, but could not find it. Kindly help me with a solution. Thanks in advance.
MY CODE:
initComponent: function() {
this.createTbar();
this.columns = [
{ xtype:'numbercolumn',
hidden:true,
dataIndex:'interview_id',
hideable:false
},
{ xtype: 'gridcolumn',
dataIndex: 'interview_by_employee_id',
header: 'Interview By',
sortable: true,
width: 290,
editor: {
xtype: 'combo',
store: employee_store,
displayField:'employee_first_name',
valueField: 'employee_id',
hiddenName: 'employee_first_name',
hiddenValue: 'employee_id',
mode: 'remote',
triggerAction: 'all',
forceSelection: true,
allowBlank: false ,
editable: false,
listClass : 'x-combo-list-small',
style: 'font:normal 11px tahoma, arial, helvetica, sans-serif'
},
renderer: function(val){
index = employee_store.findExact('employee_id',val);
if (index != -1){
rs = employee_store.getAt(index).data;
return rs.employee_first_name;
}
}
},
{ xtype: 'gridcolumn',
dataIndex: 'interview_date',
header: 'Date',
sortable: true,
readOnly: true,
width: 100,
editor: {
xtype: 'datefield'
}
},
{ xtype: 'numbercolumn',
header: 'Performance',
format:'0',
sortable: true,
width: 100,
align: 'right',
dataIndex: 'interview_performance',
editor: {
xtype: 'numberfield'
}
}
];
candidate_grid_interview.superclass.initComponent.call(this);
}
and the screen shots,
I faced the same problem and found my solution somewhere. Here is a reduced version of what I'm using. I think the key was the renderer property on the column. If your combo uses remote data, it might be loading its content after the grid is done loading - but I'm not sure it will cause the problem you're describing.
Try this concept:
var myStore = new Ext.data.JsonStore({
autoLoad: false,
...
fields: [
{ name: 'myID', type: 'int' },
{ name: 'myName', type: 'string' }
],
listeners: {
load: function () {
// Load my grid data.
},
scope: this
}
});
var myCombo = new Ext.form.ComboBox({
...
displayField: 'myName',
valueField: 'myID',
store: myStore
});
var grid = new Ext.grid.EditorGridPanel({
store: new Ext.data.ArrayStore({
...
fields: [
...
{ name: 'myID', type: 'int' },
...
]
}),
...
cm: new Ext.grid.ColumnModel({
columns: [
...
{
header: 'Header',
dataIndex: 'myID',
editor: myCombo,
renderer: function (value) {
var record = myCombo.findRecord(myCombo.valueField, value);
return record ? record.get(myCombo.displayField) : myCombo.valueNotFoundText;
}
}]
})
});
myStore.load();
Store loading is asynchronous, so it might be loading itself after rendering the grid. I recommend you render your grid within the store onload event. Also, datatypes can be painfull if you don't pay enough attention. Be sure that your grid store and combo store types match.