Problems with click function in JQuery - javascript

When I add a comment, and hit the click-able text "Edit" the alert box doesn't pop up. First when I add the second comment, I'm able to hit the "edit" on the first one comment, and the alert box pop up.
Why that??
Live Demo
function addComment(name1) {
var container = $('#divComments');
var inputs = container.find('label');
var id = inputs.length + 1;
var div = $('<div />', {
class: 'CommentStyle'
});
$('<label />', {
id: 'comment' + id,
text: name1
}).appendTo(div);
var d = new Date();
var $fulaDate = $('<div class="floatleft">' + d.getFullYear() + "-" + monthNames[d.getMonth()] + "-" + d.getDate() + "T" + d.getHours() + ":" + d.getMinutes() + '</div>').appendTo(div);
var $edit = $('<p />', { class: 'edit', text: 'Edit' }).addClass('edit').appendTo(div);
$('.edit').click(function () {
alert('Hallo');
});
div.appendTo(container);
}

You need to use event delegation for dynamically created elements:
$('#divComments').on('click','.edit',function () {
alert('Hallo');
});
Also, as suggested by #Archer, you need to move the click handler outside of your function to avoid nested click events from firing multiple times.
Updated Fiddle

Problem with your implementation is that when you are attaching event like
var $edit = $('<p />', { class: 'edit', text: 'Edit' }).addClass('edit').appendTo(div);
$('.edit').click(function () {
alert('Hallo');
});
Edit element which you created just now is not added to DOM it is appeded to div only, which is not added to DOM. thus in short it doesn't exists in DOM, thus event is not binded with the button.
So to fix the issue instead of binding event to $('.edit') you need to bind event with $edit.
var $edit = $('<p />', { class: 'edit', text: 'Edit' }).appendTo(div);
$edit.click(function () {
alert('Hallo');
});
DEMO
However I would recommend you to use Event Delegation as
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
Code
function addComment(name1) {
}
$('#divComments').on('click', '.edit', function () {
alert('Hallo');
});
DEMO with event delegation

Related

Confirm-Button event fires twice

