Ext JS: Image with dynamic height resizing container - javascript

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()
});
}
});

Related

ExtJS Viewport produce blank page

Ext.define('rgpd.view.Viewport', {
extend: 'Ext.container.Viewport',
layout: 'border',
items: [{
region: 'north',
html: '<h1 class="x-panel-header">Page Title</h1>',
border: false,
margin: '0 0 5 0'
}, {
region: 'west',
collapsible: true,
title: 'Navigation',
width: 150
// could use a TreePanel or AccordionLayout for navigational items
}, {
region: 'south',
title: 'South Panel',
collapsible: true,
html: 'Information goes here',
split: true,
height: 100,
minHeight: 100
}, {
region: 'east',
title: 'East Panel',
collapsible: true,
split: true,
width: 150
}, {
region: 'center',
xtype: 'tabpanel', // TabPanel itself has no title
activeTab: 0, // First tab active by default
items: {
title: 'Default Tab',
html: 'The first tab\'s content. Others may be added dynamically'
}
}]
});
here is my viewport.
it's loaded in the browser i checked from network console tab, I added a console.log("test") call and it appears; but a blank page is rendered on the browser. Why ? The content of the class definition comes from ExtJS document (I use ExtJS 6.0)
i found out the problem comes from my controller but i don't know why
Ext.define('rgpd.controller.cMain', {
extend: 'Ext.app.Controller',
models: [
'mExemple',
'mCorpsMetier',
'mUtilisateur'
],
stores: [
'sExemple',
'sCorpsMetier',
'sUtilisateur'
],
views: [
'Exemple.View',
'CorpsMetier.View'
],
init: function() {
this.control({
});
},
onLaunch: function() {
},
});
Fiddle
Works perfectly. The question is how do you insert component in your parent view. You create instance and attach it or link component with 'xtype' in your view? Provide more code and we will see.

Ext JS tabpanel won't fit window size

Someone wants a panel done in Ext JS to dynamically fit the window size. I'm not familiar with Ext, but after hours of searching, I haven't found a working solution. Here is the code that is expected to be fixed:
var histotab = Ext.createWidget('tabpanel', {
activeTab: 0,
width : 2000,
height : "50%",
defaults :{
bodyPadding: 10
},
items: [
{
id: 'chartCmp',
title: 'By Year',
xtype: 'chart',
style: 'background:#fff',
layout:'fit',
animate: true,
shadow: true,
store:SOD.storeHistogram,
axes: [{
type: 'Numeric',
position: 'left',
fields: ['countoffiles'],
label: {
font: '8px Arial'
},
Any suggestions are greatly appreciated.
Use the Ext.container.Viewport class with a fit layout. The viewport always sizes itself to the document view size.
Ext.widget('viewport', {
layout: 'fit',
items: {
xtype: 'tabpanel',
items: [{
title: 'Foo',
html: 'First tab'
}]
}
});

ExtJs 4 - Resize form items on window resize

I am using ExtJs 4.0.7 and I have just got into a problem.
I want to resize the elements in the form(panel) when I resize the window which contains it(or them).
It's simple when you don't have columns and you are using an anchor layout, I know.
So far, my code looks like this:
initComponent: function ()
{
var me = this;
me.terminalImage = Ext.create('Ext.Img', {
src: 'http://www.sencha.com/img/20110215-feat-html5.png',
width: 50,
margin: '0 10 0 0'
});
me.nameField = Ext.create('Ext.form.Text', {
xtype: 'textfield',
name: 'defname',
fieldLabel: 'myFLabel',
allowBlank: false,
listeners: {
}
});
me.terminalTypeCmb = Ext.create('Ext.form.field.ComboBox', {
fieldLabel: me.getTrans('lblTerminalType.Text', 'Type'),
parentRecord: me.parentRecord,
store: 'myStore',
queryMode: 'local',
name: 'typename',
width: 300,
valueField: 'deftype',
displayField: 'typename',
listeners: {
}
});
me.form = Ext.create('Ext.form.Panel', {
xtype: 'form',
autoScroll: true,
defaultType: 'textfield',
defaults: { layout: 'anchor', flex: 1},
padding: '10',
items: [{
xtype: 'container',
layout: 'hbox',
items: [
me.terminalImage,
{
items: [me.nameField, me.terminalTypeCmb]
}
]
}
]
});
Ext.apply(this,
{
defaults: {
},
defaultType: 'textfield',
items: [me.form]
});
if (me.parentRecord)
{
me.form.loadRecord(me.parentRecord);
}
this.callParent(arguments);
}
I wanted to get something like that:
My Image | My TextField (resizable width on window resize)
(fixed size) | My ComboBox (I know it is not resizable)
|
Right now, my textfield remains with a constant width on window resize. Thank you for your help.
you are almost there :)
just remove default flex :defaults: { layout: 'anchor', flex: 1}, // not sure if you need the layout.
and add flex:1 only to the TextField.
Having the other items with fixed with, will make the TextField take all the space left.

ExtJS 3.4 vbox layout is not rendering correctly

I'm trying to render a GridPanel, and two regular Panels in a vbox layout (will update the Panels based on user actions later).
http://jsfiddle.net/auVez/
I have the store working OK
var store = new Ext.data.ArrayStore({
autoDestroy: true,
storeId: 'myStore',
fields: [
{name: 'categoryId', type: 'int'},
{name: 'categoryName', type: 'string'}
]
});
And the GridPanel was working OK before I started working with the vbox...
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header:'Category ID', width: 40, sortable: true, dataIndex: 'categoryId', hidden: true},
{header:'Cat. Name', width: 80, sortable: true, dataIndex: 'categoryName'}
],
flex: 10,
loadMask: true,
stripeRows: true,
viewConfig: { autoFill: true }, //This makes the columns span the screen onLoad
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
})
});
I've added a height to the vbox, because I read that it must have one...
var mainPanel = new Ext.Panel({
renderTo: 'myDiv',
frame: true,
layout: 'vbox',
layoutConfig: {
align: 'stretch'
},
height: '200px',
items: [
grid,
{
flex: 5,
title: 'Take Action',
id: 'SelectedItemPanel',
bodyStyle: {
background: '#ffffff',
padding: '6px 15px 0px 15px'
},
html: 'Please select item above to take action upon.'
},
{
flex: 5,
title: 'Preview',
id: 'SelectedItemPanel2',
bodyStyle: {
background: '#ffffff',
padding: '6px 15px 0px 15px'
},
html: 'Magic!'
}
]
});
But it still renders as an, approx, 10px height grey border, and doesn't take up 300px as requested.
I'm guessing I'm missing some overflow declaration or something, but this is frustrating, as I've spent ~4 hours I don't have on trying to get something so simple to work :-(
Hi problem is in height config
give height:300 (remove single quotes s)
see here jsfiddle link

ExtJS 4: How do I Re-render Ext.Component iframe?

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();

Categories