jquery.on() event handlers not firing on dynamically added $element - dom

To illustrate my problem, I created a jsfiddle page here
http://jsfiddle.net/7HZvS/
Why does the alert function not get fired after the panel slides? Click on the grey box labeled "swiperee" and watch a grey panel slide in. Then click on the one labeled "swiperee2". Nothing. Should cause an alert. :(
Since the first panel slides when you click on the "swiperee" grey button, I see no reason why the second grey button "swiperee2" doesn't handle its .on() event - its generated identically.
Thanks.
EDIT:
Gabe's answer below is not exactly right IMHO. Firstly, his code is using the .on() event list not events-map but that's just syntax. his point is that the events should be delegated because I'm dynamically adding elements.
I'm actually not sure that is really the right thinking, because I have all elements in fact already loaded, they're just not displayed - there is no ajax here. All that happens is that elements move around the DOM hierarchy.
below is the sample code from the jsFiddle above, as requested.
$(function(){
var g = {
func : {
swipeLeft : function($el)
{
$RIGHT = $('<div id="right">')
.appendTo('body')
.addClass('scrollable hwaccel')
.css({
'position' : 'absolute',
'z-index' : '2',
'top' : '0px',
'left' : '640px',
'width' : '640px',
'height' : '960px',
'border' : '1px solid #ccf'
})
;
$el.appendTo($RIGHT);
$('#right, #main').animate(
{
left : '-=640px'
},
500,
function(){
$MAIN.empty();
$el.appendTo($MAIN);
$MAIN.css('left','0px');
$RIGHT.remove();
}
);
}
}
};
$MAIN = $('<div id="main">')
.appendTo('body')
.addClass('scrollable hwaccel')
.css({
'position' : 'absolute',
'z-index' : '1',
'top' : '0px',
'left' : '0px',
'width' : '640px',
'height' : '960px',
'border' : '1px solid #009'
})
;
$start = $('<div id="start">')
.appendTo($MAIN)
.css({
'position' : 'absolute',
'top' : '0px',
'left' : '0px',
'width' : '640px',
'border' : '1px solid #900'
})
.html(
'hello<br/>456'
)
.append(
$('<div id="swiperee">')
.css({
'position' : 'absolute',
'top' : '10px',
'left' : '10px',
'width' : '100px',
'height' : '40px',
'background': '#ccc',
'cursor' : 'pointer'
})
.html('swiperee')
.on({
click : function(){
g.func.swipeLeft($next);
}
})
)
;
$next = $('<div id="next">')
.css({
'position' : 'absolute',
'top' : '0px',
'left' : '0px',
'width' : '640px',
'height' : '960px',
'background': '#ddd'
})
.html(
'sdfjkgh sdklfjgh sdklfjgh skldfj ghskldjgh'
)
.append(
$('<div id="swiperee2">')
.css({
'position' : 'absolute',
'top' : '10px',
'left' : '10px',
'width' : '100px',
'height' : '40px',
'background': '#ccc',
'cursor' : 'pointer'
})
.html('swiperee2')
.on({
click : function(){
alert('sdf');// WHY DOES NOT CALL??
}
})
)
;
});
​

The problem is the line $MAIN.empty() in the animate callback. Remove that and it works.
The .empty() call apparently does some cleanup where it unbinds event handlers.

Related

Set store dynamic on a combobox

Hi,
I have two combo boxes. The value of second combo box depends on first combo select. The user does select the first combo then the store of second will be set accordingly.
Here are my two Combos:
Combo 1
items:[
{
xtype : 'combo',
name : 'cmbSATopFacility',
labelStyle : 'color: black; font-weight: bold; width: 250px; padding: 10;',
labelSeparator : "",
id : 'cmbSATopFacility',
width : 250,
fieldLabel : 'Top MGMT Entity',
triggerAction : 'all',
store : Ext
.create(
'Ext.data.Store',
{
id : 'store',
fields : [
{
name : 'id',
type : 'integer',
},
{
name : 'name'
} ],
remoteGroup : true,
remoteSort : true,
proxy : {
type : 'rest',
url : 'pmsRest/facilities?sub_facility_id=-3',
reader : {
root : "facilityMaster",
idProperty : 'id'
}
},
autoLoad : true
}),
displayField : 'name',
valueField : 'id',
multiSelect : false,
typeAhead : true,
listeners : {
change : function(combo) {
/// code to convert GMT String to date object
n();
Ext.getCmp('cmbSAMedFacility').getStore().load();
}
},
allowBlank : false,
//enableKeyEvents : true,
},
Combo 2
{
xtype : 'combo',
name : 'cmbSAMedFacility',
labelStyle : 'color:black;font-weight:bold;width:250px;padding:10;',
labelSeparator : "",
id : 'cmbSAMedFacility',
width : 250,
fieldLabel : 'Institution',
triggerAction : 'all',
store : medfacility,
displayField : 'name',
valueField : 'id',
multiSelect : false,
typeAhead : true,
//disabled: true,
listeners : {
click : function(combo) {
alert("hjdfhcsdj");
n();
Ext.getCmp(this).getStore().load();
}
},
allowBlank : false,
//enableKeyEvents : true,
},
]
Code to set store
var medfacility = loadFacility();
function loadFacility(){
topApp = Ext.getCmp('cmbSATopFacility').getValue( );
alert(topApp);
var urL = 'pmsRest/facilities?sub_facility_id='+topApp ;
alert(urL);
var store = Ext.create('Ext.data.Store', {
id : 'store',
fields : [
{
name : 'id',
type : 'integer',
},
{
name : 'name'
} ],
remoteGroup : true,
remoteSort : true,
proxy : {
type : 'rest',
url : urL,
reader : {
root : "facilityMaster",
idProperty : 'id'
}
},
autoLoad : true
});
return store;
}
I tried to get the values in the second combo but it didn´t work.
WE CAN USE ONLY
listeners : { change : function(combo) { Ext.getCmp('cmbSAMedFacility').bindStore(n());}},
I think you need describe a store for a second combobox, but without data (empty array).
And fill data for that store when you need by using loadData method.
Hope this helps.

Not showing the form corretly in ExtJs

I've created a form using ExtJs library. Here is my code;
form1 = new Ext.form.FormPanel({
bodyStyle : {
"background-color" : "#000000"
},
items : [ {
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Vehicle Registration Number',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Device ID',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Default Rep',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Driver',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Assistant',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Porter 1',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Porter 2',
editable : false,
},
{
xtype : 'combo',
name : 'include_type',
fieldLabel : 'Porter 3',
editable : false,
},
],
buttons : [ {
text : 'Delete',
handler : function() {
}
}, {
text : 'View',
handler : function() {
}
}, {
text : 'New',
handler : function() {
}
}, {
text : 'Exit',
handler : function() {
win1.hide();
}
} ]
});
win1 = new Ext.Window({
title: 'Vehicle Assigning',
layout: 'fit',
autoScroll: true,
y: 120,
width: 600,
height: 500,
modal: true,
plain:true,
bodyStyle:'padding:8px;',
buttonAlign:'center',
closeAction: 'hide',
floating: true,
closable : true,
items: [form1]
});
win1.show();
It pop ups a new window successfully, but there is a problem. All the text fields(Vehicle Registration Number, Device ID, and so on) are not showing correctly. The form looks like following:
Why these text fields are not showing correctly ? Another thing that I want to know is how should I center the whole form within the window. I've tried following code but no luck.
layout: {
pack: 'center',
type: 'hbox'
},
Any suggestions are appreciated.
Thank you
1) Looks like your border is overlapping your labels. You can add some padding to the label if you want to move them over slightly. (see below)
2) You have to set the layout on the form, not on the window, if you want the form's contents to be centered.
The code below applies a label width of 200 to each label, adds 25px of padding to the left hand side, and centers the labels and fields in the form.
var form1 = new Ext.form.FormPanel({
bodyStyle : {
"background-color" : "#000000"
},
layout: {
type: 'vbox',
align: 'center'
},
defaults: {
labelWidth: 200,
padding: '0 0 0 25'
},
...

how to add/remove composite field in extjs 3.4 dynamically

i am using extjs 3.4 add add this code for add /remove key value pair in field set but is not working fine it is add the field dynamically but when we remove this browser given the infinite loop error and after some time field is also given the following error:
TypeError: this.dom is undefined
here is my code :
//This js for test only
Ext.onReady(function(){
Ext.QuickTips.init();
function addressCounter(incr) {
if (!this.no) {
this.no = 0;
} else {
this.no = this.no + 1;
};
};
var counter = new addressCounter();
console.log(counter.no);
var roomPanel = new Ext.form.FormPanel({
renderTo:"sid",
id: "roomFP",
baseCls: 'x-plain',
labelWidth: 120,
defaultType: 'textfield',
monitorValid:true,
bodyStyle: ' padding: 15px; background-color: #ffffff' ,
items:[
{
xtype: 'fieldset',
title: 'Room Properties',
collapsible: true,
id:'roompropertiesId',
items:[new Ext.Button({
text:'Add Property',
handler: function(item){
var fieldset = Ext.getCmp('roompropertiesId');
if(fieldset.items.length >5){
Ext.MessageBox.alert('Add Property','only five fields has been added');
return;
}
counter.no = counter.no + 1;
var a = fieldset.add({
xtype : 'compositefield'
,
id : 'compositefieldId'+counter.no
,
name : 'name'+counter.no
,
height : 22
,
autoDestroy : true
,
items : [{
name : 'key'+counter.no
,
fieldLabel : "Key",
id : 'keyFieldId'+counter.no
,
xtype : 'textfield'
,
width : 50
,
height : 22
,
allowBlank : true
},{
name : 'value'+counter.no
,
xtype : 'textfield',
id : 'valueFieldId'+counter.no
,
fieldLabel : 'Value'
,
width : 50
,
allowBlank : true
},{
xtype : 'displayfield',
id:'removeFieldId'+counter.no,
html : '<div class="img-delete" onclick="removeFormFields(\''+counter.no+'\');">Remove</div>'
,
height : 16
}]
});
fieldset.doLayout();
removeFormFields = function(id) {
Ext.getCmp('compositefieldId'+id).destroy();
}
}
})]
}
],
listeners : {
render : function(form){
}
},
});
});
It looks like it is bug in Ext JS.
When you put normal Container instead of CompositeField then it works properly.
I figured out that CompositeField subfields are added to BasicForm (FormPanel.getForm) on CompositeField creation, but aren't removed. This causes that, for example, BasicForm validation refers to destroyed fields, and causes error.
IMO you can freely switch from CompositeField to Container.
Call formPanel.getForm().cleanDestroyed() after composite component is destroyed.

getting TypeError: el is null .../ext/ext-all-debug-w-comments.js Line 44393 when loading grid a second time

I'm using a panel called "content panel" in the center of a border layout of my viewport.
I swap content in and out as needed by click handlers against the menu buttons. The second time I swap in this grid it gives this error. This is the only grid that does it in the app and the only grid that has a paging bar. I know the error has something to do with the paging bar being rendered. What am I missing?
controller (changes is the button that's failing):
Ext.define('DDI.controller.DDI', {
extend : 'Ext.app.Controller',
views : [ 'panel.BannerPanel', 'panel.ContentPanel', 'panel.NavPanel', 'panel.FooterPanel', 'Welcome' ],
init : function() {
this.control({
'navpanel button[text=Home]' : {
click : function() {
var cp = Ext.getCmp('contentpanel');
cp.removeAll();
cp.add({
xtype : 'welcomepanel'
});
}
},
...
'navpanel button[text=Changes]' : {
click : function() {
var cp = Ext.getCmp('contentpanel');
var height = Ext.getBody().getViewSize().height - 100;
// cp.removeDockedComponent(cp.getDockedComponent(0));
cp.removeAll(false);
cp.add({
xtype : 'changesummaryview',
height : height
});
cp.doLayout();
}
},
....
The grid panel is defined as such:
var changeStore = Ext.create('DDI.changetracker.store.Change');
Ext.define('DDI.changetracker.view.ChangeSummaryView', {
extend : 'Ext.grid.Panel',
alias : 'widget.changesummaryview',
id : 'changesummaryview',
title : 'All Change Summary',
scroll : 'both',
store : changeStore,
tbar : [
'Open Change Summary View',
'-',
{text : 'New Change'
}, {
xtype : 'button',
text : 'Print'
},
'->',
{xtype : 'exporterbutton'
}
],
bbar : Ext.create('Ext.PagingToolbar', {
store : changeStore,
displayInfo : true
}),
listeners : {
'render' : function(grid) {
grid.view.tip = Ext.create('Ext.tip.ToolTip', {
target : grid.getEl(),
showDelay : 2000,
// Each grid row causes its own seperate show and hide.
delegate : ".x-grid-cell",
items : [], // add items later based on the record
// Render immediately so that tip.body can be referenced prior
// to the first show.
listeners : {
// Change content dynamically depending on which element
// triggered the show.
beforeshow : function updateTipBody(tip) {
var rec = grid.view.getRecord(
Ext.get(tip.triggerElement).findParentNode('.x-grid-row'));
grid.fireEvent('rowhover', tip, rec);
return true;
}
}
});
}
},
columns : [
{
header : 'ticket',
dataIndex : 'ticket',
filter : {
type : 'string'
},
flex : 1,
editor : 'textfield'
},
{
header : 'account_name',
dataIndex : 'account_name',
flex : 1,
editor : {
xtype : 'customercombo',
fieldLabel : ''
}
},
{
header : 'employee_1',
dataIndex : 'employee_1',
flex : 1,
editor : {
xtype : 'personelcombo',
fieldLabel : '',
valueField : 'name'
}
},
{
header : 'dns_team_approved',
dataIndex : 'dns_team_approved',
filter : {
type : 'string'
},
flex : 1,
editor : {
xtype : 'dnsapprovecombo',
fieldLabel : ''
}
},
{
header : 'approval_status',
dataIndex : 'approval_status',
flex : 1,
editor : {
xtype : 'approvalstatuscombo',
fieldLabel : ''
}
},
{
header : 'status',
dataIndex : 'status',
flex : 1,
filter : {
type : 'list',
options : [ [ '%', 'All' ], [ 'OPEN', 'OPEN' ], [ 'HOLD', 'HOLD' ], [ 'CLOSED', 'CLOSED' ],
[ 'CANCELED', 'CANCELED' ] ],
value : '%',
active : true,
single : true
},
editor : {
xtype : 'statuscombo',
fieldLabel : '',
store : 'Status'
}
}, {
header : 'open_date',
dataIndex : 'open_date',
flex : 1,
editor : 'textfield'
}, {
header : 'next_check',
dataIndex : 'next_check',
flex : 1,
editor : 'textfield',
renderer:function(value, metadata, record, rowIndex, colIndex, store){
a=value.split(" ");
d=a[0].split("-");
t=a[1].split(":");
dateValue=new Date(d[0],d[1]-1,d[2],t[0],t[1],t[2]);
today=new Date();
if (dateValue <= today){
return '<span style="background-color: #FFff66">'+value+'</span>';
}
return value;
}
}, {
header : 'start_time',
dataIndex : 'start_time',
flex : 1,
editor : 'textfield',
renderer:function(value, metadata, record, rowIndex, colIndex, store){
a=value.split(" ");
d=a[0].split("-");
t=a[1].split(":");
dateValue=new Date(d[0],d[1]-1,d[2],t[0],t[1],t[2]);
today=new Date();
if (dateValue <= today){
return '<span style="background-color: #FF8080">'+value+'</span>';
}
return value;
}
}, {
header : 'end_date',
dataIndex : 'end_date',
flex : 1,
editor : 'textfield'
}, {
header : 'is_expedited',
dataIndex : 'is_expedited',
flex : 1,
editor : 'textfield'
} ],
features : [ {
ftype : 'filters',
encode : false,
local : false
} ],
plugins : [ {
ptype : 'cellediting',
clicksToEdit : 2,
pluginId : 'cellediting'
} ]

Using Fancybox 2 with Scriptculous?

Has anyone successfully used both libraries together? I can't seem to place the code in the properly sequence to get them to work together.
According to your comment, you are doing this :
jQuery.noConflict(
$(document).ready(function () {
$('.fancybox-media').fancybox({
openEffect : 'none',
closeEffect : 'none',
helpers : {
media : {}
}
});
$(".fancybox").fancybox({
openEffect : 'none',
closeEffect : 'none'
});
});
);
... try this instead :
jQuery.noConflict();
jQuery(document).ready(function($) {
$('.fancybox-media').fancybox({
openEffect : 'none',
closeEffect : 'none',
helpers : {
media : {}
}
}); // first fancybox
$(".fancybox").fancybox({
openEffect : 'none',
closeEffect : 'none'
}); // second fancybox
}); // ready
Have you tried using jquery's noConflict() ? Since you are using two different libraries, it might be causing error. Using jQuery.noConflict() function might help.