Onclick multiple function calls issue, also sending previous click data - javascript

I have a problem with duplicate calls being sent onclick of a link, which includes the previous call data if they were made.
Here is the construction of the link in question.
for (var key in res) {
var followers = res[key].followers;
var totalposts = res[key].totalposts;
var id = res[key].id;
var name = res[key].name;
var titles = "";
titles = '<ul class="titles">';
if (typeof res[key].titles === "object") {
for (var index in res[key].titles) {
var url = res[key].titles[index].st_url;
titles += '<li><div class="ui grid"><div class="ui fourteen wide column">\u2022 '+url+'</div><div class="ui two wide column"><a title"Remove this post" href="#" onclick="showRemPost('+id+', \''+url+'\', \''+name+'\')" id="remPostButton"><i class="ui remove grey circle icon"></i></a></div></div></li>';
}
}
titles += "</ul>";
html +=
'<div class="ui eight wide column"><div class="ui segment" data-id="' + id + '" id="list' + id + '">' +
'<div class="listTitle"><h4 class="left">' + name + '</h4><div class="right"><i class="edit icon"></i> <i class="remove icon"></i></div><div class="clear"></div></div>' +
'<div>' + titles +
'</div>' +
'<div class="footList"><div class="left"><p>Followers: <span class="follow">'+followers+'</span>' +
'<br/>Posts: <span class="post">'+totalposts+'</span>' +
/*'<br/>Upvotes: <span class="upvote">'+res[key].upvotes+'</span>' + */
'</p></div>' +
'<div class="right"><i class="ui add blue circle icon"></i></div></div><div class="clear"></div>' +
'</div></div>';
}
Then I have this code for the function call:
showAddPost = function(id, lname){
//do stuff
console.log("\nshowAddPost function called");
}
console.log("\nshowAddPost function called"); is showing 1 time on first click, then 2x on second click, and so on. Each time, I get the data from the previous click.
Since there are multiple links to click, any link clicked after another, will send all previous clicks and their data, as events to the showAddPost.
Ex: 1st click has "ID": "1" and "name": "One". These are sent. On the second link and second click, "ID": "2" and "name": "Two", which should only call once, and send only the Two data, but it sends the previous data, "1:One" to the function call showAddPost, then it send a second call to showAddPost for the actual link clicked with "2:Two". And the if I click on a third link, the same or different, it send the previous two data to the function.
Is the only way to resolve this by moving the onclick from the HTML to it's own .on() handler and then getting the data through data- attributes? Or can I get the data passed in an easier way with the .on() handler? Can I still use onclick and resolve this problem?
All of this is in a separate namespace, not global scope.
Thank you anyone for any help.

You are most likely not closing the a tags.
So you end up with
<a href="#" onclick="showAddPost('+id+', \''+name+'\')" class="addPostButton">
<a href="#" onclick="showAddPost('+id+', \''+name+'\')" class="addPostButton">
...
Nesting a tags is invalid. The issue in your case is that the inner a tags will trigger all the previous since the click event bubbles upwards.
update after updated code and comment
Actually yes, the line
'<div class="right"><i class="ui add blue circle icon"></i></div></div><div class="clear"></div>' +
has wrong matching on opening/closing tags. Lets break it down to see
<div class="right">
<a href="#" onclick="showAddPost('+id+', \''+name+'\')" class="addPostButton">
<i class="ui add blue circle icon"></i>
</div> <!-- << this here does not match a div, it should be an a -->
</div>
<div class="clear">
</a> <!-- << this here probably belong on the previous group -->
</div>

Related

.click get a piece of json to appear inside an alert

