I have a list item that is populated by a store. Once the store loads, the list does not seem to resize with the proper height. The height is in fact zero. Do you guys have any recommendations on having the list re-calculate its height after loading the store?
My view:
xtype: 'fieldset',
cls: 'damage-list-fieldset',
margin: '',
itemId: 'damageFieldSet',
flex: 1,
layout: {
type: 'fit'
},
items: [
{
xtype: 'list',
action: 'showNotes',
cls: 'damage-list',
itemCls: 'x-list-item-label',
itemId: 'DamageList',
disableSelection: true,
height: 'auto',
emptyText: 'No damage has been reported',
itemTpl: [
'<table border="0" width="100%">',
' <tr>',
' <td class="part" width="30%">{part}</td>',
' <td class="note" width="30%">{date}</td>',
' <td class="type" width="30%">{type}</td>',
' <td class="note" width="10%"><div class="count">{noteCount}</div></td>',
' </tr>',
'</table>',
''
],
store: 'Damage',
grouped: true,
onItemDisclosure: false
}
]
},
I realize the itemTpl shouldn't have tables in it, but let's ignore that for now.
Here's how I'm currently forcing it to work. I push the height from the controller store load callback.
Ext.getStore('Damage').load({
params: {repairOrderId: this.repairOrderId},
callback: function(records, operation, success) {
if(records.length) {
report.getComponent('noteInstruction').setHidden(records.length == 0);
/* Calculate the height of the damage rows and set it*/
var location = new Array();
var locationCount = 0;
for(var i = 0; i < records.length; i++) {
if(location.indexOf(records[i].data.location) < 0) {
location.push(records[i].data.location);
locationCount++;
}
}
var damageRow = 54;
var damageHeader = 56;
var damageHeight = (records.length * damageRow) + (locationCount * damageHeader);
report.getComponent('damageFieldSet').getComponent('DamageList').setHeight(damageHeight);
report.getComponent('damageFieldSet').getComponent('DamageList').setScrollable(false);
}
Ext.Viewport.setMasked(false);
},
scope: this
});
Not very elegant, because I'm just jamming in a set height.
So the question is, how do I force the list to redraw its height after getting the records back from the store?
The loading process is async and your callback from the load does not neccessarily affect the list.
Height can be read from the list.element.html and you do not need to calculate the height, as the list already has a list.
Load already updates the the list automatically.
The list component of Sencha 2.2.1 is generated in a different way. It only generates the number of visible items plus 1 and switches location of the listitems
height:'auto' would be best replaced with flex: 1
I would recommend, that you
delete your callback
call the store to see if there are items in the store
set the listitem height to a fix value (do not try to set the height of each row in the list, otherwise use dataview and set the height on dataview upatedata event)
remember that dataview is way slower than list and that on a list all items are meant to have the same height
And last but not least you can use on the list config:
variableHeights: true
Related
I am working with ExtJS 4.2.1
I have a button to make appear a panel.
This panel is containing my treepanel, five checkboxes below, and finally one valid button (to close the treepanel and valid the fact that we checked some nodes) and one cancel button (just to cose the treepanel).
I can make my panel appear and it works fine. But if I click on my cancel or my valid button, the panel will hide (ok), and next time I try to show it it doesn't contain my treepanel anymore, only the five checkboxes and the two buttons (attention, the two panels are different, the panel is containing my treepanel).
I don't understand because there is no reason for it to disappear. When I check the treepanel with some console.log() I can see, passing by treepanel.store.tree.root that my treepanel still exists and is properly filled. When I pass through treepanel.view.all I can see the right elements are present in my view. But when I check treepanel.body.dom with chrome debugging I can't see where the element is (ordinary when you pass over the dom with the mouse on chrome debugging you can see the corresponding part of the page colored).
Here is the concerned part of my code:
var button = Ext.get('ProductSelectionButton');
var treeSelector = createTree('stAddAction.do?action=product_tree_selector', 550, 490, '', 'lbl_st_tree_selection_empty', true, 'productlist');
button.on('click', function(){
treeSelector.store.proxy.url = 'stAddAction.do?action=product_tree_selector';
treeSelector.store.reload();
var productPanel = Ext.create('Ext.FormPanel',{
fieldDefaults:{
labelWidth: 75 // label settings here cascade unless overridden
},
frame:true,
title: document.getElementById('applicability').innerHTML + ' - ' + document.getElementById('lbl_st_product_tree_win').innerHTML,
style:'padding: 5px 5px 0; margin-top: 0;',
width: 550,
items: [treeSelector,
{
xtype: 'checkboxgroup',
items: [
{boxLabel: document.getElementById('lbl_status_deleted').innerHTML, name: 'status_2', checked: false, ctCls:'check-status-2',
listeners: {
change: function(newValue, oldValue, eOpts ){
if(newValue.checked){
// To show items with status 2 which is Deleted status
Ext.Array.remove(statusToHide, "2");
ProductList.showIdsStatus(2);
}
else{
// To hide items with status 2 which is Deleted status
Ext.Array.push(statusToHide, "2");
ProductList.hideIdsStatus(2);
}
}
},
... four others checkboxes
}],
buttons: [{
icon : 'img/st_little_valid.png',
style:'width:20px!important;',
handler: function(){
var data = '',
selNodes = treeSelector.getCheckedNodes(treeSelector.getRootNode());
precedentlyCheckedNodes = selNodes;
xhr = getXhr();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4 && xhr.status == 200) {
var myLoad = eval(myDataGrid);
productgrid.store.loadData(myLoad);
productgrid.getView().refresh();
win.hide();
enableSave();
}
}
var params = "action=set_iceproduct&datatoadd=" + data + "&datatoremove=" + strUnchecked;
xhr.open("POST", "stAddAction.do", true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('Content-length', params.length);
xhr.send(params);
}
},
{
icon : 'img/st_little_cancel.png',
handler: function(){
/* restore all nodes how they were before (checked or unchecked) */
treeSelector.verifyCheckedNodes(precedentlyCheckedNodes);
win.hide();
/* Only expand the first level */
treeSelector.collapseAll();
treeSelector.getRootNode().expand();
}
}]
});
I don't know if it really is quite explicit...
Anyway, any idea could be welcomed!
How can this treepanel disappear from my panel and still exist!
Thank you
You are calling Ext.create in the buttons click event function every time. This means that the first time you create it, it's okay. But when you click the button again, it will create another panel with the same configuration, only you can't have treeSelector in both because it is already somewhere else. Change your code to something like:
var button = Ext.get('ProductSelectionButton');
var treeSelector = createTree('stAddAction.do?action=product_tree_selector', 550, 490, '', 'lbl_st_tree_selection_empty', true, 'productlist');
button.on('click', function(button){
treeSelector.store.proxy.url = 'stAddAction.do?action=product_tree_selector';
treeSelector.store.reload();
if(!button.productPanel)
{
button.productPanel = Ext.create('Ext.FormPanel',{
fieldDefaults:{
labelWidth: 75 // label settings here cascade unless overridden
},
frame:true,
title: document.getElementById('applicability').innerHTML + ' - ' + document.getElementById('lbl_st_product_tree_win').innerHTML,
style:'padding: 5px 5px 0; margin-top: 0;',
width: 550,
items: [
treeSelector,
{
xtype: 'checkboxgroup',
items: [
{boxLabel: document.getElementById('lbl_status_deleted').innerHTML, name: 'status_2', checked: false, ctCls:'check-status-2',
listeners: {
change: function(newValue, oldValue, eOpts ){
if(newValue.checked){
// To show items with status 2 which is Deleted status
Ext.Array.remove(statusToHide, "2");
ProductList.showIdsStatus(2);
}
else{
// To hide items with status 2 which is Deleted status
Ext.Array.push(statusToHide, "2");
ProductList.hideIdsStatus(2);
}
}
In my project, I am trying to change the background color of all the panels inside a container. The code which I am trying is as follows:
container --> panel (don't change) --> panel (Change)
//Generated dynamically using for loop.
listeners: {
'render': function(panel) {
panel.body.on('click', function() {
//here change the background color of all the panels inside the container>panel.
});
}
}
What should I write to change the background color of the only panels which are present inside the parent panels of a main container?
I tried:
Ext.each('panel',function(){this.body.setStyle('background','white')}),
But the above approach is giving me the following error:
Uncaught TypeError: Cannot call method 'setStyle' of undefined
EDIT:
Here, I am looking for a method of extjs which quite do the same work as jQuery's children().
$('#containerID').children('panel').children('panel').css(change background color);
Based on your requirements you will always have a sum of 9 components you are looking at -1 the you start from. The shortest way is to use the each() method of the MixedCollection (at runtime all items are within a MixedCollection)
'render': function(panel) {
panel.body.on('click', function() {
panel.items.each(function(p){ p.body.setStyle('background','white'); }, this)
},this);
}
This may not be the variant with the best performance but knowing your requirement from the last question I can say that this is the easiest. And in addition it will be easy to maintain. And read the article about delegates that I posted in the comments of the last question!
I hope there is now typo, cause it is untested
Update
Well, you are looking for the ownerCt property here (at least that is the easiest way). But there are some mightier navigation methods up() / down() both can be feeded with a ComponentQuery string. Leave the up() arguments empty will return the immediate owner/activater (basically the same as ownerCt).
Following a working example:
var childItems = [], items = [];
for (i = 0; i < 9; ++i) {
childItems.push({
xtype: 'container',
width: 50,
height: 50,
html: i + '',
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
listeners: {
'afterrender': function(panel) {
panel.el.on('click', function(e,t) {
panel.el.on('click', function(e,t) {
panel.el.setStyle('background','red');
panel.ownerCt.items.each(function(p){ if(panel.el.id != p.id) p.el.setStyle('background','white'); })
});
}
}
});
}
for (i = 0; i < 9; ++i) {
items.push({
xtype: 'container',
layout: {
type: 'table',
columns: 3
},
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
items: childItems
});
}
Ext.create('Ext.container.Container', {
layout: {
type: 'table',
// The total column count must be specified here
columns: 3
},
renderTo: Ext.getBody(),
style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px', margin: '30px'},
items: items
});
Update 2
To reset all try this (untested)
'afterrender': function(panel) {
panel.el.on('click', function(e,t) {
panel.el.setStyle('background','red');
panel.ownerCt.ownerCt.items.each(function(op){
op.items.each(function(p){
if(panel.el.id != p.id)
p.el.setStyle('background','white');
})
}, this)
});
}
JSFiddle
So if I have a gridpanel in ExtJS 4, how do I check for a value in it?
I'm building a pop-up window to add a value to the gridpanel, and I want to make sure that the value the user is trying to add to the gridpanel isn't already listed in the grid panel.
I've been searching the docs for a while and googling around and haven't found anything.
I added the following code to the bottom of the example at http://dev.sencha.com/deploy/ext-4.0.7-gpl/examples/grid/array-grid.html
Hopefully it's a start for you, though you might have additional things to consider such as the following in order to devise the most robust solution:
What if the same value can occur multiple times in the grid?
What if the data in the grid is paginated?
CODE:
dockedItems: [{
xtype: 'toolbar',
items : [ {
xtype: 'button',
text: 'Seek Value',
handler: function() {
Ext.Msg.prompt('Value in Grid?', 'Search:', function(btn, text){
if (btn == 'ok' && text){
var columnNames = Ext.Array.pluck(grid.columns, 'dataIndex');
grid.store.data.each(function(record, index) {
for (var i=0,n=columnNames.length; i<n; i++) {
var columnName = columnNames[i];
if (columnName) { //protects against null dataIndex using pluck above
if (record.get(columnName) == text) {
console.log(index); //row
console.log(columnName);
return;
}
}
}
});
}
});
}
}],
dock: 'bottom'
}]
I'm using ExtJS's GridPanel library to render a list of rows that have a CheckboxModel for selections. There is also a summary row that adds up all of the selected data and displays it in a row at the bottom of the GridPanel. The code for this is:
var sm = Ext.create('Ext.selection.CheckboxModel', {
/////////
// With large number of rows ... this takes forever
/////////
grid.getView().refresh();
/////////
/////////
listeners:{
selectionchange: function(selectionModel, selectedRecords, options){
// Do stuff
}
}
});
var selSumFn = function(column, selModel){
return function(){
var records = selModel.getSelection(),
result = 0;
//console.log("records:" + records.length);
Ext.each(records, function(record){
result += record.get(column) * 1;
});
return result;
};
};
var grid = Ext.create('Ext.grid.Panel', {
autoScroll:true,
features: [{
ftype: 'summary'
}],
store: store,
defaults: {
sortable:true
},
selModel: sm,
columns: [
{header: 'Column 1', width: 100, dataIndex: 'col1', summaryType: selSumFn('col1', sm)},
{header: 'Column 2', width: 100, dataIndex: 'col2', summaryType: selSumFn('col2', sm)}
],
width: 730,
height: 400 ,
title: 'Data',
renderTo: 'data-div',
viewConfig: {
stripeRows: true
},
listeners: {'beforerender' : {fn:function(){this.store.load();}}}
});
Is there any way to only refresh the summaryrow feature and not the entire view? Refreshing the view was the only way I could find to refresh the summary row when updates were made to checkbox selections of the GridPanel.
There is no support for this in Ext 4.0.2a. The grid view builds a single view template with features adding or modifying this template via a multitude of defined hooks. The result is a single template instance that cannot be easily dissected.
The best solution I found is to rebuild the template fragment that renders the summary row mimicking what the grid view is doing during the template construction process. Then overwrite the existing DOM for the summary row with a freshly rendered version.
I have created a patch (as an override) that adds a refresh() method to the Summary feature.
The code turned out to be surprisingly slick.
Ext.require('Ext.grid.feature.Summary', function() {
Ext.override(Ext.grid.feature.Summary, {
refresh: function() {
if(this.view.rendered) {
var tpl = Ext.create(
'Ext.XTemplate',
'{[this.printSummaryRow()]}',
this.getFragmentTpl()
);
tpl.overwrite(this.getRowEl(), {});
}
},
getRowEl: function() {
return this.view.el.down('tr.x-grid-row-summary');
}
});
});
In your selectionchange listener:
selectionchange: function(selectionModel, selectedRecords, options) {
grid.getView().getFeature(0).refresh();
}
See this JsFiddle for a live demo.
Of course this might break in future versions of Ext. However, it could turn out to be quite robust since it delegates most of its work to existing methods.
If you are using GroupingSummary, you need to use this instead:
refresh:function(){
var rowEls = this.view.el.query('tr.x-grid-row-summary');
var i = 1;
Ext.Array.each(this.summaryGroups, function(group){
var tpl = new Ext.XTemplate(
this.printSummaryRow(i),
this.getFragmentTpl()
);
tpl.overwrite(rowEls[i-1], {})
i++;
},this);
I am using GridPanel w/CheckboxSelectionModel for item selection.
In the edit mode, where some options were already picked, I am trying to pre-select the rows when loading the form.
...
store.load();
//curSelections is an array containing the some ForeingKey IDs of the selected records.
...
for (var i = 0; i < curSelections.length; i++) {
console.log('found personel ' + curSelections[i] + ' at ',
store.findExact('Id', curSelections[i]));
selectedRecords.push(store.findExact('Id', curSelections[i]));
}
//everything is fine according to console log.
checkGrid.getSelectionModel().selectRecords(selectedRecords, true);
formWin.show();
this does not work.
I try to call" selectRecords" also on some other page/form events, but none of those even fires.
grid.addListener('show',
grid.on('show',
formWin.on('activate',
formWin.on('show',....
some of the grid code
var sm = new Ext.grid.CheckboxSelectionModel({
singleSelect: false,
sortable: false,
checkOnly: true
});
checkGrid = new Ext.grid.GridPanel({
xtype: 'grid',
store: obPersonelStore,
loadMask: true,
layout: 'fit',
height: 120,
id: 'grdIsBirimiPersonelListesi',
columns: [
sm,
{
I am missing something simple, but dont know what it is.
Any kind of help is greatly appreciated.
Store.findExact returns a numeric index. SelectionModel.selectRecords expects an array of Record objects. Have you tried selectRows instead? Either that, or use store.getAt to retrieve records by index to pass to selectRecords().
try:
var store = new Ext.data.Store({
...
});
var grid = new Ext.grid.GridPanel({
store: store,
...
});
store.on('load', function() {
grid.getSelectionModel().selectFirstRow();
});
store.load();
I'm not 100% certain what you want to achieve. You said:
I find the selected rows of the entire list
Do you mean you want to select every row? In that case you can use the selectAll() method of the CheckboxSelectionModel.
If you only want to select some of the rows then I'd need to see the code you're using to get those rows in the first place but it could be that you want to use selectRecords() rather than selectRows().