I've been going through my dynamically added code and changing everything that was using .click() to use .on("click") and its been working great but now I've run into something that I am not sure how to convert to dynamically added compatible.
Here is the code: This is a function in javascript that is called when a button named "Add" or "Remove" is clicked (these buttons are also dynamically added after another button is clicked)
function row_add_remove(sname, snum, count, type) {
if (type == "add") {
var selectbox = '<select id="qty_'+snum+'_'+count+'" name="qty_'+snum+'_'+count+'">';
for (i=1;i<16;i++){selectbox += '<option value='+i+'>'+i+'</option>';}
selectbox += '</select>';
if (count > 1) {
$("#tr_"+sname+"_"+(count-1)).after('<tr id="tr_'+sname+'_'+count+'"><td>'+selectbox+' X <input type=text id="item_'+sname+'_'+count+'" name="item_'+snum+'_'+count+'" size="70" placeholder="Item '+count+'" /></td></tr>');
$("#toprow"+snum+"_count").html("("+count+")");
}
}
if (type == "remove") {
if (count == 1) {
$("#"+sname).hide();
$("#toprow"+snum+"_count").html("");
$("#td_"+sname+"_"+count).remove();
$("#ph_order_div").show();
count--;
}
if (count > 1) {
$("#tr_"+sname+"_"+count).remove();
count--;
$("#toprow"+snum+"_count").html("("+count+")");
}
if (count < 0) {count = 0;}
}
}
The problem (I think, maybe its more than this) is the .after() doesn't fire. Now i'm not sure if the problem lies with that or with the whole code but when I click the Add button its not adding another TR after the one that is shown by default.
This code works great when NOT dynamically added so can anyone help me with what I need to change to get the above function to work when the buttons that call it and the TR's that it tries to modify are dynamically added?
Here is the code that is fired when the buttons are clicked:
whatmeatfield = $("#meat_field_count").html();
$(document).on("click", "#add_btn_1", function() {
if (whatmeatfield <= 0) {whatmeatfield = 1;}
whatmeatfield++;
row_add_remove("meatseafood",1,whatmeatfield,"add");
});
$(document).on("click", "#remove_btn_1", function() {
row_add_remove("meatseafood",1,whatmeatfield,"remove");
whatmeatfield--;
if (whatmeatfield <=0) {whatmeatfield = 1;}
});
in your .after(), there is typo mistake in <input type=text there should be quote like <input type="text"
You have not define whatmeatfield variable. it should be
var whatmeatfield
Also you are directly passing html of some element id, you need to parse it to integer. like
var whatmeatfield = parseInt($("#meat_field_count").html()) ;
This may help you to solve your issues
The problem may occur becouse of two things.
You're using id selector and you're porobably adding another button with the same id and as far as html spec says id should be unique.
What can you do?
Change ID to CLASS.
The problem occurs becouse you're changing the id to schema like #remove_btn_1, #remove_btn_2, #remove_btn_3 and therefore you do not have any handler for this buttons.
What can you do?
Change selector from "#remove_btn_1" to "[id*=remove_btn_]"
Of course same with #add_btn_
Post me back if it was helpful.
Related
i have a page and i got 2 tables in that page. I want to pass the value from rows to one .php page but with the same button. My code is this:
JS code:
var flag;
function highlight(e) {
if (selected[0]){
selected[0].className = '';
flag='1';
}
else if (selected2[0]){
selected2[0].className = '';
flag='0';
}
e.target.parentNode.className = 'selected';
alert(flag);
}
var table = document.getElementById('data-table'),
selected = table.getElementsByClassName('selected');
var table2 = document.getElementById('data-table-aux'),
selected2 = table2.getElementsByClassName('selected');
table.onclick = highlight;
table2.onclick=highlight;
$("#tst").click(function(){
if(flag=='1'){
var value =$(".selected td:first").html();
value = value || "Nenhuma coluna selecionada";
window.open("info_detalhada.php? data2="+value,'_blank','toolbar=0,location=no,menubar=0,height=550,width=650,lef t=200, top=300'); }
else if(flag=='0'){
var value =$(".selected td:first").html();
value = value || "Nenhuma coluna selecionada";
window.open("info_detalhada2.php? data2="+value,'_blank','toolbar=0,location=no,menubar=0,height=550,width=650,lef t=200, top=300');
}
});
HTML CODE
creating 2 tables
<table style="float: left" id="data-table"></table>
<table style="float: left" id="data-table-aux"></table>
(Dynamic tables )
button:
<input type="button" id="tst" value="Detailed information" />
The problem is that first time i select a row the variable flag will have the old value and not the new value from click.
For example, first time i click a row flag = undefined , second time got the value of the table selected (0 or 1) , if i click on other row the flag wont change and will got the old value (or 0 or 1).
Any tips ?
Thanks
edited: i didnt put the html in first place because i dont think it's an html solution, I dont have a fiddle created because i'm using dynamic table's but i will try to make a fiddle with my example and i will put here when it's done ;)
Fiddle : https://jsfiddle.net/gwg639Lf/9/
Let me suggest a more generic approach
First of all wrap your tables in a div
<div class="data-tables">
<table style="float: left" id="data-table"></table>
<table style="float: left" id="data-table-aux"></table>
</div>
Then delegate the click event handlers
$('.data-tables').delegate('table', 'click', function(event) {
$this = $(this)
$this.addClass('active').removeClass('inactive')
$this.siblings().addClass('inactive').removeClass('active')
});
This function does the following:
Add class active and remove inactive (if exists) to the selected item/table
Remove the class active and add class inactive from all adjacent tables
In this way you will only have one active table at the time
Then declare your button handler
$("#tst").click(function(){
var value = $('.active').html()
// Use the value as you want
})
This code will work no matter how many tables you add to the div
You're setting the class name of the element after the condition statement. Hence, the first time, your flag variable is undefined.
Try putting it in the beginning of the highlight function.
function highlight(e) {
e.target.parentNode.className = 'selected';
if (selected[0]){
selected[0].className = '';
flag='1';
}
else if (selected2[0]){
selected2[0].className = '';
flag='0';
}
alert(flag);
}
JsFiddle: https://jsfiddle.net/gwg639Lf/10/
Edit:
Add it before and after the condition. Adding it before the condition gives you the class name to initialize the flag variable. Adding it after gives the formatting bar.
JsFiddle: https://jsfiddle.net/gwg639Lf/13/
Ok, after some tests on Kostas Pelelis functions, i found a solution that is valid for my problem.
here is the code of JS:
var flag;
$("#data-table tr").click(function(){
$("#data-table-aux tr").addClass('selected').siblings().removeClass('selected');
$(this).addClass('selected').siblings().removeClass('selected');
flag='1';
});
$("#data-table-aux tr").click(function(){
$("#data-table tr").addClass('selected').siblings().removeClass('selected');
$(this).addClass('selected').siblings().removeClass('selected');
flag='0';
});
$('#tst').on('click', function(e){
if (flag=='1')
alert($("#data-table tr.selected td:first").html());
else if (flag=='0')
alert($("#data-table-aux tr.selected td:first").html());
});
Here is the fiddle --> fiddle
Thank you all for the help ;)
EDIT: I cleaned up the code a bit and narrowed down the problem.
So I'm working on a Wordpress site, and I'm trying to incorporate drop-downs into my menu on mobile, which means I have to use jQuery to assign classes and id's to my already existing elements. I have this code that already works on premade HTML, but fails on dynamically created id's.
Here is the code:
...
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
$(document).on('click', '.dropdown-title', function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
//THIS LINE FAILS
$(currentAttrValue).slideDown(300).addClass('d-open');
}
e.preventDefault();
});
I've registered the elements with the class dropdown-title using $(document).on(...) but I can't figure out what I need to do to register the elements with the custom ID's. I've tried putting the event callback inside the .each functions, I've tried making custom events to trigger, but none of them will get the 2nd to last line of code to trigger. There's no errors in the console, and when I console log the selector I get this:
[ul#m0.sub-menu.dropdown-content, context: document, selector: "#m0"]
0
:
ul#m0.sub-menu.dropdown-content
context
:
document
length
:
1
selector
:
"#m0"
proto
:
Object[0]
So jQuery knows the element is there, I just can't figure out how to register it...or maybe it's something I'm not thinking of, I don't know.
If you are creating your elements dynamically, you should be assigning the .on 'click' after creating those elements. Just declare the 'on click' callback code you posted after adding the ids and classes instead of when the page loads, so it gets attached to the elements with .dropdown-title class.
Check this jsFiddle: https://jsfiddle.net/6zayouxc/
EDIT: Your edited JS code works... There also might be some problem with your HTML or CSS, are you hiding your submenus? Make sure you are not making them transparent.
You're trying to call a function for a attribute, instead of the element. You probably want $(this).slideDown(300).addClass('d-active'); (also then you don't need $(this).addClass('d-active'); before)
Inside submenus.each loop add your callback listener.
As you are adding the class dropdown-title dynamically, it was not available at dom loading time, that is why event listener was not attached with those elemnts.
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
// add callback here
$(this).click( function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
$(currentAttrValue).slideDown(300).addClass('d-active');
}
e.preventDefault();
});
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
Turns out my problem is that jQuery is adding to both the mobile menu and the desktop menu, where the desktop menu is being loaded first when I search for that ID that's the one that jQuery finds. So it turns out I was completely wrong about my suspicions.
as you can see here jsfiddle.net/TTU4Z/1/
The jquery code in question is below and if i run it without all my code (like in jsfiddle) it run perfectly. but with all my code doesn't run.
$(document).ready(function() {
// This button will increment the value
$('.plus').click(function(e){
// Stop acting like a button
e.preventDefault();
// Get the field name
fieldName = $(this).attr('field');
// Get its current value
var currentVal = parseInt($('input[id='+fieldName+']').val());
// If is not undefined
if (!isNaN(currentVal)) {
// Increment
$('input[id='+fieldName+']').val(currentVal + 1);
} else {
// Otherwise put a 0 there
$('input[id='+fieldName+']').val(0);
}
});
// This button will decrement the value till 1
$(".minus").click(function(e) {
// Stop acting like a button
e.preventDefault();
// Get the field name
fieldName = $(this).attr('field');
// Get its current value
var currentVal = parseInt($('input[id='+fieldName+']').val());
// If it isn't undefined or its greater than 0
if (!isNaN(currentVal) && currentVal > 0) {
// Decrement one
$('input[id='+fieldName+']').val(currentVal - 1);
} else {
// Otherwise put a 0 there
$('input[id='+fieldName+']').val(0);
}
});
});
Clicking on "add" button all is good, but when you click in one of minus or plus button it delete all.
It should increase or decrease the val of the relative input as you can see, but nothing change if i try to edit everything in those functions.
What to do?
Since you are appending elements dynamically you have to use event delegation in this situation. Actually the registered events are not invoking in your context, that's why the buttons are exhibiting their original behavior.
Try,
$(document).on('click','.plus',function(e){
and
$(document).on('click','.minus',function(e){
Additionally, the selector that you are framing dynamically contains some meta-characters, just pass that as a string or you have to escape it, in order to make your code work properly.
DEMO
New Demo after fixing your concatenation issues. And in that demo, i just removed the attribute selectors like [id='blah'] and replaced that with $('#blah').
DEMO - I
See updated fiddle http://jsfiddle.net/LfNmh/
You had your x variable inside the code string where it should have been in the code. line 15 ..
var numPortata = '<td><button class="minus" field="portata'+x+'">-</button><input id="portata'+x+'" type="number" name="numPortata[]" value="1" size="10" min="1" max="10" step="1" required><button class="plus" field="portata'+x+'">+</button></td>';
I also changed the code so that the events are attached at the document level as Rajaprabhu said.
I'm trying to figure out the following.
I have following jQuery code:
var as = "";
var bPlay = 0;
audiojs.events.ready(function() {
as = audiojs.createAll();
$(".audiojs .play-pause").click(function() {
var e = $(this).parents(".audiojs").index(".audiojs");
$.each(as, function(t, n) {
if (t != e && as[t].playing) {
as[t].pause()
}
})
bPlay = !bPlay;
if (bPlay == 1) {
$(".bar").each(function(i) {
fluctuate($(this));
});
} else {
$(".bar").stop();
}
})
});
In a nutshell it preforms list of things when someone clicks particular .audiojs instance on a page. 1) checks if there is any other instance playing, if there is pauses it. And if it is playing applies fluctuate function to elements on a page that have class="bar". This is the issue! I don't want to apply it to all .bar's on a page, but only to a specific group that is associated with particular .audiojs instance (the one that is being clicked and is playing).
I thought of the following solution. Each .audiojs instance is inside a div tag that has id like "post-1", "post-2" etc.. where numerical value is post id from database. I can add this numerical id to bar, so it would be like bar-1, bar-2 etc... However after this I'm having issues.
For javascript to work I need to retrieve numerical value from "post-[id]" associated with audiojs instance that is being clicked and than store it somehow, so I can use it like this afterwards
bPlay = !bPlay;
if (bPlay == 1) {
$(".bar-[value retrieved from post-...]").each(function(i) {
fluctuate($(this));
});
} else {
$(".bar-[value retrieved from post...]").stop();
}
Could someone explain to me how it can be achieved?
Honestly, the easiest way would be to stick it in a custom data-* attribute on the <div id="post-X"> element, like so:
<div id="post-1" data-bar="bar-1">...</div>
Then, you said your .audiojs element is inside that <div>, so just go from this inside the event handler to that <div> element (using .closest()) and get the value of it:
var barId = $(this).closest('[id^="post-"]').attr('data-bar');
Then when you need to use it:
$("." + barId).each(function(i) {
fluctuate($(this));
});
Instead of embedding the value in a class or ID, use a data-* attribute:
<div class="audiojs" data-fluctuate-target="bar-1">
<button type="button" class="play-pause">
<!-- ... -->
</button>
</div>
<div class="bar-1">
<!-- ... -->
</div>
In your click event handler, use the following to fluctuate or stop the correct elements:
var fluctuateClass = $(this).closest('.audiojs').attr('data-fluctuate-target');
$('.' + fluctuateClass).each(function () {
if (bPlay == 1) {
fluctuate($(this));
} else {
$(this).stop();
}
});
I swear I'm going to learn more JavaScript...
I have this page (which really an include file in another ASP page, but I copied the correct HTML and made it so it'd load by itself for my testing purposes):
FO Samples
This is how it should show when they first load it. If they choose one of the other radio buttons, it should HIDE the 2 dropdown boxes. Using this code (something I found from someone else's question on here), its working.
<script type="text/javascript">
function ChangeDropdowns(value) {
if (value == "0") {
document.getElementById('SAMPLEDROPDOWN').style.display = 'block';
}
else {
document.getElementById('SAMPLEDROPDOWN').style.display = 'none';
}
}
</script>
But I can't figure out how to make it show them again if they go back to the "I wanna pick my own!" radio. The value of SAMPGROUP is the ID from the database of that sample category group. So it won't necessarily be in numerical order, it might skip #'s (if we delete a category or something). Basically, it should show the dropdowns if SAMPGROUP = 0 and not if its anything else!
I tried changing my code to this (95 being the value of SAMPGROUP for the "Autumm" option), but it doesn't seem to have made a difference.
<script type="text/javascript">
function ChangeDropdowns(value) {
if (value == "0") {
document.getElementById('SAMPLEDROPDOWN').style.display = 'block';
} else if (value == "95") {
document.getElementById('SAMPLEDROPDOWN').style.display = 'none';
}
else {
document.getElementById('SAMPLEDROPDOWN').style.display = 'none';
}
}
</script>
Any help would be greatly appreciated!!
Mahalo!
You are not setting the "value" in your onchange event, thus it's never equal to 0. Try changing this:
<input type="radio" name="SAMPGROUP" value="0" OnChange="Javascript:ChangeDropdowns()" checked />
to
<input type="radio" name="SAMPGROUP" value="0" OnChange="Javascript:ChangeDropdowns(0)" checked />
Here is the fiddle.
Good luck.
You may not be passing any value to the parameter "value" on calling the function ChangeDropdowns. Please ensure you pass the value like ChangeDropdowns(0) etc..