When an item is dynamically added to the created component, if there is an error in the item, the application crashes.
This problem does not exist when the item is not created.
Ext.define('Test', {
extend: 'Ext.panel.Panel',
initComponent: function () {
// make error
// this.callParent();
}
});
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 400,
height: 300,
title: 'Application',
layout: {
type: 'vbox',
align: 'center',
},
defaults: {
margin: 10,
},
items: [{
xtype: 'button',
iconCls: 'x-fa fa-cog',
handler: function (btn) {
let mainPanel = btn.up('panel'),
item = Ext.create('Test');
// bug
mainPanel.add(item);
},
}],
});
sencha fiddle
Strange problem, because you are trying to find out if the developer did something wrong during runtime.
But anyways - here is one solution for your problem:
handler: function (btn) {
let mainPanel = btn.up('panel'),
item = Ext.create('Test');
// bug testing
if(Ext.isDefined(item) && Ext.isObject(item.layout)) {
mainPanel.add(item);
} else {
console.error(item.id + ' could not be added because of an error I made.')
}
},
Related
I've just started working with Sencha Touch over the past couple days and I've run into a few questions. The main one is, when working with anything that doesn't regularly have user click interaction (titlebar, html text, etc for some random examples), is it possible to click on things like this and get a panel to appear.
I know that with buttons and other things, you have a tap, itemtap, etc, but I'm not sure about instances like this. Any help would be appreciated with examples.
Yes you can. Check out my blog post here: http://www.senchahackers.com/touch/multiple-tap-listeners-one-xtemplate/ that explains exactly how to do that.
Basically you can listen for a tap event on any element, as long as you add it to the list of 'delegates'
In your view:
listeners: {
tap: {
element: 'element',
delegate: '.app-box, .doc-box, .bubble-holder',
fn: function(e){
var url = e.target.name,
divClassName = e.delegatedTarget.className,
appbox = "app-box",
docbox = "doc-box",
bubble = "bubble-holder";
console.log(divClassName);
switch(divClassName){
case docbox :
//lets say you have an element '.doc-box' that you want to click and show the panel
// show the panel, which is a separate file, shown below
var profileController = YourApp.getController('YourController');
//call the showProfilePanelPopup() method in your controller, passing in this as the element that shows it
profileController.showProfilePanelPopup(this);
break;
case appbox :
alert(appbox);
break;
case bubble :
alert(bubble);
break;
}
}
}
}
Then in your controller:
extend: 'Ext.app.Controller',
config: {
refs: {
profilePanelPopup: {
autoCreate: true,
selector: '#profilePanelPopup',
xtype: 'profilePanelPopup'
}
}
},
showProfilePanelPopup: function(btn, action, values) {
var me = this;
var popup = me.getProfilePanelPopup();
popup.showBy(btn);
popup.on('hide', function () {
popup.destroy();
}, this);
}
Assuming you some Panel in your views directory like this:
Ext.define('App.view.ProfileNowPop', {
extend : 'Ext.Panel',
alias: 'widget.profileNowPop',
xtype: 'profilePanelPopup',
config: {
height: (Ext.os.deviceType != "Desktop") ? "35%" : 253,
cls:'profilePop',
left: '1%',
padding: 0,
top: '1%',
width: (Ext.os.deviceType != "Desktop") ? '40%' : '36%',
hideOnMaskTap: true,
modal: {
cls:'opaquemask'
},
scrollable: false,
store: 'ProfilePopStore',
model: 'App.model.ProfilePopModel',
items:[
{
xtype: 'fieldset',
items: [
{
xtype: 'textfield',
id: 'gradePopField0',
cls: 'gradePopField',
style: 'background: #f7f7f5',
listeners: {
initialize: function(ele, eOpts) {
this.setReadOnly(true);
}
}
}
]
}
]
},
initialize: function() {
this.callParent(arguments);
}
});
I have a border layout with two panels inside center and west regions. By default, west panel is collapsed and if you click on any part of the title bar while is collapsed, the panel is temporary expanded until you move the mouse pointer out of its boundaries.
What I want to do is to have this same "temporary expand" not by clicking on the panel's title bar, but just hovering over it. How can I make that possible?
Here is my code:
Ext.onReady(function() {
Ext.create('Ext.window.Window', {
width: 500,
height: 300,
layout: 'border',
items: [{
xtype: 'panel',
title: 'Center Panel',
region: 'center',
flex: 1
},{
xtype: 'panel',
title: 'West Panel',
region: 'west',
flex: 1,
collapsible: true,
collapsed: true,
animCollapse: false,
collapseDirection: Ext.Component.DIRECTION_BOTTOM,
titleCollapse: true
}]
}).show();
});
Please refer to the following fiddle for your convenience: http://jsfiddle.net/3FJ58/3/
Thanks in advance!
Yes, this is possible but you have to extend from Ext.panel.Panel to override the getPlaceholder method that is used by the borderlayout
getPlaceholder: function(direction) {
var me = this,
collapseDir = direction || me.collapseDirection,
listeners = null,
placeholder = me.placeholder,
floatable = me.floatable,
titleCollapse = me.titleCollapse;
if (!placeholder) {
if (floatable || (me.collapsible && titleCollapse)) {
listeners = {
mouseenter: {
// titleCollapse needs to take precedence over floatable
fn: (!titleCollapse && floatable) ? me.floatCollapsedPanel : me.toggleCollapse,
element: 'el',
scope: me
}
};
}
me.placeholder = placeholder = Ext.widget(me.createReExpander(collapseDir, {
id: me.id + '-placeholder',
listeners: listeners
}));
}
// User created placeholder was passed in
if (!placeholder.placeholderFor) {
// Handle the case of a placeholder config
if (!placeholder.isComponent) {
me.placeholder = placeholder = me.lookupComponent(placeholder);
}
Ext.applyIf(placeholder, {
margins: me.margins,
placeholderFor: me
});
placeholder.addCls([Ext.baseCSSPrefix + 'region-collapsed-placeholder', Ext.baseCSSPrefix + 'region-collapsed-' + collapseDir + '-placeholder', me.collapsedCls]);
}
return placeholder;
}
See the updated JSFiddle
Overriding is at least the cleanest way IMO. But it would also be possible to manipulate the placeholder created by the borderlayout.
#JoseRivas already posted something like this but with some issues I will add the snipped how this can be done in a cleaner way
listeners: {
afterrender: function(p){
p.placeholder.getEl().on('mouseenter', function(){ p.floatCollapsedPanel() })
}
}
See the updated JSFiddle
jacoviza. Can you try to capture focus event of panel. this link helps you. Extjs panel. Keyboard events
add a listener to the el of the placeholder for mouseover and then call the floatCollapsedPanel()
Ext.onReady(function () {
Ext.create('Ext.window.Window', {
width: 500,
height: 300,
layout: 'border',
items: [{
xtype: 'panel',
title: 'panel1',
region: 'center',
flex: 1
}, {
xtype: 'panel',
title: 'panel2',
region: 'west',
flex: 1,
id: 'mypanel2',
collapsible: true,
collapsed: true,
animCollapse: false,
collapseDirection: Ext.Component.DIRECTION_BOTTOM,
titleCollapse: true,
listeners: {
afterrender: {
fn: function (self) {
self.placeholder.getEl().on('mouseover', function () {
var panel = Ext.getCmp('mypanel2');
panel.floatCollapsedPanel()
})
}
}
}
}]
}).show();
});
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) {
....
}
I was wondering if it's possible to not to allow the user to close the item again when it's open, meaning to let it close only when i click on another item in the accordion.
hope it's clear enough.
I'm adding the code:
Ext.define('application.view.SystemHealth', {
extend: 'Ext.Container',
alias: 'widget.globalSynchronization',
requires: ['infra.view.views.BoxHeader',
'application.view.SystemStatusHeader',
'application.model.SystemHealth',
'application.store.SystemHealth',
'infra.utils.pvs.SyncJobRunningStep',
'application.view.CostCalculation',
'application.view.SystemStatusHeader',
'application.view.DataCollector',
'application.view.PublicCloudConnection',
'Ext.layout.container.Accordion'
],
layout:{
type:'vbox',
align:'stretch'
},
header: false,
cls: ['global-synchronization'],
syncJobStatus: null,
initComponent: function() {
var me = this;
me.store = Ext.create('itfm.application.store.SystemHealth');
me.store.load({scope: me, callback: me.onLoadDone});
Ext.apply(me, {
items: [
{
xtype: 'boxHeader',
width: '100%',
title: itfm.application.T.GlobalSynchronizationTitle
},
{
xtype: 'label',
width: '90%',
html: itfm.application.T.GlobalSynchronizationDescription,
margin: "0 0 30 10"
}
]
});
me.callParent(arguments);
},
onLoadDone: function(records, operation, success){
var me =this;
var accordionItemsMargin = '0 0 30 0';
me.accordion = Ext.create('Ext.panel.Panel', {
margin: "0 0 30 10",
defaults:[{
layout:'fit',
height:'100%',
width:'100%'
}] ,
layout: {
type: 'accordion',
titleCollapse: false,
animate: true,
activeOnTop: true,
fill : true,
collapseFirst :true
},
items: [
{
height: 180,
xtype: 'dataCollector',
autoScroll:true,
margins: accordionItemsMargin,
store: records[0].dcModule()
}
,
{
xtype: 'costCalculation',
margins: accordionItemsMargin,
store: records[0].ccModule()
},
{
xtype: 'publicCloudConnection',
margins: accordionItemsMargin,
store: records[0].pcModule()
}
]
});
me.add( me.accordion);
}
});
thanks for the help
What you want is that nothing happens when the user click on the currently expanded panel, instead of collapsing and expanding the next one, is that right?
Unfortunately, there's no built-in option for that... If you really want it, you'll have to override Ext.layout.container.Accordion and implement it yourself.
Edit
In fact most of the collapsing/expanding code lies in the Ext.panel.Panel class.
This simple override seems to be enough to do what you want. Apparently this method is used only for collapse listeners, so it shouldn't have any adverse effect (unless the method is also used somewhere in your code...).
Ext.define('Ext.ux.Panel.JQueryStyleAccordion', {
override: 'Ext.panel.Panel'
,toggleCollapse: function() {
if (this.collapsed || this.floatedFromCollapse) {
this.callParent();
}
}
});
See this fiddle.
I was able to override the accordion with the following
Ext.define('itfm.application.view.SystemHealthAccordion', {
extend: 'Ext.layout.container.Accordion',
alias: ['layout.systemHealthAccordion'] ,
constructor: function() {
var me = this;
me.callParent(arguments);
},
onComponentExpand: function(comp) {
var me = this;
me.callParent(arguments);
var button = comp.down('tool');
button.setDisabled(true);
},
onComponentCollapse: function(comp) {
var me = this;
me.callParent(arguments);
var button = comp.down('tool');
button.setDisabled(false);
}
});
inside the class of the first item of the accordion, there is a need to do the following:
me.on('boxready', me.disableTools);
},
// disable the click on the item in case it's open
disableTools: function(){
var me = this;
var button = me.getHeader().down('tool');
button.setDisabled(true);
}
so when the first item is open it will have the same behaviour
I have following problem. I have grid with tbar. Inside tbar I have number of Ext.form.field.Trigger.
When the user click on trigger button I want to filter the store using function that is provided with grid. I want to define functionality of triggerclick inside defined class, so I can reuse this component with different grid.
So, in short I want to find the panel where clicked component is placed and call panel function, or pass reference of panel to triggerclick, or fire an event with some parameter that will calculated based on where the button was clicked, or maybe there is a better method to accomplish this.
The code (FilterField -> extension of trigger):
Ext.define('GSIP.core.components.FilterField', {
extend: 'Ext.form.field.Trigger',
alias: 'widget.filterfield',
initComponent: function() {
this.addEvents('filterclick');
this.callParent(arguments);
},
onTriggerClick: function(e, t) {
//Ext.getCmp('gsip_plan_list').filterList(); - working but dont want this
//this.fireEvent('filterclick'); - controller cant see it,
//this.filterList; - is it possible to pass scope to panel or reference to panel
//e.getSomething() - is it possible to get panel via EventObject? smth like e.getEl().up(panel)
}
});
code of panel:
Ext.define('GSIP.view.plans.PlanReqList', {
extend: 'Ext.grid.Panel',
alias: 'widget.gsip_devplan_list',
id: 'gsip_plan_list',
title: i18n.getMsg('gsip.view.PlanReqList.title'),
layout: 'fit',
initComponent: function() {
this.store = 'DevPlan';
this.tbar = [{
xtype: 'filterfield',
id: 'filter_login',
triggerCls: 'icon-user',
//scope:this - how to pass scope to panel without defining onTriggerClick here
// onTriggerClick: function() {
// this.fireEvent('filterclick'); //working event is fired but controller cant see it
// this.filterList; //this is working but i dont want to put this code in every filterfield
// },
// listeners : {
// filterclick: function(btn, e, eOpts) { //this is working
// }
// },
}];
this.columns = [{
id: 'id',
header: "Id",
dataIndex: "id",
width: 50,
sortable: true,
filterable: true
}, {
header: "Name",
dataIndex: "name",
width: 150,
sortable: true,
filterable: true
}, {
header: "Author",
dataIndex: "author",
sortable: true,
renderer: this.renderLogin,
filterable: true
}];
this.callParent(arguments);
},
filterList: function() {
this.store.clearFilter();
this.store.filter({
property: 'id',
value: this.down("#filter_id").getValue()
}, {
property: 'name',
value: this.down("#filter_name").getValue()
});
},
renderLogin: function(value, metadata, record) {
return value.login;
}
});
part of code of Controller:
init: function() {
this.control({
'attachments': {
filesaved: this.scanSaved,
}
}, {
'scan': {
filesaved: this.attachmentSaved
}
}, {
'#filter_login': {
filterclick: this.filterStore //this is not listened
}
});
},
filterStore: function() {
console.log('filtering store');
this.getPlanListInstance().filter();
},
Controller can listen to anything. Just need to specify exactly what to. But I would fire events on the panel level - add this into your trigger handler:
this.up('panel').fireEvent('triggerclicked');