So I have a confirm button:
<confirm-button class-name="btn-primary"
text="Save"
body="A customer with the same Last Name is already associated with this Company. Do you want to create this customer anyway?"
action="vm.save(false)"
place="bottom"></confirm-button>
It's a custom directive:
.directive('confirmButton', function () {
return {
restrict: 'E',
replace: true,
scope: {
text: '#',
className: '#',
action: '&'
},
controller: function ($scope, $element, $attrs) {
var content = $attrs.body ? '<p>' + $attrs.body + '</p>' : '';
var place = $attrs.place ? $attrs.place : 'top';
var rndEleId = 'BtnId' + Math.random().toString(36).slice(2);
var popoverOpts = {
title: $attrs.title || 'Are you sure?',
placement: place,
html: true,
content: content +
'<div class="centered">' +
'<button id="yes' + rndEleId + '" name="yes' + rndEleId + '" type="button" class="btn btn-primary btn-small" data-result="yes"><i class="icon-ok"></i> Yes</button>' +
' ' +
'<button id="no' + rndEleId + '" name="no' + rndEleId + '" type="button" class="btn btn-warning btn-small" data-result="no"><i class="icon-ban-circle"></i> No</button>' +
'</div>'
};
$element.popover(popoverOpts)
.parent()
.delegate('button',
'click',
function(e) {
e.preventDefault();
var el = $(e.currentTarget);
var result = el.data('result');
$element.popover('hide');
if (result === 'yes') {
$scope.$apply($scope.action);
}
}
);
},
template: '{{text}}'
};
})
I have this button on the page twice: once at the top of the page, and once at the bottom. Regardless of which one you click, when the Yes or No buttons are clicked, they fire twice. This means the Save method in the button Action property is called twice. If you're updating a record, that's not a horrible thing, but if you're creating a record... It's created twice.
I used Chrome's Developer Tools and placed a breakpoint on the e.preventDefault(); line in the directive, and sure enough, it gets hit twice.
But this ONLY happens if there is more than one of these directives used on the page. If I have just one button (at top or bottom of the page), the e.preventDefault(); breakpoint only gets hit once. Further, it seems like it's multi-threaded. I put a counter variable in at one point, with the old school theory of "set it to 0, then set it to ++, and check to see if it's now 1. If it's greater than 1, don't do the action. If it equals 1, do the action." And the variable... was created new each time, and thus never incremented past 1.
I'm stymied.
You haven't really asked a direct question but it appears that you want to know why this is happening.
It's happening because you are adding a click event listener to the parent of the directive every time the directive loads. So when you had 2 of these directives on the same page, you clicked your button and the event was fired twice because there are 2 event listeners registered. Heres where you are registering your event listener using the delegate method:
$element.popover(popoverOpts)
.parent()
.delegate('button',
'click',
function(e) {
...
First of all you need to make sure that you clean up after yourself and unbind your event listener when your directive get's destroyed (check out life-cycle hooks in the documentation). Here is a quick example of how you can unbind your event listener when your directive get's destroyed:
// ...
// register your popover here
$element.popover(popoverOpts);
// reference your parent
var parent = $element.parent();
// reference your click function
var handleClick = function(e) {
e.preventDefault();
var el = $(e.currentTarget);
var result = el.data('result');
$element.popover('hide');
if (result === 'yes') {
$scope.$apply($scope.action);
}
}
// register your event listener
parent.on('click', handleClick);
// when your directive get's destroyed you need to unbind the `handleClick` function
$scope.$on('$destroy', function(e) {
parent.off('click', handleClick);
});
// ...
To solve your issue you will need to make sure that you are registering your event listeners to suit your needs. You can read more about event listeners here.
Although to be honest, looking at your code, you should give ui-bootstrap a try.

How to create "change" event handlers dynamically?

I create dropdown dynamically.
Their ids are ddl1, ddl2, ddl3 and so on.
$('#ddl1').focus(function() {
var previous = this.value;
}).change(function() {
var index = $(this).find('selected').index();
$('#ddl1').find('option:eq(' + index + ')').hide();
$('#ddl2').find('option:eq(' + index + ')').hide();
});
$('#ddl2').focus(function() {
...
Creation of 7 dropdowns makes me to write 7 change event handlers.
How to implement dynamically create change event?
My dropdown append methods are:
var x=1;
var dropdown=('#ddl1').html();
$('#btnadd').click(function() {
$('#divname').append('<select id="ddl'+x+' > </select> <option>../option>');
x++;
});
Give a common class to every dropdown and refer to that. Also, use .on() (event delegation) to catch dynamic created elements:
$(document).on('change', '.common-class', function() {
//Your function
var currentId = $(this).attr('id');
});
UPDATE
Add the same class every time you append a select element:
//...
$('#divname').append('<select id="ddl'+ x + '" class="common-class"><option>../option></select>');
SELECTED OPTION
In order to get the selected option:
$('#current-id').find('option:selected').index();
Variant without delegated events to reduce resource usage:
var $dds = $('select');
$dds.each(function(index) {
var $this = $(this);
processDdChange($this);
});
function processDdChange($obj) {
$obj.on('change', function(e) {
var $this = $(this);
alert($this.attr('id') + ' | ' + $this.find(':selected').val());
});
}
https://jsfiddle.net/tasmanangel/2p9mbs7h/

jQuery .on() event ignores selector

I have a function to create a div, ID it and add content before binding it to a click event using the .on() method using a selector as the second parameter. Here is the code I am using.
$('#overlayLeft').append(createOption('Item ID'));
function createOption(name){
var element = document.createElement('div');
var noSpaceName = name.replace(" ", "_");
element.id = 'toolOverlay' + noSpaceName;
element.innerHTML = '<input type="checkbox"><label>' + name + '</label>';
$('body').on('click', $('#' + element.id),function(){
alert("Test");
});
return element;
}
However instead of binding the click event to the body using the id of the generated element as the selector, the event acts whenever a click occurs on the body of the page.
How do I get the event to occur only on clicking the element without first creating the element and then binding the event separately?
You do not need jquery object, you need selector.use:
$('body').on('click', '#' + element.id,function(){
alert("Test");
});
also you can bind the click event without delegation using:
$('#' + element.id).click(function(){
alert("Test");
});
You have a strange mix of JQuery and native JS code. Maybe this works for your.
function createOption(){
return $('<div></div>')
.attr('id', 'toolOverlay' + name.replace(" ", "_"))
.append(
$('<input></input>')
.attr('type', 'checkbox'))
.append(
$('<label></label>')
.text(name))
.click(function(){
alert('test');
});
}
Try to put just selector string:
$('body').on('click', '#' + element.id,function()
That's not a selector that you are using, it's a jQuery object.
You can solve it by using just the selector, but instead of binding a lot of delegates to the body element, you can just bind the event on the element. That means that you don't need an id on the element to target it.
$('#overlayLeft').append(createOption('Item ID'));
function createOption(name){
var element = $('<div>');
element.html('<input type="checkbox"><label>' + name + '</label>');
element.click(function(){
alert("Test");
});
return element;
}
Binding global delegates is what the live method did, and it was deprecated because that is not a good way to use delegates.
If you're going to use jQuery, may as well use it everywhere. Note that the .click event is attached to the jQuery object/element as soon as it's created:
$('#overlayLeft').append(createOption('Item ID'));
function createOption(name) {
var noSpaceName = name.replace(" ", "_");
var div = $('<div>', {'id': 'toolOverlay' + noSpaceName})
.append('<label><input type="checkbox">' + name + '</label>')
.click(function () {
alert('test');
});
return div; // returns a jQuery object now, not a DOM element,
// which is fine when using .append() as you do here
}
http://jsfiddle.net/mblase75/bdvk9ssa/

How to change progress bar with creating dynamic checkboxes

I have looked all over and found many similar threads, but none of them really answered my question with this specific situation:
I want to, when the visitor creates dynamic Checkbox, then the visitor checks or unchecks a checkbox it will increase or decrease the value shown on the progress bar. In addition I want to show the percent of the progress bar. Like this: Image
Here is a demo
Here is the Code:
HTML:
<div id="cblist"></div>
<input type="text" id="checkBoxName" />
<input type="button" value="ok" id="btnSaveCheckBox" />
<div id="progressbar"></div>
<br/>
Jquery:
$(document).ready(function () {
$('#btnSaveCheckBox').click(function () {
addCheckbox($('#checkBoxName').val());
$('#checkBoxName').val("");
});
$(function () {
$("#progressbar").progressbar({
value: 0,
max: 100
});
});
});
function addCheckbox(name) {
var container = $('#cblist');
var inputs = container.find('input');
var id = inputs.length + 1;
$('<input />', {
type: 'checkbox',
id: 'cb' + id,
value: name
}).appendTo(container);
$('<label />', {
'for': 'cb' + id,
text: name
}).appendTo(container);
$('<br/>').appendTo(container);
}
Please HELP !!!!
You need to add a Handler to the page to determine when a Checkbox has been checked / unchecked.
To do this you can use a delegate event handler, or assign the Event handler manually when you create the checkbox.
This first example is showing you using the Delegated Event Handler :
JSFiddle
Code :
$(document).ready(function() {
$('#btnSaveCheckBox').click(function() {
addCheckbox($('#checkBoxName').val());
$('#checkBoxName').val("");
});
$(document).on('change', 'input[type="checkbox"]', updateProgress);
$("#progressbar").progressbar({
value: 0,
max: 100
});
});
function updateProgress() {
var numAll = $('input[type="checkbox"]').length;
var numChecked = $('input[type="checkbox"]:checked').length;
if (numAll > 0) {
var perc = (numChecked / numAll) * 100;
$("#progressbar").progressbar("value", perc);
}
}
function addCheckbox(name) {
var container = $('#cblist');
var inputs = container.find('input');
var id = inputs.length+1;
$('<input />', { type: 'checkbox', id: 'cb'+id, value: name }).appendTo(container);
$('<label />', { 'for': 'cb'+id, text: name }).appendTo(container);
$('<br/>').appendTo(container);
updateProgress();
}
The changes made to your code are the addition of the updateProgress(); function, which looks for all the Checkboxes on the page and determines the percentage of them that have been checked, it will then update the Progress bar with this value.
Also the call to the updateProgress function at the end of your addCheckbox function, to re-calculate the percentage done when new elements are added.
And the following line of code in the Document.Ready handler :
$(document).on('change', 'input[type="checkbox"]', updateProgress);
This line of code creates a Delegate event handler to monitor all checkboxes on the page, and any that may be added in future to determine when they have been changed, and when they have it will execute the updateProgress function.
By Manually Assigning Event Handler on Creation :
If you don't want to use a Delegated event handler and want to use a direct event handler, you can do the following.
Change the line that creates the checkbox in your addCheckbox function to the following :
$('<input />', { type: 'checkbox', id: 'cb'+id, value: name }).appendTo(container).change(updateProgress);
This adds an event handler to the change event of the element and calls the updateProgress function.
To display the Value on the Progress bar : See this answer
Basically when you set the value of the Progress bar (in the updateProgress function) change the line to be the following :
$("#progressbar").progressbar("value", perc)
.children('.ui-progressbar-value')
.html(perc.toPrecision(3) + '%')
.css("display", "block");
This will then display the value in the progress bar. You can format the text using the following CSS :
.ui-progressbar-value {
font-size: 13px;
font-weight: normal;
line-height: 18px;
text-align:center;
}
check this fiddle:
UPDATED
http://jsfiddle.net/KAALv/8/
to increment progressbar use these code:
var val = $("#progressbar").progressbar( "value" ) || 0;
$("#progressbar").progressbar( "value", val + 5 );
UPDATE Also use this to give percentage value to a textbox..
$("#progressbar").progressbar({
value: 0,
max: 100,
change: function() {
$("#txtProgressbarStatus").text( $("#progressbar").progressbar( "value" ) + "%" );
},
});

Can I trigger an eventClick from outside the calendar?

I'm creating a "summary" list of events on the page alongside the calendar. I want to trigger the eventClick handler of an event when I click on the entry in the summary. The markup for a summary entry is
<dd id="E45">9:00am-10:00am</dd>
where the id is fullCalendar's event ID.
How can I trigger an eventClick (on the correct event) when the user clicks on the dd?
EDIT:
Thanks for the response. I don't think I was clear enough, though, about what I'm trying to do.
I don't want the fullCalendar instance to have to know in advance that its eventClick event might be triggered from an event outside of itself.
If "summary" and "calendar" are two separate divs and the fullCalendar has been instantiated in the "calender" div and a summary object has been instantiated in the "summary" div, then I'd like to do something like this to trigger the eventClick of the calendar (and pass the correct arguments) when a dd is clicked in the summary.
$("#summary dd").click($("#calendar").fullCalendar.trigger("eventClick", ???????));
This would not be in the fullCalendar code.
Instead of triggering eventClick handler, I've used the updateEvent fullCalendar method:
var eventsToBeUpdated = [];
var allEvents = $('#calendar').fullCalendar('clientEvents');
var chosenEvents = $('#calendar').fullCalendar('clientEvents', eventId);
// remove selected-event css from all events
for (var ei in allEvents) {
var e = allEvents[ei];
var classIndex;
if (classIndex = e.className.indexOf("selected-event") != -1) {
e.className.splice(classIndex, 1);
eventsToBeUpdated.push(e);
}
}
if (chosenEvents.length > 0) {
chosenEvents[0].className.push("selected-event")
eventsToBeUpdated.push(chosenEvents[0]);
}
// update all events which have changed
for (uei in eventsToBeUpdated) {
var updatedEvent = eventsToBeUpdated[uei];
$("#calendar").fullCalendar("updateEvent", updatedEvent);
}
Ok , Not sure exactly what you are trying to do.
You can define the eventClick: in the fullcalendar declaration. The calEvent parameter includes the ID from the Event Object. So could you add a new function and then call that same function passing the ID from your <DD ID="1"> that matches the event click?
$('#calendar').fullCalendar({
header: {
left: 'prev, next today',
center: 'title',
right: 'month, basicWeek, basicDay'
}
eventClick: function(calEvent, jsEvent, view) {
alert('Event: ' + calEvent.title);
alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
alert('View: ' + view.name);
// change the border color just for fun
$(this).css('border-color', 'red');
eClick(calEvent.id);
}
});
function eventClick(id) {
alert('Event ID: ' + id);
' Your event click code would go here.
}
try this :
$("#summary dd").click(function() {
var eventId = $(this).attr('id');
var events = $('#calendar').fullCalendar('clientEvents',eventId);
if (events.length > 0) {
$("#calendar").fullCalendar.trigger('eventClick', events[0]);
}
});

Categories

Resources