So I have a get json function that makes items appear on my page, there is a button with json included inside of it that when is clicked I want the item to appear inside an alert (its called cart) - its going to be a simple shopping cart that is hidden on page ready/load. So when the user clicks this button parts of my json file appear inside of the alert, like a shopping cart, If there can be a total to calculate the price this would be good but is not necessary.
So this is my script to get the json and display it on my page :
$.getJSON('iproducts.json',function(products){
var output = "";
$.each(products.appleitems, function(i, product) {
output +=
"<div class=\"col-xs-12 col-sm-6 col-md-3\"><div class='panel panel-default'><div class='panel-footer'><h4 class='text-center'>"
+ products.appleitems[i].Product_id
+ "</h4></div>" + "<img src ='" + products.appleitems[i].Imgpath + "' style='width:100%;height:250px; display: block;' id='appleinfo_"
+ products.appleitems[i].Product_id +
"' /><p class='lead text-justify'>" + products.appleitems[i].Information
+ "</p><div class='panel-footer'><button class='btn btn-primary btn-block' id='btncart'>£" + products.appleitems[i].Price+"</button></div></div></div>";
});
$("#container").html(output);
});
as you will notice this is the button I am talking about:
<div class='panel-footer'><button class='btn btn-primary btn-block' id='btncart'>£" + products.appleitems[i].Price+"</button></div>
the price is displayed inside of the button.
This is a snip (one of the products, there are about 12 products in total) from my json file:
{
"appleitems":[
{
"Product_id":"Iphone5",
"Information":"Iphone 5 64GB",
"Imgpath":"image/iphone5.jpg",
"Price":"200.00"
}
]
}
This is the alert I want the name and price to display in when the button is clicked:
<div class="alert alert-warning" id="cart"></div>
Here is a bit of a clue from a previous script I worked on, when the user entered their name/ login details (from the json) and they matched their name, picture and details would appear in the welcome alert, I also had a hide button inside this alert that then hid the welcome alert and this is how I got it to work ( could be quite similar to this only .show():
$(document).ready(function() {
//Hide alert when page loads
$("#loginalert").hide();
$("#invalid").hide();
$("#loginbtn").click(function(event){
$.getJSON('result.json', function(jd) {
var id = $('#userName').val();
var name = $('#userName2').val();
var valid = false;
$('#loginalert').html('<img src="' + jd.user[i].imgpath + '"><br><p> Welcome: ' + jd.user[i].name + '</p><button type="button" id="btnhide" class="btn btn-primary btn-md">Hide</button>');
//show the alert after loading the information
$("#loginalert").stop().fadeIn('slow').animate({ opacity: 1.0 }, 3000)
$('#invalid').hide();
$('#btnhide').on('click', function(e){
e.preventDefault();
$('#loginalert').hide();
});
}
}
if (!valid) {
$('#invalid').fadeIn('slow');
$('#loginalert').hide();
Kind Regards
So on button click you want to update the alert div with it's price.
Here is a code block explaining things you need.
According to this html
$('.btn-block').click(function(e){
//alert($(this).attr("value")); //get value of button
$("#cart").empty(); //clear div every time on click
$("#cart").html($(this).attr("value")); //this will update div with value of button.
var product_information = $(this).closest("div").prev("p").html();//This will get you product info
});
I have added some explanation as comment.This are self explanatory.
Important
I notice you assign hardcore id in each loop in button which is not correct.You should always assign dynamic id as id cannot be same.

.click add a piece of json into a panel

Ive been desperately trying to get this to work.
Iknow there are probably better ways to do this other than the way I am trying but its for an assignment and has to be done this way.
I am creating a simple shopping cart/ the cart does not have to add a total just get the items inside of the panel (if anyone knew how to add the price also that would be brilliant but not 100% necessary)
So I have displayed items of json using json and ajax, on page ready the items are on show as so (there are about 12 items):
so I have the panel hidden, when the user clicks on a button (the blue button) I want the json information and the json price to appear inside the panel.
here is a snip of one of the items from my json file (which is called result.json:
{
"appleitems":[
{
"Product_id":"Iphone5",
"Information":"Iphone 5 64GB",
"Imgpath":"image/iphone5.jpg",
"Price":"200.00"
}
]
}
This ishow my items are displayed:
$.getJSON('iproducts.json',function(products){
var output = "";
$.each(products.appleitems, function(i, product) {
output +=
"<div class=\"col-xs-12 col-sm-6 col-md-3\"><div class='panel panel-default'><div class='panel-footer'><h4 class='text-center'>"
+ products.appleitems[i].Product_id
+ "</h4></div>" + "<img src ='" + products.appleitems[i].Imgpath + "' style='width:100%;height:250px; display: block;' id='appleinfo_"
+ products.appleitems[i].Product_id + "' /><h5 class='text-center'>" + products.appleitems[i].Information
+ "</h5><div class='panel-footer'>`<button class='btn btn-primary btn-block' id='btnadd'>£" + products.appleitems[i].Price+"</button>`</div></div></div>";
});
$("#container").html(output);
});
and you will notice the button that I want clicked to display the json is btnadd:
<button class='btn btn-primary btn-block' id='btnadd'>£" + products.appleitems[i].Price+"</button>
so when the user clicks btn add I want the json "information" and "price" to display inside of the pannel cart:
<div class="panel panel-default">
<div class="panel-body" id="cart"></div>
I have started the script for this:
$(document).ready(function() {
//Hide alert when page loads
$("#cart").hide();
//get the item into the panel
$("#btnadd").click(function(event){
$.getJSON('result.json', function(add) {
...
});
});
});
First of all, You are having same Id value for all the buttons(inside the loop). Duplicate Id's are not valid. So may be you can remove that and add a css class to the button for the jQuery selection. Also i would recommend keeping the price and information in HTML5 data attributes on the button for easier read.
var output ="";
$.each(products.appleitems, function(i, product) {
output += "<div><div>"
output +="<button class='btn btn-primary btn-block addBtn' data-info='"+
product.Price +"' data-price='"+
product.Information +"'>£" + product.Price+"</button>";
output +="</div></div>";
});
And listen to the click event on this specific css class
$(function(){
$(document).on("click",".addBtn",function(e){
e.preventDefault();
var _this=$(this);
var c=_this.data("info") + " " +_this.data("price");
$("#cart").html(c);
});
});
Here is a working sample

clearing input text area with dynamic input id's on button click - jQuery

Although the question title gives an impression that I want to ask one question, but there are two problems I have facing at the moment.
I have gone through few similar questions on how to clear the input text area on button click, but most of them are for fixed input class or id's.
Problem 1: I am generating rows dynamically and and all the fields are being populated using JS thus the input ID's for all text boxes are different. Now if a user enter some number on "Apply to all" input field and click the button the same number should be set to all the rows which are added in the betslip.
Problem 2: After entering individual values in the betslip input boxes and if I click "clear all" button. It should clear all the inputs entered earlier in the bet slip.
Here is the HTML structure
<div id="bets">
<div id="idNo1" class="bet gray2" name="singleBet">
<div class="left">
<p class="title">
<p class="supermid">
<input id="input_1" type="text">
</div>
</div>
<div id="idNo2" class="bet gray2" name="singleBet">
<div class="left">
<p class="title">
<p class="supermid">
<input id="input_2" type="text">
</div>
</div>
<div id="idNo3" class="bet gray2" name="singleBet">
<div class="left">
<p class="title">
<p class="supermid">
<input id="input_3" type="text">
</div>
</div>
</div>
JS for adding element in the individual bets
function createSingleBetDiv(betInfo) {
var id = betInfo.betType + '_' + betInfo.productId + '_' + betInfo.mpid,
div = createDiv(id + '_div', 'singleBet', 'bet gray2'),
a = createA(null, null, null, 'right orange'),
leftDiv = createDiv(null, null, 'left'),
closeDiv = createDiv(null, null, 'icon_shut_bet'),
singleBetNumber = ++document.getElementsByName('singleBet').length;
// Info abt the bet
$(leftDiv).append('<p class="title"><b><span class="bet_no">' + singleBetNumber + '</span>. ' + betInfo['horseName'] + '</b></p>');
var raceInfo = "";
$("#raceInfo").contents().filter(function () {
if (this.nodeType === 3) raceInfo = $(this).text() + ', ' + betInfo['betTypeName'] + ' (' + betInfo['value'].toFixed(2) + ')';
});
$(leftDiv).append('<p class="title">' + raceInfo + '</p>');
// Closing btn
(function(id) {
a.onclick=function() {
removeSingleBet(id + '_div');
};
})(id);
$(a).append(closeDiv);
// Creating input field - This is where I am creating the input fields
$(leftDiv).append('<p class="supermid"><input id="' + id + '_input\" type="text" class="betInput"></p>');
// Creating WIN / PLACE checkbox selection
$(leftDiv).append('<p><input id="' + id + '_checkbox\" type="checkbox"><b>' + winPlace + '</b></p>');
// Append left part
$(div).append(leftDiv);
// Append right part
$(div).append(a);
// Appending div with data
$.data(div, 'mapForBet', betInfo);
return div;
}
HTML for Apply to all and Clear all button
APPLY TO ALL <input type="text">
CLEAR ALL
JS where I need to implement those 2 functions
function applyToAllBetInput() {
$('.apply').change(function() {
$(this).prevAll().find('input[type=text]').val($(this).val());
});
}
function clearAllBetInput() {
$('.clearall').click(function() {
$('div.bet').find('input').val('');
});
}
The best thing to do is remove the inline event handlers from the links, like this...
APPLY TO ALL <input type="text">
CLEAR ALL
Then, assign the event handlers in your script...
$("a.button.apply").on("click", function(e) {
e.preventDefault();
applyToAllBetInput($(this).find("input").val());
});
$("a.button.clearall").on("click", function(e) {
e.preventDefault();
applyToAllBetInput("");
});
And this would apply the value to all inputs...
function applyToAllBetInput(value) {
$("#bets div[name=singleBet] .supermid input:text").val(value);
}
If you pass a parameter into applyToAllBetInput and then set the inputs with that then you only need the one function, as they both do the same thing, but with different values. Best to only have 1 bit of code if it's only doing 1 thing, then you only have to fix it once if things change in the future :)
Please replace the id's i've given with your actual button/textarea ids (give ID's to your elements).
$('#txtApplyToAll').change(function() {
$(this).prevAll().find('input[type=text]').val($(this).val());
});
$('#btnClearAll').click(function() {
$('#txtApplyToAll').prevAll().find('input[type=text].val('');
});
There are several general suggestions I'd make before even starting to write the code. First, Why are you using longhand JavaScript when you have jQuery available? For example:
inputId = divId.document.getElementById('input');
should be simply:
inputId = $(inputId).find('input');
(or something along those lines--I'm not sure what you're after with that.)
Next, you're using inline click handlers. Instead, use event listeners:
<a href="javascript: applyToAllBetInput()" ...
Should be
$('a#my-id').click(function() { ... }
Finally, you can target all your inputs for clearing with a selector like this:
$('div.bet').find('input').val('');

Sorting consistency of dynamically created IDs on DOM Elements

My application successfully creates elements and assigns them different (increasing) IDs.
Now my issue relies when the user deletes these elements (because they have the option to delete as well as create), the consistency of these IDs get broken therefore my application doesn't run well.
This Fiddle represents what I have so far. Just a textbox that appends its value and a few other elements inside a collapsible as many times as the user wants (For some reason my fiddle doesn't increment the alert value, but it works fine on my platform).
SCRIPT (Sorry the txt variable is too long)
$('#Add').click(function () {
if ($("#MedNameStren").val() != "") {
var value = $("#MedNameStren").val();
var noOfMeds = $('#NoOfMedicines').val();
//to check current value
alert(noOfMeds);
var text = '<div data-role="collapsible" data-collapsed="true" data-iconpos="left" data-content-theme="e">' + '<h2>' + desc + '</h2>' + '<div class="ui-grid-a">' + '<div class="ui-block-a" style="width:25%; margin-right:3%;">' + '<input id="quantity' + noOfMeds + '" class="quantity" type="text" placeholder="Quantity" />' + '</div>' + '<div class="ui-block-b" style="width:70%; margin-right:2%;"">' + '<textarea id="directions' + noOfMeds + '" class="directions" cols="40" rows="4" placeholder="Directions given by your GP." ></textarea>' + '</div>' + '</div>' + '<button key="' + vpid + '">Remove</button>' + '</div>';
$("#medListLi").append(text);
$('button').button();
$('#medListLi').find('div[data-role=collapsible]').collapsible();
$('#medListLi li').listview("refresh");
$('#medListLi').trigger("create");
document.getElementById("manuallyName").value = "";
noOfMeds++
$("#NoOfMedicines").val(noOfMeds);
}
else {
alert('Please Provide Medicine Name')
}
});
I am using a counter that neatly increments the ids of quantity and description like:
quantity0
quantity1
quantity2
..and so on, but once the following script is called...
//Deletes colapsible sets (Medicines) from the selected List
$('#medListLi').on('click', 'button', function (el) {
$(this).closest('div[data-role=collapsible]').remove();
var key = $(this).attr('key');
localStorage.removeItem(key);
var noOfMeds = $('#NoOfMedicines').val();
noOfMeds--
$("#NoOfMedicines").val(noOfMeds);
//location.reload();
});
depending on which element (collapsible) is deleted, the IDs stop being consistent. For example if the collapsible with id="quantity1" is deleted then the counter will go back to 1 (currently 2) and on the next addition the respective collapsible will get an id that's already taken, and unfortunately I don't need this to happen.
Maybe I'm making this sound more complicated that it is, but will appreciate any suggestions or ideas to solve this issue (if possible).
If more information is needed, please let me know.
Was brought to my attention that creating and deleting dynamic IDs can be done but keeping up with consistency of these IDs can be very tricky to work around it.
I've solved my own problem by simply creating a function that would keep count of the IDs from the amount of collapsibles inside my list and "renewing" the ID numbers on each Add and Delete.

Self written toc jQuery function: jump to link target and show corresponding element

I generate dynamically a toc for elements of class=faqQuestion.
The answer resides in a class=faqAnswer element which is hidden by default.
By clicking on class=faqQuestion entry it will show up with
$(this).next(".faqAnswer").slideToggle(300);
Everything works as expected.
What I want: by clicking on a toc link i will jump to the target faqQuestion element and show the corresponding faqAnweser element.
The way I generate the toc:
$(document).ready(function(){
var url = window.location.pathname;
$('<ol />').prependTo('#toc')
$(".faqQuestion").each(function(i) {
var current = $(this);
current.attr("id", "entry" + i);
$("#toc ol").append("<li class=\"faqToc\"><a id='link" + i + "' href='" + url + "#entry" +
i + "' entry='" + current.attr("tagName") + "'>" +
current.html() + "</a></li>");
});
This is what I tried, which will jump to the selected faqQuestion but the faqAnswer element is still hidden.
$(".faqToc").click(function(event){
$(this).next(".faqAnswer").slideToggle(300);
});
My problem is this - at least I think so - so I tried something like - which results in "undefined"
var url = $(this).prop("href");
alert(url);
Trying attr instead of prop returns also "undefined".
Can you point out my problem?
I'm trying to improve my Javascript and jQuery know how, so I don't want to use a toc-plugin.
Update: HTML looks like this:
<div id="toc">
<ol>
<li class="faqToc">
...
</li>
<li class="faqToc">
...
</li>
</div>
<p id="entry0" class="faqQuestion">...</p>
<div class="faqAnswer" style="display: none;">...</div>
<p id="entry1" class="faqQuestion">...</p>
<div class="faqAnswer" style="display: none;">...</div>
A very simple way would be to use the index() method since relationship between the TOC elements and the question/answer elements is 1 to 1.
$(".faqToc").click(function(event){
var index=$(this).index(); /* zero based index position of element within it's siblings*/
/* toggle answer element with same index */
$(".faqAnswer").eq(index).slideToggle(300);
});
jQuery API Reference : index()

Categories

Resources