How can I re-render this Ext.Component when a combo box option is selected?
var searchForm = Ext.create('Ext.form.Panel', {
width: 320,
style: 'margin: 20px',
renderTo: 'SearchPanel',
style: {
position: 'fixed',
top: '0px',
left: '865px'
},
items: [{
xtype: 'combo',
width: 300,
labelAlign: 'right',
fieldLabel: 'Subject Area',
store: subjectAreaStore,
valueField: 'id',
displayField: 'value',
typeAhead: true,
mode: 'local',
triggerAction: 'all',
selectOnFocus: true,
value: 'Account',
listeners: {
select: function (combo) {
cmp.autoEl.src = '/' + combo.getValue() + '/2nd Iteration.htm';
alert(cmp.autoEl.src);
cmp.render(); // this does not work!
}
} // listeners
}]
});
// create the cmp
var cmp = Ext.create('Ext.Component', {
title: 'Data Models',
style: {
width: '100%',
height: '750px'
},
autoEl : {
tag : 'iframe',
src : '/Account/2nd Iteration.htm'
},
renderTo: 'models'
});
Update: 10/23/2012:
This isn't working yet:
listeners: {
select: function (combo) {
cmp.autoEl.src = '/' + combo.getValue() + '/2nd Iteration.htm';
var the_iframe = cmp.getEl().dom;
the_iframe.contentWindow.location.reload();
}
} // listeners
I would suggest a different approach to creating the iframe. Just use the html property of a component and write the html yourself instead of using the autoel feature (never done this with a component, only a container but it should work the same)...
var cmp = Ext.create('Ext.Component', {
title: 'Data Models',
style: {
width: '100%',
height: '750px'
},
renderTo: 'models',
html: '<iframe src="/Account/2nd Iteration.htm"></iframe>'
});
Then do this in the listener to update it...
listeners: {
select: function (combo) {
cmp.update('<iframe src="/' + combo.getValue() + '/2nd Iteration.htm"></iframe>');
}
}
The render() method only deals with HTML that was created (rendered) by ExtJS. You created that iframe yourself, so you have to control it yourself. You should be able to get the DOM element from the Component like this:
var the_iframe = cmp.getEl().dom;
the_iframe.contentWindow.location.reload();
Related
I am using extjs 3.4
I have panels added dynamically to parent panel.
I would like to catch value of iterator (i) on click.
Value of this iterator is saved in hidden element:
xtype: 'hidden',
cls: 'hidden-ID',
value: i
so basically on click I should be able to find this sibling (perhaps by class name or type?).
But I really don't know how - I've alredy tried to find parent, but from parent I wasn't able to find children.
Example is here
Code:
Ext.onReady(function () {
var eleCatDisplay2 = new Ext.Panel({
renderTo: Ext.getBody(),
height: 350
});
for (i = 0; i < 10; i++) {
eleCatDisplay2.add(new Ext.Panel({
layout: 'hbox',
border: false,
style: {
marginTop: '10px'
},
items: [{
xtype: 'displayfield',
flex: 1,
value: 'rowNum__' + i.toString()
}, {
xtype: 'hidden',
cls: 'hidden-ID',
value: i
}, {
xtype: 'panel',
flex: 0.3,
border: false,
html: '<div>click to send</div>',
listeners: {
'render': function (panel) {
panel.body.on('click', function () {
//here I would like to catch value of i
alert('test');
});
}
}
}]
}));
}
eleCatDisplay2.doLayout();
});
You can also store value in some custom property of the panel:
Ext.onReady(function () {
var eleCatDisplay2 = new Ext.Panel({
renderTo: Ext.getBody(),
height: 350
});
for (i = 0; i < 10; i++) {
eleCatDisplay2.add(new Ext.Panel({
layout: 'hbox',
border: false,
style: {
marginTop: '10px'
},
items: [{
xtype: 'displayfield',
flex: 1,
value: 'rowNum__' + i
}, {
xtype: 'hidden',
cls: 'hidden-ID',
value: i
}, {
xtype: 'panel',
flex: 0.3,
border: false,
html: '<div>click to send</div>',
somePropertyName: i,
listeners: {
'render': function (panel) {
panel.body.on('click', function () {
console.log(panel.somePropertyName);
});
}
}
}]
}));
}
eleCatDisplay2.doLayout();
});
Solution (on display field I've add cls: 'display-cat-name'):
var cNM = Ext.getCmp(this.up('.hbox-parent').select('.display-cat-name').elements[0].id).value;
var catId = this.up('.hbox-parent').select('.hidden-ID').elements[0].value;
I have a list of images that I can choose from, and each one of them has different dimensions. In order to maintain aspect ratio, I'm only setting the width on the image, so the browser determines which height the image should be given. Unfortunately, because I don't have a height, Ext JS is unsure what height to give the container, so it doesn't update it after the first image is rendered.
In the example below, you'll see the first image renders properly and sets the height of the panel's body. If you select the other image in the combobox, it won't set the height, and it'll be cut off. However, if you uncomment the bodyCls property, and re-run the example, it will behave as it should... the image selection changes the height of the panel dynamically.
This seems a little hacky to me, and I don't like using float: left directly, but I want these items to be laid out in an hbox fashion, so I'm wondering if there's a better way of accomplishing this. Does someone have a better solution?
And no, I don't want to use object-fit or background-size: cover;
Here's the Fiddle and code:
Ext.application({
name: 'Fiddle',
launch: function () {
var f = Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
border: true,
bodyStyle: 'border-color: blue !important;',
height: 'auto',
referenceHolder: true,
// layout: {
// type: 'hbox',
// columns: 2
// },
// layout: 'fit',
defaults: {
style: 'float: left;'
},
// This style add height: 100% to the body
// bodyCls: 'blah',
margin: 5,
bodyPadding: 5,
viewModel: {
stores: {
logosStore: {
autoLoad: true,
proxy: {
url: 'data1.json',
type: 'ajax'
}
}
}
},
items: [{
xtype: 'image',
width: 200,
reference: 'blah',
hidden: true,
bind: {
src: '{record.logoSrc}',
hidden: '{!record.logoSrc}'
}
}, {
xtype: 'combobox',
valueField: 'logoFileId',
displayField: 'name',
queryMode: 'local',
forceSelection: true,
margin: '0 0 0 40',
value: 2,
listConfig: {
itemTpl: '<img src="{logoSrc}" style="max-height: 40px;" />'
},
bind: {
store: '{logosStore}',
selection: '{record}'
},
listeners: {
select: function (combo, record) {
f.getViewModel().notify();
// f.setHeight(f.lookupReference('blah').getHeight());
// f.lookupReference('blah').getEl().dom.setAttribute('background-image', 'url("' + record.get('logoSrc') + '")');
}
}
}]
})
}
});
EDIT
My solution starts to break down when you have my component being used in another container with several other components. See this Fiddle, but it works if you uncomment the cls property in the MyForm component... just seems wrong that I have to add height: 100% !important to everything. Like maybe there's a layout that I could use instead.
I did come up with a solution, and that was to employ a little bit of JavaScript... I basically wait for the image to load, grab the current height of the image, and update the maxHeight of its container, so it can report its height back to its parent container. The one odd thing is, if the maxHeight is below a certain threshold, I want to keep it at 150, and if the threshold is hit twice or more, when I do setMaxHeight(150), it doesn't actually update the height of the image. That's why I setMaxHeight(null) first if the threshold hasn't been met. An example of this was when I selected the 2nd image first, and then the 3rd image... the 3rd image would be cut off if I didn't setMaxHeight(null).
I think this is an acceptable solution, but once again, I'm wondering if there's a layout that'll do this for me, or I'm not understanding a certain layout or nesting components.
Fiddle and code:
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('MyForm', {
extend: 'Ext.form.Panel',
alias: 'widget.myForm',
border: true,
bodyStyle: 'border-color: blue !important;',
referenceHolder: true,
scrollable: true,
layout: 'fit',
margin: 5,
bodyPadding: 5,
tools: [{
xtype: 'button'
}],
viewModel: {
stores: {
logosStore: {
autoLoad: true,
proxy: {
url: 'data1.json',
type: 'ajax'
}
}
}
},
items: [{
xtype: 'container',
reference: 'blah2',
scrollable: true,
height: 150,
maxHeight: 150,
layout: {
type: 'hbox'
},
items: [{
xtype: 'image',
width: 200,
reference: 'blah',
hidden: true,
bind: {
src: '{record.logoSrc}',
hidden: '{!record.logoSrc}'
},
listeners: {
el: {
load: function () {
f.getViewModel().notify();
var blah2 = f.lookupReference('blah2');
var height = f.lookupReference('blah').getHeight();
if (height < 150) {
height = 150;
blah2.setMaxHeight(null);
}
console.log(blah2.setMaxHeight(height), height);
}
}
}
}, {
xtype: 'combobox',
valueField: 'logoFileId',
displayField: 'name',
queryMode: 'local',
forceSelection: true,
margin: '0 0 0 40',
value: 2,
width: 350,
listConfig: {
itemTpl: '<img src="{logoSrc}" style="max-height: 40px;" />'
},
bind: {
store: '{logosStore}',
selection: '{record}'
}
}]
}]
});
var f = Ext.create('MyForm', {
renderTo: Ext.getBody()
});
}
});
I am trying to populate a tabpanel with an extension I've created. Inside this extension i have a panel with 2 fields (timefield and datefield) which may have the values from my store.
Each of these fields may have different values in each tab. I am passing these values from the extended component via config. So far I can see these values in the console.log() but I can't put these values inside the fields.
This is how my extended component is:
Ext.define('PlaylistGrid', {
extend: 'Ext.panel.Panel',
alias: 'widget.playlistgrid',
border: false,
config: {
plIndex: 0,
plDate: '1970-10-10',
plTime: '00:00:00'
},
constructor: function(cfg) {
Ext.apply(this, cfg);
this.callParent(arguments);
},
items: [{
layout: 'hbox',
bodyStyle: 'padding: 5px',
border: false,
xtype: 'form',
name: 'myForm',
items: [{
xtype: 'datefield',
fieldLabel: 'Data de início',
name: 'datefld',
itemId: 'datefld'
}, {
xtype: 'timefield',
fieldLabel: 'Horário de início',
name: 'timefld'
}, {
xtype: 'button',
iconCls: 'save',
style: 'margin-left: 10px',
tooltip: 'Salvar data e hora',
handler: function() {
Ext.Msg.alert('Salvando...', 'Implementar');
}
}]
}, {
xtype: 'grid',
border: false,
width: '100%',
height: 476,
columns: [{
header: 'Ordem',
dataIndex: 'order',
width: 50
}, {
header: 'Video',
dataIndex: 'video',
width: 308
}, {
header: 'Duracao',
dataIndex: 'duration',
width: 100
}, {
header: 'Formato',
dataIndex: 'format',
width: 75
}]
}],
listeners: {
render: function(e, eOpts) {
console.log(e.getPlDate());
}
}
});
And this is how I am adding this component inside the tabpanel:
var plSt = Ext.getStore('playlistStore');
plSt.load();
plSt.on('load', function(store, records, successful, eOpts) {
plSt.each(function(record, idx) {
var playlist = {
xtype: 'playlistgrid',
title: 'Playlist ' + (records[idx].data.playlistId),
name: 'playlist' + idx,
plIndex: records[idx].data.playlistId,
plDate: records[idx].data.playlistDate,
plTime: records[idx].data.playlistTime
};
e.add(playlist);
});
if (records.length > 0) {
e.setActiveTab(1);
}
})
The data seems to be ok, but it does not display in the datefield... Do you have any point about it?
I have already search how to do this, but couldn't find the answer at all.
SOLVED
OK, I got it. The solution was simple. I just added a new config var that passes the current tab index, and the afterRender method.
I did this
afterRender: function(e, eOpts) {
var idx = e.getTabIdx();
var dateFld = Ext.ComponentQuery.query('datefield[name=datefld]');
dateFld[idx].setValue(new Date(e.getPlDate()));
//console.log(e.getPlDate());
}
Thank you!
I am writing a Rally App in which I have a rallychart and a button.
I need to access the chart and modify its setting on a button click. The button is also in the same app container as the rallychart.
I tried Ext. this. etc.
These access specifiers do not work. Could you please help me with this?
Sample code:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
id: 'appid',
launch: function () {
var datepickerfrom = Ext.create('Ext.Container', {
items: [{
xtype: 'rallytextfield',
fieldLabel: 'Enter Start Date for chart (mm/dd/yyyy): ',
labelWidth: 150
}],
renderTo: Ext.getBody().dom,
id: 'd1'
});
this.add(datepickerfrom);
this.add(
{
xtype: 'rallychart',
height: 400,
width: 800,
id: 'chart1',
itemId: 'chart1',
chartConfig: chartConfig,
renderTo: Ext.getBody().dom
}
);
button2 = {
xtype: 'rallybutton',
text: 'Plot Graph',
handler: function () {
console.clear();
console.log("Clicking button");
// I NEED to ACCESS the CHART HERE or EVEN the TEXTFIELD DATA HERE
},
callback: function(){
}
};
this.add(button2);
You may reference them via itemID. After the itemID on the element is set:
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {//...}
//...
}
it can be used to reference the element:
this.down('#myChart')
In addition to what Nick said (referencing by id) you can create a variable for each one as you define them like so:
var pickerForm = this.add(datepickerfrom);
var chart = this.add({
xtype: 'rallychart',
height: 400,
width: 800,
id: 'chart1',
itemId: 'chart1',
chartConfig: chartConfig,
renderTo: Ext.getBody().dom
});
And then reference them like this:
chart.method1();
...
Here is an example application. The toggle button shows and hides the cardboard:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
items: [{
xtype: 'button',
text : 'Toggle Cardboard',
handler: function() {
if (App.cardBoard.isHidden()) {
App.cardBoard.show();
} else {
App.cardBoard.hide();
}
}
}],
launch: function() {
App = this;
var addNewConfig = {
xtype: 'rallyaddnew',
recordTypes: ['PortfolioItem/Feature', 'PortfolioItem/Initiative', 'PortfolioItem/Theme'],
ignoredRequiredFields: ['Name', 'Project'],
showAddWithDetails: false
};
App.addNew = this.add(addNewConfig);
var cardBoardConfig = {
xtype: 'rallycardboard',
types: ['PortfolioItem/Feature', 'PortfolioItem/Rollup'],
attribute: 'InvestmentCategory'
};
App.cardBoard = this.add(cardBoardConfig);
}
});
I am wondering to see that the tooltip that I am giving inside the Ext window is hiding. It is going back to the window. The code is working fine without a window (It works fine in formPanel). The code and screenshot is attached. I know that the change would be made in target of the tip. But don't know what to give.
Ext.onReady(function() {
Ext.tip.QuickTipManager.init();
var btn = new Ext.Button({
renderTo: Ext.getBody(),
text:'Submit',
handler:function(){
new Ext.Window({
width:600,
height:500,
items:[formPanel]
}).show();
}
})
var formPanel = Ext.widget('form', {
width: 350,
bodyPadding: 10,
title: 'Account Registration',
defaults: {
anchor: '100%'
},
/*
* Listen for validity change on the entire form and update the combined error icon
*/
listeners: {
fieldvaliditychange: function() {
this.updateErrorState();
},
fielderrorchange: function() {
this.updateErrorState();
}
},
updateErrorState: function() {
var me = this,
errorCmp, fields, errors;
if (me.hasBeenDirty || me.getForm().isDirty()) { //prevents showing global error when form first loads
errorCmp = me.down('#formErrorState');
fields = me.getForm().getFields();
errors = [];
fields.each(function(field) {
Ext.Array.forEach(field.getErrors(), function(error) {
errors.push({name: field.getFieldLabel(), error: error});
});
});
errorCmp.setErrors(errors);
me.hasBeenDirty = true;
}
},
items: [{
xtype: 'textfield',
name: 'username',
fieldLabel: 'User Name',
allowBlank: false,
minLength: 6
}],
dockedItems: [{
xtype: 'container',
dock: 'bottom',
layout: {
type: 'hbox',
align: 'middle'
},
padding: '10 10 5',
items: [{
xtype: 'component',
id: 'formErrorState',
baseCls: 'form-error-state',
flex: 1,
validText: 'Form is valid',
invalidText: 'Form has errors',
tipTpl: Ext.create('Ext.XTemplate', '<ul><tpl for="."><li><span class="field-name">{name}</span>: <span class="error">{error}</span></li></tpl></ul>'),
getTip: function() {
var tip = this.tip;
if (!tip) {
tip = this.tip = Ext.widget('tooltip', {
target: this.el,
title: 'Error Details:',
autoHide: false,
anchor: 'top',
mouseOffset: [-11, -2],
closable: true,
constrainPosition: false,
cls: 'errors-tip'
});
tip.show();
}
return tip;
},
setErrors: function(errors) {
var me = this,
baseCls = me.baseCls,
tip = me.getTip();
errors = Ext.Array.from(errors);
// Update CSS class and tooltip content
if (errors.length) {
me.addCls(baseCls + '-invalid');
me.removeCls(baseCls + '-valid');
me.update(me.invalidText);
tip.setDisabled(false);
tip.update(me.tipTpl.apply(errors));
} else {
me.addCls(baseCls + '-valid');
me.removeCls(baseCls + '-invalid');
me.update(me.validText);
tip.setDisabled(true);
tip.hide();
}
}
}]
}]
});
});
I know that ExtJS has a zindex manager, which controls what items are shown when two items overlap. Hope that points you in the right direction.