Best way to assign the same function to buttons in JS? - javascript

I wanted to know how I can optimize my current code.
I use buttons which are generated when an item is created it increases/decreases its value in a table. The button is pushed into an array this array iterates through all buttons in this array and give them a function based on their id.
var increaseButtonArray = [];
var increaseButton = 'increaseButton' + obj.id;
$('#d' + i + 'Content').append('<tr>' +
'<td><button type="button" id="' + increaseButton + '">...
increaseButtonArray.push(increaseButton);
Because I use 4 button for each element I can't just give the button the id of the element I instead make "the name of the button" + the id of the element.
function increaseButtonFunction() {
$.each(increaseButtonArray, function (index, obj) {
$("#" + obj).click(function btnClick() {
var x = obj.substring(14, 17);
$.each(list.List, function (k, v) {
$.each(v, function (index, obj2) {
if (obj2.id == x) {
obj2.value = obj2.value+ 1;
}
});
});
drawRow();
});
})
}
To find the button I use substring(I know that is bad practice) but my code currently works and the application only uses <40 elements.
What is a cleaner solution for this?
UPDATE
Working Snippet
https://jsfiddle.net/9vh2ebqk/

I had make a more flexible version of inc and dec button.
`
https://jsfiddle.net/pm01z4of/
`
Don't understand what should exactly happen with set and delete but anyway I hope it helps you.

Related

Linked "Combos" not working correctly

Fiddle: https://jsfiddle.net/Mrbaseball34/kuj2cz5g/
In the code, I call GetYears to fill a <ul> with data. When a year is clicked on, it is supposed to append the selected year to the text of the flyout then load the makes <ul>
But, what is happening is it is "looping" through the years and calling yearClick for each year in the list after the that is clicked. Yes, it fills the makes <ul> but then begins looping yearClick() again.
Can anyone help out here? I can't see the forest for the trees, I guess...;-)
var year;
var make;
var model;
var ic;
GetYears();
$("#year-flyout").css("top", $(".m-assisted-decode").position().top);
$("#make-flyout").css("top", $(".m-assisted-decode").position().top + 40).hide();
$("#model-flyout").css("top", $(".m-assisted-decode").position().top + 75).hide();
$("#parts-flyout").css("top", $(".m-assisted-decode").position().top + 112).hide();
function GetYears() {
var data =
[{"year":"2017"},{"year":"2016"},{"year":"2015"},{"year":"2014"},{"year":"2013"},{"year":"2012"},{"year":"2011"},{"year":"2010"},{"year":"2009"}];
$.each(data, function(i, item) {
$("#years").append("<li class=\"year\">" + item.year + "</li>");
$(".year").on("click", yearClick);
});
$("#fa_year").hide();
$("#year-flyout").show();
}
function yearClick(event) {
year = $(this).text();
$("#year_value").attr("placeholder", $("#year_value").attr("placeholder") + ":" + year);
$("#year-flyout").hide();
// Get the Makes and populate the Makes Flyout
GetMakes();
}
function GetMakes() {
var data =
[{"make":"ACURA"},{"make":"AUDI"},{"make":"BMW"},{"make":"BUICK"},{"make":"CADILLAC"},{"make":"CHEVROLET"},{"make":"CHRYSLER"},{"make":"DODGE"},{"make":"FORD"},{"make":"GMC"},{"make":"HONDA"},{"make":"HUMMER"},{"make":"HYUNDAI"},{"make":"INFINITI"},{"make":"JAGUAR"},{"make":"JEEP"},{"make":"KIA"},{"make":"LAND ROVER"},{"make":"LEXUS"},{"make":"LINCOLN"},{"make":"MAZDA"},{"make":"MERCEDES-BENZ"},{"make":"MERCURY"},{"make":"MINI"},{"make":"NISSAN\/DATSUN"},{"make":"PONTIAC"},{"make":"PORSCHE"},{"make":"RAM"},{"make":"SAAB"},{"make":"SATURN"},{"make":"SCION"},{"make":"SMART"},{"make":"SUBARU"},{"make":"SUZUKI"},{"make":"TOYOTA"},{"make":"VOLKSWAGEN"},{"make":"VOLVO"}];
$.each(data, function(i, item) {
$("#makes").append("<li class=\"make\">" + item.make + "</li>");
$(".make").on("click", makeClick);
});
$("#make-flyout").show();
}
function makeClick(event) {
make = $(this).text();
$("#make_value").attr("placeholder", $("#make_value").attr("placeholder") + ":" + make);
$("#make-flyout").hide();
// Get the Models and populate the Models Flyout
// GetModels();
}
There's no need to attach the event listener after each added <li> since you're using the class. Just move it out of the each loop
$.each(data, function(i, item) {
$("#years").append("<li class=\"year\">" + item.year + "</li>");
});
$(".year").on("click", yearClick);
If you inspect your year element in Chrome inspector, you can see all the attached events on click, and see that it was firing the same event several times.

Duck Punching / Monkey Patching breaks Tablesorter

I have a textbox that comma separated/delimited values are entered into which I have to make sure has unique entries. Solved that using Paul Irish's Duck Punching example #2 and tying it to onblur for that textbox.
The values entered into the textbox get broken out into a table. As the table can get very lengthy, I found Mottie's Tablesorter to work brilliantly.
The problem is, the the Duck Punching code is breaking the Tablesorter. The style for the Tablesorter is passed through just fine, but the table doesn't actually sort. BUT, when I comment out the Duck Punching code, Tablesorter miraculosly works.
My coding skills are not such that I can figure out why the two are conflicting. Any assistance would be much appreciated.
I haven't modified the Tablesorter code or added any special sorting elements to it...just following the very basic example right now. Here's the Duck Punching code which I've only modified to include the var for the textbox I need to have unique entries.
function ValidateTextBox1()
{
(function($){
var arr = document.getElementById("TextBox1").value.split(',');
var _old = $.unique;
$.unique = function(arr){
// do the default behavior only if we got an array of elements
if (!!arr[0].nodeType){
return _old.apply(this,arguments);
} else {
// reduce the array to contain no dupes via grep/inArray
return $.grep(arr,function(v,k){
return $.inArray(v,arr) === k;
});
}
};
})(jQuery);
}
The function above is in a separate js file which is called via onblur for TextBox1.
Then, I have a button which runs the following:
function GenerateTable()
{
var Entry1 = document.getElementById("TextBox1").value
var Entry2 = document.getElementById("TextBox2").value
var content = "<table id=myTable class=tablesorter ><thead><tr><th>Entry 1 Values</th><th>Entry 2 Value</th></tr></thead><tbody>"
var lines = Entry1.split(","),
i;
for (i = 0; i < lines.length; i++)
content += "<tr><td>" + (Entry1.split(",")[i]) + "</td><td>" + Entry2 + "</td></tr>";
content += "</tbody></table>"
$("#here_table").append(content);
$(function(){
$("#myTable").tablesorter({
theme: 'default'
});
});
}
The function will generate/append the table in a specific DIV.
If I leave in the validation code for TextBox1, the table will generate but isn't sortable (though it does manage to still pull the theme).
If I remove the validation code, the table will generate and is sortable.
The validateText box function above will not work as expected. In this case, "duck-punching" is not even necessary.
Here is how I would fix the script (demo):
HTML
<textarea id="textbox1">6,1,7,5,3,4,3,2,4</textarea><br>
<textarea id="textbox2">column 2</textarea><br>
<button>Build Table</button>
<div id="here_table"></div>
Script (requires jQuery 1.7+)
(function($) {
// bind to button
$(function () {
$('button').on('click', function () {
// disable button to prevent multiple updates
$(this).prop('disabled', true);
generateTable();
});
});
function unique(arr) {
return $.grep(arr, function (v, k) {
return $.inArray(v, arr) === k;
});
}
function generateTable() {
var i,
$wrap = $('#here_table'),
// get text box value, remove unwanted
// spaces/tabs/carriage returns & create an array
val = $('#textbox1').val().split(/\s*,\s*/),
// get unique values for Entry1
entry1 = unique( val ),
entry2 = $('#textbox2').val(),
content = "";
// build tbody rows
for (i = 0; i < entry1.length; i++) {
content += "<tr><td>" + (entry1[i] || '?') + "</td><td>" + entry2 + "</td></tr>";
}
// update or create table
if ($wrap.find('table').length) {
// table exists, just update the data
$wrap.find('tbody').remove();
$wrap.find('table')
.append(content)
.trigger('update');
} else {
// table doesn't exist, build it from scratch
$wrap
.html('<table id=myTable class=tablesorter><thead><tr>' +
'<th>Entry 1 Values</th>' +
'<th>Entry 2 Value</th>' +
'</tr></thead><tbody>' + content + '</tbody></table>')
.find('table')
.tablesorter({
theme: 'blue'
});
}
// enable the button to allow updating the table
$('button').prop('disabled', false);
}
})(jQuery);
I tried to add a few comments to make more clear what each step is doing. Please feel free to ask for any clarification.

How To Loop Through Set Of Value Pairs JSON Object

im trying to loop through a JSON object via Jquery. For some reason its not looping right.. It seems to be looping all the way to the end, But I would like to get each individually property in my object. Im using a For(var in) loop which loops through my object correctly but its a bit off.. MyAny help would be glady appreciated.. thanks so much!!! I can provide a quick link to my website that has mock up of the code if needed..
Ive also added more code and html via elements that using ..Hint*** Theres more if - conditional statements that checks for sounds_like,sounds_price... The first JSON Object works with no problem, its the second JSON object that im using with the pop over thats causing me trouble
<div class="overlay-bg">
<div id= "overlay" class="overlay-content">
<p>This is a popup!</p>
<button class="close-btn">Close</button>
</div>
</div>
$.getJSON("php/music_data.php",function(data){
$.each(data,function(key,obj){
for(var prop in obj){
// console.log("Property: " + prop + " key:" + obj[prop]);
if(prop === "sounds_like"){
results_div = document.getElementById("results");
music_div_container = document.createElement("div");
music_div_container.id = "music_data_container";
music_div_container.innerHTML = "<div id=\"sounds_like\">" + "Sounds Like: " + obj["sounds_like"] +"</div>";
results_div.appendChild(music_div_container);
var pop_up = document.createElement("a");
pop_up.href = "#";
pop_up.className = "show-popup";
pop_up.innerHTML = "Click";
music_div_container.appendChild(pop_up);
default_photo = document.createElement('div');
}
if(prop === "sound_desc"){
var sound_desc = document.createElement("div");
sound_desc.innerHTML = "<div id=\"sounds_desc\">" + obj["sound_desc"] +"</div>";
music_div_container.appendChild(sound_desc);
}
$.getJSON("php/music_data.php",function(data){
$.each(data,function(idx,obj){
$.each(obj,function(key,value){
$(".show-popup").click(function(event){
event.preventDefault();
$(".overlay-bg").show();
if(key === "sounds_like"){
/***Should be Beyonce,Drake,Nicki Minaj***/
/*****But my console is showing Nicki Minaj*******/
$(".overlay-content").html(value);
}
if(value === "sounds_desc"){
/***Should be Smooth, Wu tang Forever, Barbie***/
/*****But my console is showing Barbie*******/
$(".overlay-content").html(value);
}
$('.close-btn').click(function(){
$('.overlay-bg').hide(); /*** hide the overlay ***/
});
$('.overlay-bg').click(function(){
$('.overlay-bg').hide();
});
$('.overlay-bg').click(function(){
return false;
})
});
});
})
});
JSON Object Below
[{"id":"39","sounds_like":"Beyonce","sound_name":"Dance 4 u.mp3","sound_desc":"Smooth","sound_genre":"R&B","sound_price":"N/A","photo_path":"\/admin_data\/uploaded_artist_photos\/","photo_name":"beyonce.jpg"},
{"id":"40","sounds_like":"Drake","sound_name":"Bottom.mp3","sound_desc":"Wu Tang Forever","sound_genre":"Rap","sound_price":"N/A","photo_path":"\/admin_data\/uploaded_artist_photos\/","photo_name":"drake.jpg"},
{"id":"41","sounds_like":"Nicki Minaj","sound_name":"RomanReloaded.mp3","sound_desc":"Barbie","sound_genre":"Rap","sound_price":"N/A","photo_path":"\/admin_data\/uploaded_artist_photos\/","photo_name":"nickiminaj.jpg"}
]
When you loop a complex object using a for var in loop, you will always have unexpected behaviors because of how this loop works.
To avoid such problems and if you need to use this type of loop, I recommend you do the following:
Example:
for (var i in obj) {
if (obj.hasOwnProperty(i)) { // this validates if prop belongs to obj
// do something
}
}
EDIT 1:
I'm not sure what you're trying to do but using jquery you can do the following:
$.getJSON("php/music_data.php", function (data) {
$.each(data, function (i, value) {
//alert(i + ": " + value.id);
alert(value.sounds_like);
// this will have Beyonce , Drake, Nicki Minaj
});
});
Another thing that does not seem right is that you're doing bind click event on each loop. Is it better to do this differently.

JavaScript For loop appending 4 times

I have a JavaScript program that isn't properly functioning. For some reasons before it appends what it is actually getting from the checked radio box it appends three times with noting in the append except the styling. I'm not sure what I'm doing wrong.
$(document).delegate('#add-owner', 'pageinit', function () {
loadOwners();
$('#add-owner-save').bind('click', function () {
var permission = $('#editing-permissions option:selected').text();
var selection = $("input[type='radio']:checked") || [];
if (selection.length > 0) {
for (var i = 0; i < selection.length; i++) {
console.log($('#label-' + selection[i].id).find('.owner-name').text());
console.log($("input[type='radio']:checked").val());
$('.display-owners').append('<div class="ui-grid-a"><div class="ui-block-a">' + $('#label-' + selection[i].id).find('.owner-name').text() + '</div><div class="ui-block-b" style="text-align:right">' + permission + '</div></div>');
}
$('.display-owners').trigger('create');
}
$('.display-owners').show();
$('#add-owner').dialog('close');
$('input[name=contribute-radio]').attr('checked', false).checkboxradio("refresh");
return false;
});
});
I think the problem is that I have multiple radio areas on this page. How do I specify that I just want these radio buttons are the ones I want it to checked?
This code:
... + $('#label-' + selection[i].id).find('...
should be like this:
... + $('#label-' + selection[i].attr('id')).find('...
because what you have in selection array are jQuery objects, not DOM elements objects.
Thanks Esalija for pointing out my assumption was not correct.
Since said you have multiple sets of radio buttons, the selector you're using is finding all of them on the page so that is why you have multiple "checked" radio buttons.
This:
var selection = $("input[type='radio']:checked") || [];
To this:
var selection = $("input[name='radioset1']:checked") || [];
Then just name each radio set different and replace "radioset1" with the set you need for this one.

Javascript Weird - I'm clueless

I'm working on this menu-system that's very similar to how operating systems do them.
Using jquery etc.
I have 2 comments down in the For Loop. It's basically outputting the last index each in the $(document).on('click')... function. But outside the document.on it works fine.
It's probably just an obvious problem but I've spent about an hour on this.. Thanks in advance!
menu: function(title) {
this.title = title;
this.slug = slugify(title);
this.icon = false;
this.buttons = Object();
this.num_buttons = 0;
this.visible = false;
this.timeout_id = null;
this.is_hovering_dropdown = false;
this.is_hovering_menu = false;
this.render = function() {
var that = this;
var slug = that.slug;
var str = '<li id="menu-' +slug +'">' + this.title + '';
if (this.num_buttons > 0) {
str += '<ul id="menu-dropdown-' + slug + '" style="display: none;" class="dropdown">';
for (var button in this.buttons) {
str += '<li>' +that.buttons[button]['title'] +'</li>'
alert(button) //new project, open project, save as etc.
$(document).on("click", "#menu-dropdown-" +slug + '-' + that.buttons[button]['slug'], function() {
$("#menu-dropdown-" + slug).hide("fade", 200);
that.visible = false;
alert(button);//save as, save as, save as, save as etc.
});
}
}
}
}
Here you go:
Thanks to the order of operations, and scoping, all of your buttons are being saved with a reference to the LAST value of button.
What you want to do is put that assignment inside of an immediately-invoking function, and pass the button into that particular function-scope.
(function (button) { $(document). //...... }(button));
Everything inside of the immediate function should still have access to the static stuff outside of the immediate-function's scope (ie: that), AND it will also have a reference to the current value of button, as it's being invoked then and there.
The longer version of the story is that your buttons, when being created are being given a reference to button, rather than the value of button, therefore, when they're actually invoked at a later time, they reference the value of button as it currently exists (ie: the last value it was assigned in the loop).

Categories