Buttons from cloned section not working properly - javascript

I'm new to jquery scripts. I managed to clone one section of the form dynamically but my button to display the ckeditor's div in the cloned section is not working. It still listening to the button from the original section and will only show the ckeditor's div(but unable to edit all of them except the original) when the original button was clicked. Here is my code:-
for(i=num; i<value; i++){
var newSlot = $('#slot' + i).clone().attr('id','slot' + (i+1));
newSlot.find('.heading-slot').attr('id', 'ID' + (i+1) + '_slot').html('Slot ' + (i+1)); //add new slot name
newSlot.find('.other_message').hide();
newSlot.find('.select_instruction').on('change', function () {
$(this).next('.other_message').toggle((this.value) == "Other")
});
newSlot.find('.extra_instruction').hide();
//the button here is not working as I wanted
newSlot.find('.btnAdditional').on('click', function(){
$(this).next('.extra_instruction').show();
});
$('#slot' + i).after(newSlot);
}
html code
<div class="col-sm-6">
<button type="button" id="btn_Additional" name="btn_Additional" class="btnAdditional btn btn-info">Additional Instruction</button>
<div class="extra_instruction">
<textarea id="input_add_instruction" name="add_instruction[]" class="form-control"></textarea>
<script>CKEDITOR.replace( 'input_add_instruction' );</script>
</div>
</div>
Can anyone guide me on this?? Please I'm very new to this. Thanks in advances..

The clone function not only clones the html but also the event listeners, instead of cloning try creating your element and adding the event listeners properly.

Related

How to select element after it was added to DOM

