Is it possible to add buttons inside a menuitem using ExtJS 4.2?
I need to achieve the following:
(To have an edit and delete buttons next to the checkbox of each menuitem. These will have their own handlers and will open new panels when clicking on them)
I've tried to achieve it by creating a container per each employee and inside it add the buttons needed plus the menuitem but it's not working properly since I can't click the custom menuitem anymore after doing it and the design didn't look good at all.
However, I found a possible "hint" in the following StackOverflow answer:
https://stackoverflow.com/a/11213707/1178686
(But this is not entirely what I expect since I don't need just an icon, I need a button with its own handler plus I don't know if interacting with the DOM is a good approach for this)
Here's what I got so far and where I'm doing my tests:
Live demo:
http://jsfiddle.net/oscarj24/hmqjqtqs/
ExtJS code:
Ext.define('Namespace.view.Panel', {
extend: 'Ext.panel.Panel',
title: 'Panel',
frame: true,
floating: true,
draggable: true,
resizable: false,
closable: true,
employees: null,
layout: {
type: 'vbox',
align: 'stretch'
},
constructor: function(cfg) {
Ext.apply(this, cfg || {});
this.items = [{
xtype: 'container',
border: false,
items: this.createItems()
}];
this.callParent(arguments);
},
createItems: function() {
var items = [];
items.push({
xtype: 'button',
text: 'Employees',
menu: {
xtype: 'menu',
items: this.createMenuItems()
}
});
return items;
},
createMenuItems: function() {
var employees = this.employees || [],
items = [];
for (var i = 0; i < employees.length; ++i) {
var employee = employees[i];
if (employee) {
items.push({
xtype: 'menucheckitem',
text: Ext.String.format('{0} {1}', employee.name, employee.lastname),
employeeId: employee.id,
listeners: {
scope: this,
checkchange: this.onMenuItemCheckChange
}
});
}
}
items.push({
xtype: 'menuitem',
iconCls: 'add',
text: 'Add'
});
return items;
},
onMenuItemCheckChange: function(item, checked, eOpts) {
console.log('Employee Id: %o was checked: %o', item.employeeId, checked);
},
destroy: function() {
delete this.employees;
this.callParent(arguments);
}
});
Ext.onReady(function() {
Ext.create('Namespace.view.Panel', {
employees: [
{id: 1, name: 'Oscar', lastname: 'Jara'},
{id: 2, name: 'Foo', lastname: 'Bar'}
]
}).show();
});
CSS:
.add {
background-image: url('http://icons.iconarchive.com/icons/awicons/vista-artistic/16/add-icon.png') !important; width: 16px; height: 16px; display: block;
}
.edit {
background-image: url('http://icons.iconarchive.com/icons/designcontest/outline/16/Pencil-icon.png') !important; width: 16px; height: 16px; display: block;
}
.delete {
background-image: url('http://icons.iconarchive.com/icons/oxygen-icons.org/oxygen/16/Actions-edit-delete-icon.png') !important; width: 16px; height: 16px; display: block;
}
If someone knows a "proper" way to achieve this please let me know since I am not sure if one of the configs specified in the API for this component could help and I wasn't able to find a good example on the internet:
http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.menu.CheckItem
Thanks in advance.
I would probably go the route of using a container and just trying to make that work. I realize the styling might not be a nice as what the framework provides, but with enough fine-tuning, you could get it there... just make use of Sencha CMD, scss files, and their pre-defined CSS vars.
In this example, I do a quick unstyling of the buttons, so they can be clickable icons/areas, and I throw the employee record on the button itself... not really the best approach, but it works. If you don't like listeners on each individual component like that, you could make the parent container have the listener, and in that function you would check the target's CSS class... but that's besides the point. Working example:
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.define('MyPanel', {
extend: 'Ext.panel.Panel',
title: 'My Panel',
renderTo: Ext.getBody(),
employees: [{
id: 1,
name: 'Oscar',
lastname: 'Jara'
}, {
id: 2,
name: 'Foo',
lastname: 'Bar'
}],
initComponent: function() {
this.createMenuItems();
this.callParent();
},
createMenuItems: function() {
var items = [];
var employees = this.employees;
if (employees) {
for (var i = 0; i < employees.length; i++) {
var employee = employees[i];
var containerItems = [];
var checkboxCmp = Ext.create('Ext.form.field.Checkbox', {
width: 20
});
containerItems.push(checkboxCmp);
containerItems.push({
xtype: 'button',
cls: 'my-custom-button',
employee: employee,
width: 22,
text: '',
iconCls: 'edit',
listeners: {
click: this.onClickEditButton
}
});
containerItems.push({
xtype: 'button',
cls: 'my-custom-button',
employee: employee,
width: 22,
text: '',
iconCls: 'delete',
listeners: {
click: this.onClickDeleteButton
}
});
containerItems.push({
xtype: 'component',
html: '<div style="border-left:1px solid #000;height:100%; display: inline-block;"></div>'
});
containerItems.push({
xtype: 'button',
cls: 'my-custom-button',
textAlign: 'left',
checkboxCmp: checkboxCmp,
employee: employee,
flex: 1,
text: employee.name + ' ' + employee.lastname,
listeners: {
click: this.onClickEmployee
}
});
items.push({
xtype: 'container',
layout: {
type: 'hbox',
align: 'stretch'
},
overCls: 'over-item-cls',
items: containerItems
});
}
}
this.tools = [{
xtype: 'button',
text: 'Employees',
menu: {
xtype: 'menu',
items: items,
plain: true
}
}];
},
onClickDeleteButton: function(button, event, eOpts) {
alert('clicked delete, check console for employee');
console.log('delete', button.employee);
},
onClickEditButton: function(button, event, eOpts) {
alert('clicked edit, check console for employee');
console.log('edit', button.employee);
},
onClickEmployee: function(button, event, eOpts) {
alert('employee checkbox changed, check console for employee');
console.log('employee', button.employee);
var checkboxCmp = button.checkboxCmp;
if (checkboxCmp) {
checkboxCmp.setValue(!checkboxCmp.getValue());
}
}
});
Ext.create('MyPanel');
}
});
CSS
.add {
background-image: url('http://icons.iconarchive.com/icons/awicons/vista-artistic/16/add-icon.png') !important; width: 16px; height: 16px; display: block;
}
.edit {
opacity: 0.4;
background-image: url('http://icons.iconarchive.com/icons/designcontest/outline/16/Pencil-icon.png') !important; width: 16px; height: 16px; display: block;
}
.edit:hover,
.delete:hover {
opacity: 1.0;
}
.delete {
opacity: 0.4;
background-image: url('http://icons.iconarchive.com/icons/oxygen-icons.org/oxygen/16/Actions-edit-delete-icon.png') !important; width: 16px; height: 16px; display: block;
}
.over-item-cls {
background-color: lightblue;
}
a.my-custom-button.x-btn-default-small {
background: none;
border: none;
}
a.my-custom-button.x-btn-default-small span {
color: #ababab;
}
a.my-custom-button.x-btn-default-small:hover span {
color: black;
}
I am not sure you are insterested in using tpl in menu items: If you are, I can improve this code below. And Fiddle: https://fiddle.sencha.com/#fiddle/tt3
Ext.define('Image', {
extend: 'Ext.data.Model',
fields: [
{ name:'buttonText1', type:'string' },
{ name:'buttonText2', type:'string' },
{ name:'menuText', type:'string' }
]
});
Ext.create('Ext.data.Store', {
id:'imagesStore',
model: 'Image',
data: [
{ buttonText1:'edit', buttonText2: 'add', menuText:'Drawing', id: '1' },
{ buttonText1:'edit', buttonText2: 'add', menuText:'Advanced', id: '2' },
]
});
var imageTpl = new Ext.XTemplate(
'<tpl for="."><table>',
'<div class="menu-row">',
'<input type="checkbox" id="check{id}">',
'<button class="{buttonText1}">{buttonText1}</button>',
'<button class="{buttonText2}" >{buttonText2}</button> {menuText}',
'</div>',
'<table></tpl>'
);
var dataview = Ext.create('Ext.view.View', {
itemId: 'idDataView',
store: Ext.data.StoreManager.lookup('imagesStore'),
tpl: imageTpl,
itemSelector: 'div.menu-row',
listeners: {
itemclick: function(dataview, record,items) {
Ext.each(items.children, function(item) {
if (item.id == 'check'+ record.get('id')) {
item.checked == false ? item.checked = true : item.checked = false;
}
});
}
}
});
var button = Ext.create('Ext.button.Split', {
text: 'menuButton',
margin: '100 100 100 100',
menu: {
//plain: true,
items: [dataview],
listeners: {
afterrender: function(menu) {
var task = new Ext.util.DelayedTask(function(){
Ext.each(menu.down('#idDataView').getEl().dom.children, function(nodes) {
Ext.each(nodes.children, function(node) {
if (node.className == 'edit') {
node.addEventListener('click', function() {
alert('edited');
});
} else if (node.className == 'add') {
node.addEventListener('click', function() {
alert('added');
});
}
})
});
});
task.delay(100);
}
},
},
renderTo: Ext.getBody()
});
Related
I have a small panel with title and body.
var dashboardPanel1 = Ext.create('Ext.Panel', {
renderTo: Ext.getBody(),
collapsible: true,
margin: '0 0 50 0',
layout: {
type: 'table',
// The total column count must be specified here
columns: 3
},
defaults: {
// applied to each contained panel
bodyStyle: 'padding:20px',
border: 0
},
title: 'Key settings',
items: [{
html: '<img src="https://i.imgur.com/n7gOYrE.png" style="width: 20px; height: 20px">',
}, {
html: '|Your key is active|',
}, {
html: '|Expiring date: 27.04.2018|',
}],
});
How can I attach a listener to a title?
So, when I click on Key settings, it will be some action performed.
You can also trigger click event using [Element.on()](https://docs.sencha.com/extjs/6.2.0/classic/Ext.dom.Element.html#method-on).
The on method is shorthand for addListener. Appends an event handler to this object.
For example:
el.on("click", function(){
//do something...
//
}, this);
I this FIDDLE, I have created a demo using your code and make some modification. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('Ext.Panel', {
renderTo: Ext.getBody(),
collapsible: true,
margin: '0 0 50 0',
layout: {
type: 'table',
// The total column count must be specified here
columns: 3
},
defaults: {
// applied to each contained panel
bodyStyle: 'padding:20px',
border: 0
},
title: '<span class="mytitle">Key settings</span>',
items: [{
html: '<img src="https://i.imgur.com/n7gOYrE.png" style="width: 20px; height: 20px">',
}, {
html: '|Your key is active|',
}, {
html: '|Expiring date: 27.04.2018|',
}],
listeners: {
afterrender: function (panel) {
Ext.get(panel.el.query('span.mytitle')[0]).on('click', function (e) {
alert(e.target.innerText)
}, panel);
}
}
});
}
});
Solution:
Replace
title: 'Key settings',
with custom header:
header: {
title: 'Custom header title',
listeners: {
click: function(h, e) {
var tm = new Ext.util.TextMetrics(h);
if (e.getX() < tm.getWidth('Custom header title')) {
Ext.Msg.alert('Information', 'Do some action!');
}
}
}
}
Working example:
var dashboardPanel1 = Ext.create('Ext.Panel', {
renderTo: Ext.getBody(),
collapsible: true,
margin: '0 0 50 0',
layout:
{
type: 'table',
// The total column count must be specified here
columns: 3
},
defaults:
{
// applied to each contained panel
bodyStyle: 'padding:20px',
border: 0
},
//title: 'Key settings',
header: {
title: 'Custom header title',
listeners: {
click: function(h, e) {
var tm = new Ext.util.TextMetrics(h);
if (e.getX() < tm.getWidth('Custom header title')) {
Ext.Msg.alert('Information', 'Do some action!');
}
}
}
},
items: [
{
html: '<img src="https://i.imgur.com/n7gOYrE.png" style="width: 20px; height: 20px">',
},
{
html: '|Your key is active|',
},
{
html: '|Expiring date: 27.04.2018|',
}],
});
Notes:
The example is tested with ExtJS 4.2. Title width is calculated with Ext.util.TextMetrics.
I have a grid and I would like to add a tree if a name is equal to “Beto Carlx” Does anyone know how to make this happen? Thank you in advance!
Here’s my code: LIVE DEMO
columns: [{
header: 'NAME',
renderer: function(val, metadata, record) {
var recordName = record.get('name');
if (recordName === "Beto carlx") {
return "TEST";
}
return recordName;
},
dataIndex: 'name',
}],
I'm trying to use this simple tree:
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [
{ text: "Beto carlx", expanded: true, children: [
{ text: "item 1", leaf: true },
{ text: "item 2", leaf: true}
] }
]
}
});
Ext.create('Ext.tree.Panel', {
width: 200,
height: 150,
store: store,
rootVisible: false,
renderTo: Ext.getBody()
});
You can be achieve this functionality by html tag inside of renderer of gridcolumn.
I this FIDDLE, I have created a demo using html tag inside of renderer config. Hope this will help you to achieve your requirement.
Update
You can use cellclick to put collapseexpand function inside of ExtJS component or controller.
For design pas I have worked for that not fully same. I have used font-awesome for icons and put css for dashed border.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('UserModal', {
extend: 'Ext.data.Model',
fields: ['name']
});
Ext.create('Ext.data.Store', {
storeId: 'gridStore',
fields: ['name'],
groupField: 'status',
data: [{
"name": "Henry Watson"
}, {
"name": "Lucy"
}, {
"name": "Mike Brow"
}, {
"name": "Mary Tempa"
}, {
"name": "Beto Carlx"
}]
});
// Setting up the Grid
Ext.create('Ext.grid.Panel', {
title: 'Render Treen inside grid cell',
store: 'gridStore',
columns: [{
header: 'NAME',
renderer: function (val, metadata, record) {
if (val === "Beto Carlx") {
return `<ul class="root-tree">
<li><i class="fa fa-minus-square"></i> <span>Beto carlx</span>
<ul class="tree-item">
<li class="tree-item-li">item 1</li>
<li class="tree-item-li">item 1</li>
</ul>
</li>
</ul>`
}
return val;
},
dataIndex: 'name',
}],
listeners: {
cellclick: function (grid, td, cellIndex, record, tr, rowIndex, e) {
var list,
styles;
if (e.getTarget('ul.root-tree', 3)) {
list = td.querySelector('ul.tree-item');
var icon = td.querySelector('i.fa').classList;
if (icon.contains('fa-minus-square')) {
icon.remove('fa-minus-square');
icon.add('fa-plus-square');
list.style.display = 'none';
} else {
icon.remove('fa-plus-square');
icon.add('fa-minus-square');
list.style.display = 'block';
}
// styles = window.getComputedStyle(list);
// = (styles.getPropertyValue('display') === 'none' ? 'block' : 'none');
} else if (e.target.className == 'tree-item-li') {
alert(e.getTarget('li.tree-item-li').innerText)
}
}
},
height: 300,
renderTo: document.body
});
}
});
CSS part
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.root-tree {
cursor: pointer;
color: #5c5c5c;
font-weight:bold;
}
.root-tree span:hover {
color: green;
}
ul.tree-item,
ul.tree-item ul {
list-style: none;
margin: 0px 10px;
padding: 0;
}
ul.tree-item ul {
margin-left: 10px;
}
ul.tree-item li {
margin: 0;
padding: 0 7px;
line-height: 20px;
color: #5c5c5c;
font-weight: bold;
border-left: 1px dashed rgb(100, 100, 100)
}
ul.tree-item li:last-child {
border-left: none;
}
ul.tree-item li:before {
position: relative;
top: -0.3em;
height: 1em;
width: 12px;
color: white;
border-bottom: 1px dashed rgb(100, 100, 100);
content: "";
display: inline-block;
left: -7px;
}
ul.tree-item li:last-child:before {
border-left: 1px dashed rgb(100, 100, 100)
}
</style>
*Note I have implemented only for Beto Carlx with static html. You can put your logic with dynamic inside of renderer function.
I have a partial solution, the only problem is that extjs doesn't like nested grids ou treepanels. The events overlap and it gives some console erros like : "Uncaught TypeError: Cannot read property 'isGroupHeader' of null".
Here is the FIDDLE
var CreateTree = function(){
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [
{ text: "Beto carlx", expanded: true, children: [
{ text: "item 1", leaf: true },
{ text: "item 2", leaf: true}
] }
]
}
});
var tree = Ext.create('Ext.tree.Panel', {
width: 200,
store: store,
rootVisible: false
});
tree.render('myDiv');
}
renderer: function (val, metadata, record) {
var recordName = record.get('name');
if (recordName === "Beto Carlx") {
setTimeout(CreateTree, 300);
return "<span id=myDiv ></span>";
}
return recordName;
}
"If it works, its not stupid!"
My treecolumn has a ComboBox as the editor component. The choices in the options menu are rendered correctly with HTML, but the input box does not render HTML, it only shows the tags (See images below.)
How I can make it to also render the value as HTML?
P.S.
This solution here EXTJS 4 render HTML of a selected value in a combobox is seems like not working with extjs6 version, check here
Here's the problem place code (rendere in case depth.TypeParameter: returns text with html tags)
{
xtype: 'treecolumn',
dataIndex: 'text',
text: Poly.utils.locale.Base.localeName,
flex: 1,
getEditor: function (record) {
return me.getController().getEditor(record);
},
renderer: function (value, meta, record) {
var depth = Poly.view.fluidProperties.sample.Tree.depth;
switch (record.getDepth()) {
case depth.Temperature:
if (Ext.isEmpty(record.get('temperature'))) {
return value;
}
var text = Ext.String.format('T = {0} {1}',
record.get('temperature').toFixed(2),
Poly.utils.UniSum.GetUnit(me.getViewModel().get('temperatureUnitId')).name);
return text;
case depth.TypeParameter:
if (record.get('isNew')) {
return value;
}
return Poly.enums.TypeFluidParameter.getName(record.get('fluidParameter'), record.parentNode.get('typeFluid'), true);
}
return value;
}
}
Full code here
Ext.define('Poly.view.fluidProperties.sample.Tree', {
extend: 'Ext.tree.Panel',
xtype: 'fluidPropertiesSampleTree',
viewModel: {
type: 'fluidPropertiesSampleTreeViewModel'
},
controller: 'fluidPropertiesSampleTreeController',
statics: {
/** Уровень элемента в дереве */
depth: {
/** Корень */
Root: 0,
/** Замер */
Sample: 1,
/** Тип среды */
TypeFluid: 2,
/** Параметер */
TypeParameter: 3,
/** Температура */
Temperature: 4
}
},
lines: false,
rootVisible: false,
useArrows: true,
enableColumnHide: false,
enableColumnResize: false,
sortableColumns: false,
border: true,
viewConfig: {
cls: 'gridActionColumnHide'
},
dockedItems: [
{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
cls: 'transparent',
layout: {
type: 'hbox',
align: 'middle',
pack: 'center'
},
items: [
{
xtype: 'button',
cls: 'pvt-chart-button',
text: '', // локализация в initComponent
flex: 2,
name: 'addSample',
margin: 2
},
{
xtype: 'button',
cls: 'pvt-chart-button',
text: '', // локализация в initComponent
flex: 1,
name: 'import',
disabled: true,
margin: 2
},
{
xtype: 'button',
cls: 'pvt-chart-button',
text: '', // локализация в initComponent
flex: 1,
name: 'export',
disabled: true,
margin: 2
}
]
}
],
listeners: {
checkchange: 'nodeCheckChange',
edit: 'edit'
},
plugins: {
ptype: 'cellediting',
clicksToEdit: 2
},
bind: {
selection: '{selectedRecord}'
},
initComponent: function () {
var me = this,
store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: []
}
}),
controller = me.getController();
me.dockedItems[0].items[0].text = me.locale.addSample;
me.dockedItems[0].items[1].text = me.locale.importText;
me.dockedItems[0].items[2].text = me.locale.exportText;
Ext.applyIf(me, {
store: store,
columns: [
{
xtype: 'treecolumn',
dataIndex: 'text',
text: Poly.utils.locale.Base.localeName,
flex: 1,
getEditor: function (record) {
return me.getController().getEditor(record);
},
renderer: function (value, meta, record) {
var depth = Poly.view.fluidProperties.sample.Tree.depth;
switch (record.getDepth()) {
case depth.Temperature:
if (Ext.isEmpty(record.get('temperature'))) {
return value;
}
var text = Ext.String.format('T = {0} {1}',
record.get('temperature').toFixed(2),
Poly.utils.UniSum.GetUnit(me.getViewModel().get('temperatureUnitId')).name);
return text;
case depth.TypeParameter:
if (record.get('isNew')) {
return value;
}
return Poly.enums.TypeFluidParameter.getName(record.get('fluidParameter'), record.parentNode.get('typeFluid'), true);
}
return value;
}
},
{
width: 30,
xtype: 'widgetcolumn',
name: 'menuWidgetcolumn',
widget: {
xtype: 'button',
margin: '5 0 0 0',
arrowCls: '',
width: 15,
height: 15,
style: {
'background-color': '000000',
'border-color': '000000'
},
menu: {
xtype: 'colormenu',
listeners: {
select: function (component, color) {
var button = component.up('button');
button.setStyle('background-color', color);
}
}
}
},
onWidgetAttach: function (column, widget, record) {
widget.setVisible(Ext.isNumber(record.get('temperature')));
}
},
{
xtype: 'actioncolumn',
width: 25,
items: [
{
handler: 'removeTreeItem',
getClass: function (v, meta, rec) {
if (!rec.get('isNew')) {
return 'poly-trash-icon';
}
return '';
},
getTip: function (v, meta, rec) {
if (!rec.get('isNew')) {
return 'Delete';
}
return '';
}
}
]
}
]
});
me.getSampleNode = controller.getSampleNode;
me.setTypeMode = Ext.bind(controller.setTypeMode, controller);
me.callParent(arguments);
}
});
Html input element can't display HTML, so you need to change template add div. Div can be shown as an overlay over input.
Best way to achieve this is by extending ComboBox:
Ext.define('HtmlComboBox', {
extend: 'Ext.form.field.ComboBox',
fieldSubTpl: [ // note: {id} here is really {inputId}, but {cmpId} is available
'<input id="{id}" data-ref="inputEl" type="{type}" {inputAttrTpl}',
' size="1"', // allows inputs to fully respect CSS widths across all browsers
'<tpl if="name"> name="{name}"</tpl>',
'<tpl if="value"> value="{[Ext.util.Format.htmlEncode(values.value)]}"</tpl>',
'<tpl if="placeholder"> placeholder="{placeholder}"</tpl>',
'{%if (values.maxLength !== undefined){%} maxlength="{maxLength}"{%}%}',
'<tpl if="readOnly"> readonly="readonly"</tpl>',
'<tpl if="disabled"> disabled="disabled"</tpl>',
'<tpl if="tabIdx != null"> tabindex="{tabIdx}"</tpl>',
'<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
'<tpl foreach="inputElAriaAttributes"> {$}="{.}"</tpl>',
' class="{fieldCls} {typeCls} {typeCls}-{ui} {editableCls} {inputCls}" autocomplete="off"/>',
// overlay element to show formatted value
'<div id="{cmpId}-overlayEl" data-ref="overlayEl"<tpl if="name"> name="{name}-overlayEl"</tpl> class="{fieldCls}-overlay {typeCls} {typeCls}-{ui} {inputCls}">{value}</div>',
{
disableFormats: true
}
],
forceSelection: true,
childEls: [
'overlayEl'
],
setRawValue: function(value) {
var me = this;
// set value in overlay
if (me.rendered) {
me.overlayEl.update(value);
}
return me.callParent([value]);
}
});
With that, some additional CSS is required:
.x-form-text-wrap {
position: relative;
}
.x-form-field-overlay {
background-color: #ffffff;
position: absolute;
top: 0;
}
Fiddle: https://fiddle.sencha.com/#fiddle/14mm
I suppose that your editor is combo, by default combo (as well as many other components) display HTML as plain text.
Example
I guess as workaround you could overrite combo (or any other component), i.e. change component <input> element to <div>. It will entail overrites of some methods (setValue() for example).
The snippet below will not run on this site, but you can access a working demo here on JSFiddle.
I am trying to get the icon to appear to the right of the checkbox, but it appears to be wrapping. Is there a property that I need to set so that it will appear in-line? This worked in ExtJS4, but after I switched to ExtJS5 this does not work.
afterSubTpl Documentation
Ext.form.field.Checkbox -> config -> afterSubTpl
An optional string or XTemplate configuration to insert in the field markup after the subTpl markup. If an XTemplate is used, the component's render data serves as the context.
Code
Ext.require(['*']);
Ext.define('App.view.MainView', {
extend: 'Ext.panel.Panel',
xtype: 'mainView',
alias: 'widget.mainview',
title: 'Checkbox Template Example',
referenceHolder: true,
layout: {
type: 'border'
},
initComponent: function () {
var me = this,
tooltip = me.getHelpIconWithTooltip();
me.items = [{
region: 'center',
xtype: 'panel',
title : 'A Panel Title',
margin : 20,
bodyStyle: 'padding: 8px;',
layout : 'vbox',
items : [{
xtype: 'checkbox',
fieldLabel : 'Checkbox',
afterSubTpl: tooltip
}]
}],
me.callParent();
},
getHelpIconWithTooltip: function () {
return this.getFormIconWithTooltip('help-icon help-form-icon',
'This is a help tooltip...');
},
getFormIconWithTooltip: function (iconClassList, toolTipText) {
var getSpan = function(cl, qt) {
return '<span class="'+cl+'" data-qtip="'+qt+'"></span>';
}
return [
'<tpl>',
getSpan(iconClassList, toolTipText),
'</tpl>'
];
}
});
Ext.define('App.app.App', {
extend: 'Ext.app.Application',
name: 'App',
launch: function () {
Ext.create('Ext.Viewport', {
layout: 'fit',
flex: 1,
items: [{
xtype: 'mainview'
}]
});
}
});
Ext.onReady(function () {
Ext.application('App.app.App');
});
.help-icon {
display: inline-block;
background: url(http://www.famfamfam.com/lab/icons/silk/previews/index_abc.png) -705px -1125px no-repeat;
width: 16px;
height: 16px;
}
.help-form-icon {
/*margin-left: 5px;*/
}
<link href="https://extjs.cachefly.net/ext/gpl/5.1.0/packages/ext-theme-crisp/build/resources/ext-theme-crisp-all-debug.css" rel="stylesheet" />
<script src="http://cdn.sencha.com/ext/gpl/5.1.0/build/ext-all.js"></script>
Edit
It looks like if I add a class to the checkbox, I can prevent it from wrapping, but now the icon is positioned too high.
{
xtype: 'checkbox',
fieldLabel: 'Checkbox',
afterSubTpl: tooltip,
cls: 'no-wrap-tooltip'
}
.no-wrap-tooltip .x-form-cb-wrap-inner {
display: inline-block;
}
I may have figured it out, but this solution uses magic numbers which make it work in this instance.
Demo
{
xtype: 'checkbox',
fieldLabel: 'Checkbox',
afterSubTpl: tooltip,
cls: 'no-wrap-tooltip'
}
.no-wrap-tooltip .x-form-cb-wrap-inner {
display: inline-block;
line-height: 28px;
}
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!