EXTjs getEl() fails before showing the element - javascript

Good day all.
In EXTjs, probably 4.x version, I have a menu with a couple of levels of sub-menus
I'd like to add a data attribute to some of those sub-menus and actually I can do this with no problems with:
Ext.getCmp("notificationMenu").getEl().set({"data-notifynumber": 4});
but this is working only for the first element of the menu (to be clear, the element that is shown upon loading.
For any other element of the menu, first of all I have to click the menu to show all the sub-menu and only at that time I can use the getEl() function, otherwise this error is shown:
Uncaught TypeError: Cannot read property 'set' of undefined
I understand that I'd need to... show? render? well, "do something" to those sub elements in order to have them in the dom properly... I attach part of the code:
this is part of the menu I create:
xtype: 'button',
id:"notificationMenu",
hidden: false,
reference: 'userType',
style: 'color: #ffffff;width:58px;height:58px;',
glyph: 0xf0f3,
menu:{
border:0,
menuAlign: 'tr-br?',
bodyStyle: {
background: '#3e4752',
},
items:[
{
text:"TASKS",
disabled:true
},
{
text:"Campaigns",
data_id:"me_campaigns",
glyph:0xf0c1,
id:"notification_me_campaigns_root",
hidden:true,
menu:{
border:0,
menuAlign: 'tr-br?',
bodyStyle: {
background: '#3e4752',
},
items:[
{
text:"Approval",...
in this example, if I make after Render:
Ext.getCmp("notificationMenu").getEl().set({"data-notifynumber": 10})
but if I use
Ext.getCmp("notification_me_campaigns_root").getEl().set({"data-notifynumber": 4})
the error above is shown. please do you have some advice? may I call a "force render" somehow?

Try to use afterrender to get dom element.
ExtJs getEl() Retrieves the top level element representing this component but work when dom is prepared without dom creation it will return null.
I have created an Sencha Fiddle demo hope this will help you to achieve you requirement/solution.
var panel = new Ext.panel.Panel({
renderTo: document.body,
title: 'A Panel',
width: 200,
tools: [{
xtype: 'button',
text: 'Foo',
menu: {
defaults: {
handler: function () {
Ext.Msg.alert('Successs', 'You have click on <b>data-notifynumber</> ' + this.up('menu').getEl().getAttribute('data-notifynumber'))
}
},
items: [{
text: 'Item 1'
}, {
text: 'Item 2',
menu: {
listeners: {
afterrender: function () {
this.getEl().set({
"data-notifynumber": 20//only for example you can put as basis of your requirement
});
}
},
defaults: {
handler: function () {
Ext.Msg.alert('Successs', 'You have click on <b>data-notifynumber</> ' + this.up('menu').getEl().getAttribute('data-notifynumber'))
}
},
items: [{
text: 'Sub Item 1',
}, {
text: 'Sub Item 2'
}]
}
}],
listeners: {
afterrender: function () {
this.getEl().set({
"data-notifynumber": 10//only for example you can put as basis of your requirement
});
}
}
}
}]
});

Related

Is there any other way to place "Close Tooltip" to default close button in the panel header in extjs?

I am using extjs for my project. There is a default close button on the upper right side for every panel. I am able to put tooltip for the button using its position.
function closeTooltip (window, 1) {
Ext.create('Ext.tip.ToolTip', {
target: window.header.items.get(1).el,
html: 'Close'
});
But, this isn't so cool because, if I add a button to the header then the position of the close button changes from 1 to 2. So, the tooltip gets displayed for the newly added button.
Is there any other way to keep close tooltip to close button that remains same ?
For getting your close button, you can use down method of Ext.dom.Element.
The down method selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
In this FIDDLE, I have created a demo using panel. I have tested in ExtJS 4.x and later versions, it's working fine. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
function closeTooltip(panel) {
if (Ext.getVersion().major > 5) {
Ext.getCmp(panel.el.down('.x-tool-close').up().id).setTooltip('close')
} else {
Ext.create('Ext.tip.ToolTip', {
target: panel.el.down('.x-tool-close').id,
html: ' Close '
//If you want to put diffrent-diffrent tooll tip then you can use below
//html:`Close ${panel.title}`
});
}
}
Ext.define('CustomPanel', {
extend: 'Ext.panel.Panel',
width: 200,
bodyPadding: 10,
margin: 5,
html: 'Custom panel used',
closable: true,
tools: [{
type: 'help',
handler: function () {
alert('help');
}
}],
listeners: {
afterrender: closeTooltip
}
});
Ext.create('CustomPanel', {
title: 'Panel 1',
renderTo: Ext.getBody()
});
Ext.create('CustomPanel', {
title: 'Panel 2',
renderTo: Ext.getBody()
});
Ext.create('CustomPanel', {
title: 'Panel 3',
renderTo: Ext.getBody()
});
Ext.create('CustomPanel', {
title: 'Panel 4',
renderTo: Ext.getBody()
});
Ext.create('CustomPanel', {
title: 'Panel 4',
renderTo: Ext.getBody()
});
}
});

How to make menu and toolbar in extjs?

I'm new in Extjs. I would like to know. Which components I can use, to make a menu and toolbar like in desktop app?
I mean something like this.
I wrote this code, but the result is not similar to desktop app menu.
Ext.define('untitled.view.main.Main', {
extend: 'Ext.panel.Panel',
xtype: 'app-main',
width: 200,
height: 150,
tbar: [{
xtype: 'button',
text: 'Select',
menu: Ext.create('Ext.menu.Menu', {
items: [{
text: 'JavaScript',
handler: function () {
alert('Selected JavaScript');
}
}, {
text: 'Java',
}, {
text: 'C/C++'
}]
})
}]
});
New -------
Thank you very much, and the last question. How can I remove this arrow?
Here is fiddle for you - desktop-like toolbar (use your iconCls for Icon buttons).
Ask if you need something updated.

Ext.bind does not see function in ExtJS

I am trying to mod the Portlet example and port it into our program. The code looks like this:
Ext.create('Ext.container.Viewport',{
id: 'app-viewport', //creates viewport
layout: {
type: 'border',
padding: '0 5 5 5' // pad the layout from the window edges
},
onPortletClose: function(portlet) {
this.showMsg('"' + portlet.title + '" was removed');
},
showMsg: function(msg) {
var el = Ext.get('app-msg'),
msgId = Ext.id();
this.msgId = msgId;
el.update(msg).show();
Ext.defer(this.clearMsg, 3000, this, [msgId]);
},
clearMsg: function(msgId) {
if (msgId === this.msgId) {
Ext.get('app-msg').hide();
}
},
items: [{
id: 'app-header',
xtype: 'box',
region: 'north',
height: 40,
html: 'Ext Welcome'
},{
xtype: 'container',
region: 'center',
layout: 'border',
items: [{
id: 'app-options', //Creates the Options panel on the left
title: 'Options',
region: 'west',
animCollapse: true,
width: 200,
minWidth: 150,
maxWidth: 400,
split: true,
collapsible: true,
layout:{
type: 'accordion',
animate: true
},
items: [{
html: content,
title:'Navigation',
autoScroll: true,
border: false,
iconCls: 'nav'
},{
title:'Settings',
html: content,
border: false,
autoScroll: true,
iconCls: 'settings'
}]
},{
id: 'app-portal', //Creates the panel where the portal drop zones are.
xtype: 'mainpanel',
region: 'center',
items: [{
id: 'col-1', //Each column represents a drop zone column. If we add more there are more created and width gets adjusted accordingly
items: [{
id: 'portlet-1',
title: 'Portlet 1',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
},{
id: 'portlet-2',
title: 'Portlet 2',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
},{
id: 'col-2',
items: [{
id: 'portlet-3',
title: 'Portlet 3',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
},{
id: 'col-3',
items: [{
id: 'portlet-4',
title: 'Portlet 4',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
}]
}]
}]
});
The problem is that Ext.bind cannot read the onPortletClose function and the browser gives me a:
Uncaught TypeError: Cannot read property 'apply' of undefined error. I checked the stack and essentially in the Ext.bind(fn,scope) the fn is undefined and thus it cannot read the handler function. The difference between my application and in the example is that I add this directly into a JSP's Ext.onReady() whereas in the example all of this is added through a Ext.apply(this, {...}). I'm really confused. I tried all kinds of gimmicks to force the scope on the viewport but it seems that whatever is inside Ext.bind() loses contact with outside or something. I've used Ext.bind() before and it went fine although it was inside an initComponent configuration. Is that mandatory? If no then what is the problem?
It is important to understand the meaning of this here (or in general when working with JavaScript or ExtJS).
In a global context, this refers to the global object, also known as the global window variable. This is the case inside your Ext.onReady function:
Ext.onReady(function() {
console.log(this === window);
// -> true
// because this is the global object
});
In an object context, by default this refers to the owner object of the function (there are ways around it and actually this is exactly want you want do achieve using Ext.bind):
var obj = {
prop: 'My text property',
fn: function() {
console.log(this.prop);
// -> My text property
// because "this" refers to our object "obj"
}
};
Now, this is exactly what makes the difference between your case and the one from the examples.
When using the approach with Ext.onReady this - as pointed out above - will refer to the global object, which of course does not have a function onPortletClose.
When using the approach from the examples, this is accessed from inside of initComponent, which is a member function of your derived viewport class, and therefore this refers to the component instance (= the owning object), which allows you to access your function.
Ext.define('MyViewport', {
extend: 'Ext.container.Viewport',
onPortletClose: function(portlet) {
this.showMsg('"' + portlet.title + '" was removed');
},
initComponent: function() {
console.log(this);
// -> the instance of your viewport class
Ext.apply(this, {
items:[{
xtype: 'panel',
title: 'Portlet 1',
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
});
this.callParent();
}
});
Side notes
Ext.apply
Ext.apply really just copies all properties from one object to another, so in this case it is just a convenient way of applying all attributes of that object to this with one function call. You could as well just use:
this.items = [...];
Changing the scope of your listeners
You do not need to use Ext.bind when adding listeners to a component, you can simply provide a scope configuration in your listeners object:
listeners: {
close: function() {...},
scope: this
}
External sources
If you want to dive in a little deeper (which I would recommend), you might want to read more about this at the MDN (Mozilla Developer Network).

Sencha Touch 2 Add and Remove textfield inside fieldset

i have strange issue with removing item from fieldset. my app success adding new textfield fieldset item, buth when i do remove() my app screen got stuck without any error on my google chrome.
here my source
view js
Ext.define('qms.view.QC23', {
extend: 'Ext.form.FormPanel',
alias: 'widget.QC23View',
id: 'QC23View',
requires: ['Ext.form.FieldSet', 'Ext.Label'],
config: {
items: [
{
xtype: 'fieldset',
//defaults: { labelAlign: 'top' },
Id:'defectAdd',
layout:{
},
items: [
{
xtype: 'button',
text: 'New Defect',
id: 'DefectQC23Button',
ui: 'action'
},
{
xtype: 'button',
text: 'Remove Defect',
id: 'RemoveQC23Button',
ui: 'action'
}
]
}
]
}
and my controler
Ext.define('qms.controller.QC23con', {
extend: 'Ext.app.Controller',
config: {
refs: {
addDefectButton:'#DefectQC23Button',
rmDefectButton:'#RemoveQC23Button'
},
control: {
addDefectButton:{
tap: 'addDefect'
},
rmDefectButton:{
tap: 'removeDefect'
},
}
},
addDefect: function(button){
button.up('fieldset').add({
xtype: 'textfield',
name: 'MyField-' + button.up('fieldset').length
});
//Ext.getCmp('defectAdd').doLayout();
},
removeDefect: function(button){
button.up('fieldset').remove(button.up('fieldset').items.items[0]);
}
the function for adding item work fine, but when i remove the item my screen stuck. i am using google chrome for testing.
please give me solution for this issue.
thanks.
I noticed you are not checking for the xtype before removing an item from the fieldset. The code might be removing the button itself in which case it might cause your screen to freeze. I created a simple sencha fiddle https://fiddle.sencha.com/#fiddle/4tf that does what you are trying to accomplish.
replace the removeDefect function with this:
var lastItem = button.up('fieldset').items.items.length-1;
if(button.up('fieldset').items.items[lastItem].xtype ==='textfield')
button.up('fieldset').remove(button.up('fieldset').items.items[lastItem]);

html with value from function

Im really new to this java script and Sencha touch so sorry if this question is simple but I didn't find a way to do this.
I have a function that returns a value .
now I want to display the value from the function inside an html line.
how im calling this function from html element? how I show the value?
config: {
title: 'Me',
iconCls: 'user',
//layout: 'fit',
/* create a title bar for the tab panel */
items: [
{
docked: 'top',
xtype: 'titlebar',
title: 'Singers'
},
{
html: [
'<h1>Hi!! ' + this.setName +'</h1>'
].join("")
}
],
},
setName: function (val) {
var store =Ext.getStore('user');
var last = st.last('user');
return val=(last.get('user'));
}
});
You could use the itemId property to reference the component and then update its html property via the initialise listener.
For example:
config: {
title: 'Me',
iconCls: 'user',
//layout: 'fit',
/* create a title bar for the tab panel */
items: [
{
docked: 'top',
xtype: 'titlebar',
title: 'Singers'
},
{
itemId:'htmlContainer', //use itemIds like div ids
xtype:'container',
html: ''
}
],
/**
* #cfg listeners
* Parent Component listeners go here.
* Check sencha touch doc for more information and other available events.
*/
listeners:{
initialize: 'onInitialise'
}
},
onInitialise: function()
{
//set the html config item here
var c = this.down('#htmlContainer');
c.setHtml(this.setName());
},
setName: function (val) {
....
}

Categories

Resources