On my HTML I have buttons list and text input field. Input field is to add extra buttons to my buttons list.
On jQuery I have eventListener when one of these buttons with .choices is clicked console log its value.
It works fine without any errors. But when I add extra button to my list with same class (.choices) new button appears but it doesn't respond to my click.
Any suggestions?
<div class="buttons">
<button id="button0" class="choices">Running</button>
<button id="button1" class="choices">Yoga</button>
<button id="button2" class="choices">Karate</button>
</div>
JS
$("#add-button").click(function(){
var inputValue = $("#add-input").val();
var generatedId = "button" + healthyChoices.length;
healthyChoices.push(inputValue);
$("<button>").attr("id", generatedId).appendTo(".buttons");
$("#" + generatedId).attr("value", inputValue);
$("#" + generatedId).attr("class", "choices");
$("#" + generatedId).text(inputValue);
$("#add-input").val("");
});
$(".choices").click(function(){
var selectedGroup = $(this).val();
console.log(selectedGroup);
});
The .click method does not handle elements dynamically added to the DOM. You should be using the .on method (as indicated by dfsq's comment).
See this SO post: Difference between .on('click') vs .click()

"change" not working like "click"

So I have a web page that looks like this to start with, essentially...
<div id="videonotes_container">
<div id="videonotes_information">
<div id="videonotes_name">Name</div>
<div id="videonotes_points">100 points etc</div>
<div id="videonotes_instructions">
Instructions
</div>
**<div id="videonotes_quicklinks">
<!-- this is where the quick links to the past comments go. -->
</div>**
</div>
<div id="videonotes_video">
<div id="videonotes_video_player"></div>
<div id="videonotes_video_player_overlay"></div>
</div>
<div id="videonotes_controls">
<div id="videonotes_start" class="videonotes_videocontrol">-></div>
<div id="videonotes_pause" class="videonotes_videocontrol">::</div>
<div id="videonotes_stop" class="videonotes_videocontrol">STOP</div>
<div id="videonotes_back30" class="videonotes_videocontrol">RW30</div>
<div id="videonotes_forward30" class="videonotes_videocontrol">FF30</div>
</div>
</div>
and the bit in bold is an area which is dynamically populated by javascript after the page has loaded, with a function that looks like this...
function videonotes_addNote(user_note_id, time, note, rating, feedback) {
// add a new div...
var html_fb = "";
var html_hl = "";
html_hl += "<div class=\"videonotes_note_time\">"+time.toFixed(0)+"</div>";
html_hl += "<div class=\"videonotes_note_note\" data-id=\""+user_note_id+"\" contenteditable>"+note+"</div>";
html_hl += "<div class=\"videonotes_note_comments\">"+rating+"</div>";
// iterate over the feedback and add it into the program.
feedback.forEach(function(value) {
html_fb += "<div class=\"videonotes_note_feedback_note\"><span class=\"videonotes_note_feedback_intro\">"+value.username+" ("+value.timestamp+") said</span> "+value.feedback+"</div>";
html_fb += "<div class=\"videonotes_note_feedback_useful\" data-id=\""+value.noteid+"\">";
html_fb += "<div class=\"videonotes_note_feedback_useful_yes videonotes_note_feedback_useful_button\">ACC</div>";
html_fb += "<div class=\"videonotes_note_feedback_useful_no videonotes_note_feedback_useful_button\">NAC</div>";
html_fb += "</div>";
});
// create a new note on the notes box...
var new_note = $('<div/>', { 'class':'videonotes_note' }).appendTo('#videonotes_quicklinks');
// add the headline to the div...
$('<div/>', { 'class':'videonotes_note_headline', 'html': html_hl, 'click':function(){ videonotes_clickNote(this, time); },}).appendTo(new_note);
// and add the feedback
$('<div/>', { 'class': 'videonotes_note_feedback', 'html': html_fb }).appendTo(new_note);
}
You will note there are a few bits created from this - there are onclick events created which will open feedback on this particular note and navigate to a part of a video. This all works just fine, and the onclick events work just fine for the dynamically created elements. The exception is that for each note you should be able to rewrite it in the div, so you can click the div with the note in, it will naviagte to the correct part of the video (works), it iwll open up the feedback (works) and when you EDIT the .videonotes_note_note class it will fire an update using this method:
$('#videonotes_container').on("change", '.videonotes_note_note', function() { videonotes_update_note($(this).data('id'), $(this).value()); })
However this does not work. I have tried $(document) and all other parent, pre loaded divs I can think of but it still doesnt fire that particular event. There is no difference in the way I am creating this listener to the others, and all the clicks work fine, but the change doesnt.
Am I misunderstanding how the change element works?
change event is not supported on the div tag, you can get the list of input on which change event get fired . https://www.w3schools.com/jsref/event_onchange.asp

Can bPopup trigger and target divs be assigned dynamically?

We have a list of paired divs dynamically built in a ColdFusion page (internshipHandleX, internshipHiddenX, etc.) by looping over a query and adding the current row, eg:
<div id="internshipHidden#internship.currentrow#" class="hidden pop-up">
that we want to bind together as modal windows and corresponding triggers. Using this code:
for (var row = 1; row <= totalInternships; row ++){
var thisHandle = "#internshipHandle" + row;
var thisHidden = "#internshipHidden" + row;
$(thisHandle).click(function(e){
e.preventDefault();
$(thisHidden).bPopup({modalColor:"black"});
});
}
We apparently link all of the internshipHandle(s) to the last internshipHidden.
What am I missing? Is there a better way to make modal windows out of dynamically created css-hidden divs (that is, within the skeleton framework? I REALLY don't want to start over using bs.)
DreamWeaver is not happy about me putting functions in loops but all the cool kids tell me not to listen to it.
Edit:tryed the same thing with the jqueryUI dialog and had the same problems. I'd love an explanation. Thanks!
Welcome to Javascript. You just encountered a closure in its natural habitat.
In order to have the row variable working the way you expect it to, you need to pass it in its own scope. This can be done using a closure. You may want to dig deeper into that topic, but for now, here is a fix for your problem:
var totalInternships = 2;
for (var row = 1; row <= totalInternships; row++){
var bindInternship = function(rowIndex) {
$("#internshipHandle" + rowIndex).click(function(e){
e.preventDefault();
alert('pop-up #' + rowIndex);
//$("#internshipHidden" + rowIndex).bPopup({modalColor:"black"});
});
};
bindInternship(row);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button type="button" id="internshipHandle1">pop-up 1</button>
<div id="internshipHidden1" class="hidden pop-up">
<button type="button" id="internshipHandle2">pop-up 2</button>
<div id="internshipHidden2" class="hidden pop-up">
Note: I commented the line for the bPopup. Uncomment it, remove the alert and you're good to go.

Delete Table Row Except in First Row

I have a form which allows the user to add a new table row via a button in the bottom row which all is working well. I now need to also add the functionality to have an additional button to allow them to delete a table row.
I gather the simplest method would be to use:
$(this).closest('tr').remove();
but I'm having trouble integrating this into the existing functionality. I also only need the "delete" button to appear on all rows except the first row (i.e. users can delete all rows except the first one). I've setup a jsfiddle here that demonstrates my current functionality:
http://jsfiddle.net/fmdataweb/daayf/1/
So in my example when the user clicks the "Add another activity" button it should create the new table row as it currently does but also add the "delete" button which deletes that row. I've currently hard-coded the "delete" button to the first row as I'm now sure how to make it appear only for new rows created via the "add new activity" button.
Few changes
In the starting markup, add the classes addbtn and delbtn also hide the delete button
<td>
<input type="button" class="button mt5 addbtn" value="Add another activity" id="button1" name="button2" />
</td>
<td>
<input type="button" class="button mt5 delbtn" value="Delete" id="deleteRowButton" name="deleteRowButton" style="display: none"/>
</td>
Then
$('#lastYear').on('click', '.delbtn', function () {
$(this).closest('tr').remove()
});
var newIDSuffix = 2;
$('#lastYear').on('click', '.addbtn', function () {
var thisRow = $(this).closest('tr')[0];
$(thisRow).find('.delbtn').show();
var cloned = $(thisRow).clone();
cloned.find('input, select').each(function () {
var id = $(this).attr('id');
id = id.substring(0, id.length - 1) + newIDSuffix;
$(this).attr('id', id);
});
cloned.insertAfter(thisRow).find('input:text').val('');
cloned.find('.delbtn').hide();
cloned.find("[id^=lastYearSelect]")
.autocomplete({
source: availableTags,
select: function (e, ui) {
$(e.target).val(ui.item.value);
setDropDown.call($(e.target));
}
}).change(setDropDown);
$(this).remove();
newIDSuffix++;
});
Demo: Fiddle
Check out this one!
if($("table tr").length > 1) {
$(this).parent().parent("tr").remove();
}
Try this
On your Delete Button
$('#lastYear').on('click', '#deleteRowButton', function(e){
$(this).closest('tr').remove()
})
First of all I renamed your Button1 for your Adding a Row to addRowButton and then I change the delegate method to be more specific to addRowButton that is from
$('#lastYear').delegate('input[type="button"]'
To like this:
$('#lastYear')delegate('input[type="button"][id^="addRow"]'
Then inside the delegate method specifically after
$(this).attr('id', id);
I add after that the one below:
var checkid = $(this).attr('id').substring(0,id.length-1);
if (checkid == 'deleteRowButto') // the 'deleteRowButto' is not a mistake
{
$(this).click(function() {
$(this).closest("tr").remove(); // I assign an onclick for the delete button in order to remove a specific row
});
}
Edit:
I made some improvements that once the row is deleted the previous add button is shown so I add the code below:
var showmenow = $(this).closest("tr").prev().find("td:eq(5)").find("input[type='button']");
$(showmenow).show();
$(this).closest("tr").remove();
});
And instead of removing the button in your original code:
$(this).remove();
newIDSuffix++;
I use hide instead:
$(this).hide();
newIDSuffix++;
See the new jsfiddle that I created.
Since you want to use the first row as template for all other row but do not want to have a delete on the all the other rows we should insert the delete only during first insertion in java script.Check this demo out i modified your fiddle for this to work.
if(cloned.find('input.mt5[value="Delete"]').length==0){
cloned.find('.mt5').each(function(){
cloned.append($('<td><input type="button" class="button mt5" value="Delete" id="deleteRow'+newIDSuffix+'" name="deleteRowButton" /></td>'));
})
}
now for handling the delete events
$('#lastYear').delegate('input.button[value="Delete"]', 'click', function () {
var thisrow=$(this).parent().parent();
var button=thisrow.find("input.button[value='Add another activity']");
if(button.length>0){
var buttoncell=button.parent().detach();
var prevrow=thisrow.prev();
var prevDelete=prevrow.find('input.button[value="Delete"]');
var previd=(prevDelete.length>0)?prevDelete[0].id:'deleteRow1';
buttoncell.children()[0].id=previd.replace('deleteRow','button');
prevrow.find('input:text:last').parent().after(buttoncell);
}
thisrow.remove();
});
Demo: http://jsfiddle.net/vwdXD/2/
You have got it right for the most part except for the small oversight here and there. I have fixed your code for you and you can find it here: http://jsfiddle.net/ManojRK/86Nec/ .
Please try to understand the changes by comparing your version and my version using a Code Diff Tool (like http://www.quickdiff.com). It will teach you a lot.
Changes Made:
I have used styles to show and hide your buttons. This is not the only way to do it. But since you are cloning rows to add, using styles will make your JavaScript simple. This is a lot less buggy and less susceptible to changes.
I have introduced css classes to differentiate Add Another Activity and Delete buttons for the click event.
Hope it helps you understand.
I used the jsfiddle that you provided in hopes of being more direct in terms of answering your question. The method I took was to:
Check if the add or delete button was pressed
If the delete button was pressed, check if its the delete button contained within the first row (actually the third row, but it's the first row with user input). If the delete button is in the first row, do nothing
If the delete button was not in the first row, create an 'add activity' button in the previous row and remove the clicked button's parent row.
Step 1:
// let's check whether they clicked the add or delete button
if ( $(this).val() == 'Add another activity' ) { // if the add button was clicked
Step 2-3:
if ( $(thisRow).index() == 2 ) { // if it's the first row, don't let them delete
return false;
} else { // if it is not the first row remove this row and create an 'add' button in first row
$(thisRow).prev().find('td:last').prev().append('<input type="button" class="button mt5" value="Add another activity" id="button2" name="button2">');
$(thisRow).remove();
}
Here's a fiddle for ya: http://jsfiddle.net/daayf/22/
I placed a couple comments in the code to help out a bit. My edits were at:
Line 275-276
Line 300-307
Hope this helps out!
I recommend adding an id attribute dynamically for each row that way you can just refer to that id with jQuery.
You can set a specific class for the buttons like this
<input type="button" class="button mt5 deleteButton" value="Delete" id="deleteRowButton" name="deleteRowButton" />
and add this code to jquery
$('.deleteButton').on('click',function(){
$(this).parent().parent().remove();
});
this jquery deletes the grandparent of the input with deleteButton Class(the delete button), which is the row it is located in.
how about do this?
$(this).find('tr').length > 0 ? $(this).closest('tr').remove() : ;
Why is your "add new activity" and "delete" having the same class "button mt5"? not sure if space is allowed for the name of a class.
You may want to refer to my table here http://jsfiddle.net/yvonnezoe/nbrSR/1/ :D I have a fixed row on top and dynamic rows following that can be deleted.
My new row is created as below:
var str = '<tr id="' + rowID + '">' + '<td>' + index + '</td><td>' + rowID + '</td><td class="type_row_' + textInput + '">' + type + '</td><td class="feedback number">' + textInput + '</td>' + '<td id="status_'+rowID+'"></td>' + '<td><input type="checkbox" name="CB" id="monitor_' + rowID + '" class="custom" data-mini="true" /><label for="CB"> </label></td><td class="outputRemove">x</td>' + '</tr>';
$('#status_table tr:last').after(str);
The remove buttons are having a same class. So the rows can deleted when clicked.
$('#status_table').on('click', '.outputRemove', function () {
$(this).closest('tr').remove();
$('#status_table tbody tr').find('td:first').text(function (index) {
return ++index;
});
});
Hope it inspires you somehow :)
very simple way
function remove_point_item(th) {
var tr = $(th).closest("tr");
var _counter=0;
$(tr.siblings('tr')).each(function(){
_counter++;
});
if(_counter!=1){
tr.remove();
}
}

click() for ClassName

UPDATE: A commenter told me to change some codes, this is the new code and its not working neither.
I'm creating a Facebook-Like chat. It gets the latest messages "Not Read" from a JSON file and it appends the text to an "UL" element vía "LI" into a box. If the box doesn't exist, it creates and attach the text. I want that when I click that div, it hides using margin-bottom negative, and when I click it again it shows by Margin-Bottom:0. Please help me since it's just not working.
function showChat(id){
$(this).animate({marginBottom : "0"}).removeClass("hidden_box").addClass("active_box").removeAttr('onclick').click(function(){
hideChat(Id);
});
}
function hideChat(id){
$(this).animate({marginBottom : "-270px"}).removeClass("active_box").addClass("hidden_box").click(function(){
showChat(Id);
});
}
function getOnJSON(){
//Creating Variables that will be used
var from;var to;var msg_id;var msg_txt;
//Getting the data from the json file
$.getJSON("/ajax/chat.json.php",function(data){
//Repeat for each result
$.each(data.notif, function(i,data){
//Getting a var to info
from = data.from;to = data.to;msg_id = data.id;msg_txt = data.text;
//check if div exists
if ($("#chat_"+from+"_lp").length === 0){
//If not, create the div
$("#boxes").append('<div id="chat_'+from+'_lp" class="chat_box hidden_box clickable_box"></div>');
//Add the senders name
$("#chat_"+from+"_lp").append('<div id="'chat_+from+'_nick" class="chat_name">'+from+'</div>');
//Add the chats UL
$("#chat_"+from+"_lp").append('<ul id="chat_'+from+'_txt" class="chat_txt"></ul>');
//Add the message text
$("#chat_"+from+"_lp").append('<li id="' + msg_id + '">'+ msg_txt+'</li>');
//Add event handler for each div
$('#chat_'+from+'_lp').click(function() {showChat(this);});
//If div exists just add the text
}else{
//Add the message text
$("#chat_"+from+"_txt").append('<li id="' + msg_id + '">'+ msg_txt+'</li>');
//Add event handler for each document
$('#chat_'+from+'_lp').click(function() {showChat(this);});
//Close If
}
//Close data for each item
});
//Close JSON
});
//Close Function
}
UPDATE 2: in order to stop making and appending things, I made an unique HTML string that is going to be appended.
new_chat_string = '<div id="chat_'+from+'_lp" class="chat_box hidden_box clickable_box"><div id="'chat_+from+'_nick" class="chat_name">'+from+'</div><ul id="chat_'+from+'_txt" class="chat_txt"><li id="' + msg_id + '">'+ msg_txt+'</li></ul></div>';
$("#boxes").append(new_chat_string);
use class instead of id
<div id="chat_sender_lp" class="chat_box hidden_box clickable_box sender-click"
then
$('.hidden_box.sender-click').live('click', function(){
$(this).slideToggle(500);
});
After:
$("#boxes").append('<div id="chat_'+from+'_lp" class="chat_box hidden_box clickable_box" ><div id="name">'+from+'</div><ul id="chat_'+from+'_txt" class="chat_txt"><li id="' + msg_id + '">'+ msg_txt+'</li></ul></div>');
Add the event handler for the inserted element:
$('#chat_'+from+'_lp').click(function() { showChat(this) })
"this" passes a DOM reference to itself.
Keep in mind that you're adding: <div id="name"> every time. IDs must be unique. Use a class name instead.
EDIT:
Appending to the DOM is really quite slow. It's actually more efficient to build up your HTML as a string and just insert it in one go. Also, you only really need to stick and ID on the wrapping element. Everything else can be derived from that using a jQuery selector. It helps you write much cleaner code.
Here's the string you need to append:
'<div id="chat_'+msg_id+'" class="chat_box hidden_box clickable_box">
<div class="chat_name">'+from+'</div><ul class="chat_txt"><li>
'+msg_txt+'</li></ul></div>'
If you wanted to select chat name later, you'd use: $('chat_1 .chat_name').html()
It also makes more semantic sense to hook up your click handler to an A tag. So you'd use:
$('#chat_'+msg_id).find('a').click(function() {showChat(this);});
The code is a lot cleaner and easier to follow this way. I hope this helps.

Categories

Resources