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.
Related
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.
I wrote some code that generates a bunch of html-elements based on a Json-Object. I add it to the page by JQuerys .append() and .after().
It does work perfectly often, but sometimes the outer loop is only executed once and stops at $( '#'+inputname ).entityselector().
function addlinks(qid, prop) {
html="<fieldset id=\"quickpresets\">" +
"<legend>Quick Presets (" + prop.name + ")</legend></fieldset>";
$('.wikibase-statementgrouplistview').first().after( html );
for( var p = 0; p < prop.defaults.length; p++ ) {
pid=prop.defaults[p].pid;
pname=prop.defaults[p].name;
pvalues=prop.defaults[p].values;
inputname="input"+pname;
pclass="addstatement";
if($('#P'+pid).find(".wikibase-snakview-value a").length !== 0) {
pclass += " disabled";
}
str="<p class='"+pclass+"'>Add "+pname+":";
for( var i = 0; i < pvalues.length; i++) {
toqid=pvalues[i].qid;
toname=pvalues[i].name;
str += " <a href='javascript:void(0);' onclick=\""+
"additemstatement("+qid+","+pid+",'"+pname+"',"+ toqid +",'" + toname+ "')\">" + toname+ "</a>"+
" ∙";
}
str += "<span class=\"quickpresetsinput\"><input id='"+inputname+"'/> ";
str += "<a href=\'javascript:void(0);\' onclick=\""+
"onselectitem("+qid+","+pid+",'"+pname+"','"+ inputname +"')\">✔</a>";
str += "</span></p>";
$('#quickpresets').append( str );
input = $( '#'+inputname ).entityselector( {
url: 'https://www.wikidata.org/w/api.php',
language: mw.config.get('wgUserLanguage')
} );
}
}
How do I fix this issue? And what other things are there that I should do to improve this ugly code?
Updates:
I get the following error in the console:
TypeError: $(...).entityselector is not a function [Weitere
Informationen]
The full code can be found here.
I have to use ES5.
The data is always the same ("hard coded") JSON.
See below for the better readable version of Roamer-1888 – which still causes the same bug.
It's not apparent in the code why .entityselector() should throw on some occasions. The most likely reason is that you are trying to invoke the plugin before it is loaded.
In an attempt to fix the issue, you might try initialising all the inputs in one hit instead of individually in the loop.
Also, the code would be made more readable by attaching a fairly simple fragment to the DOM, then immediately adding links and attaching event handlers with jQuery.
Here it is the way I would write it (with a bunch of tidying up) :
function addlinks(qid, prop) {
// compose and intert fieldset.
var $fieldset = $("<fieldset><legend>Quick Presets (" + prop.name + ")</legend></fieldset>")
.insertAfter($('.wikibase-statementgrouplistview').first());
// loop through prop.defaults
prop.defaults.forEach(function(dflt) {
// compose and append a basic fragment ...
var $fragment = $("<p class='addstatement'>Add " + dflt.pname + ":<span class=\"links\"></span>"
+ "<span class=\"quickpresetsinput\"><input /> ✔</span></p>")
.appendTo($fieldset);
// ... then allow jQuery to augment the appended fragment :
// i) conditionally addClass('disabled')
if($('#P' + dflt.pid).find(".wikibase-snakview-value a").length !== 0) {
$fragment.addClass('disabled');
}
// ii) loop through dflt.values and add links.
dflt.values.forEach(function(val) {
$("<span> ∙</span>")
.appendTo($fragment.find('span.links'))
.find('a')
.text(val.name)
.on('click', function(e) {
e.preventDefault();
additemstatement(qid, dflt.pid, dflt.pname, val.qid, val.name);
});
});
// iii) attach click handlers to the quickpresets inputs
$fragment.find('.quickpresetsinput').find('a').on('click', function(e) {
e.preventDefault();
var selection = $(this).prev('input').data('entityselector').selectedEntity();
additemstatement(qid, dflt.pid, dflt.pname, selection.id.substring(1), selection.label);
});
});
// invoke .entityselector() on all the quickpresets inputs in one hit
$('.quickpresetsinput input').entityselector({
'url': 'https://www.wikidata.org/w/api.php',
'language': mw.config.get('wgUserLanguage')
});
}
untested except for syntax
That's certainly tidier though without a proper understanding of the original issue, .entityselector() may still throw.
I'm currently building a small Todo list application using vanilla Javascript but I'm having some issues creating a delete button that onClick removes it's parent element.
From what I have read, when an onClick is called in Javascript the this keyword can be used to refer to the element that called the function. With this in mind I have the following code:
window.onload = initialiseTodo;
function addRecord(){
var title = document.getElementById('issueTitle');
var issueContent = document.getElementById('issueContent');
var contentArea = document.getElementById('contentArea');
if(title.value.length > 0 && issueContent.value.length > 0){
var newItem = document.createElement('div');
newItem.id = 'task' + count++;
newItem.className = 'task';
newItem.innerHTML = '<div class="taskbody"><h1>' + title.value + '</h1>'+ issueContent.value + '</div><div class="deleteContainer">'
+ '<a class="delete">DELETE</a></div>';
contentArea.appendChild(newItem);
assignDeleteOnclick();
}
}
function deleteRecord(){
this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
}
function assignDeleteOnclick(){
var deleteArray = document.getElementsByClassName('delete');
for(var i=0;i<deleteArray.length;i++){
deleteArray[i].onclick= deleteRecord();
}
}
function initialiseTodo(){
var btn_addRecord = document.getElementById('addRecord');
btn_addRecord.onclick = addRecord;
}
Basically I have a form that has two fields. When these fields are filled and the addRecord button is clicked a new div is added at the bottom of the page. This div contains a delete button. After the creation of this I assign an onclick event to the delete button which assigns the deleteRecord function when the delete button is clicked. My issue is with the deleteRecord function. I have used this to refer to the calling element (the delete button) and wish to remove the task div that is the outermost container however I current get a message that says: 'Cannot read property 'parentNode' of undefined ' which suggests to me the this keyword is not working correctly.
Any help would be greatly appreciated.
I've added the full code to a fiddle.
http://jsfiddle.net/jezzipin/Bd8AR/
J
You need to provide the element itself as a parameter. I did so by changing the html to include onclick="deleteRecord(this)" to make it a little easier to deal with. This means you can remove the assignDeleteOnclick() function
function deleteRecord(elem){
elem.parentNode.parentNode.remove();
}
Demo
You might style the .content to be hidden better if there are no elements to prevent that extra white space
Edit
Since you don't want an inline onclick, you can do it with js the same:
function deleteRecord(elem){
elem.parentNode.parentNode.remove();
}
function assignDeleteOnclick(){
var deleteArray = document.getElementsByClassName('delete');
for(var i=0;i<deleteArray.length;i++){
// Has to be enveloped in a function() { } or else context is lost
deleteArray[i].onclick=function() { deleteRecord(this); }
}
}
Demo
My JavaScript code is:
<script type="text/javascript">
var current = 0;
var cars = new Array(5);
cars[0] = "Audi";
cars[1] = "Bentley";
cars[2] = "Mercedes";
cars[3] = "Mini";
cars[4] = "BMW";
document.getElementById("addCarBtn").onclick = function () {
if (!(current > cars.length - 1)) {
document.getElementById("carsDiv").innerHTML += cars[current] + "<br />";
current++;
}
}
</script>
I want to display the value of each array item one by one on button click the div.
But when i click the button, the array[0] i.e "Audi" is displayed but just for fraction of seconds. then it disappears and only the button is visible.
You can use a loop like:-
for(var i=0; i< cars.length;i++)
{
alert(cars[i]);
}
//It will show alert 5 times. You'll need to click through ok to traverse all array elements.
//I think it is what you're thinking, or have I interpreted it wrong.
// I'm assuming you're completely new to javascript then on your button write onclick="yourFuncName();"
function YourfuncName()
{
//Initailze your array here, like you have done or like kamituel has done
// then just print each array element one by one
for(var i=0; i< cars.length;i++)
{
alert(cars[i]);
}
}
How about the every method?
cars.every( function(c) {
alert("car: " + c);
});
You're almost there. Since the JS code was located before the HTML, the button element still doesn't exist. Best just wrap the code with window.onload and it should work:
window.onload = function() {
document.getElementById("addCarBtn").onclick = function() {
if (!(current > cars.length - 1)) {
document.getElementById("carsDiv").innerHTML += cars[current] + "<br />";
current++;
}
}
};
Live test case.
Edit: just noticed your button doesn't have type. This means that some browsers might make it a submit button by default, which will cause a page reload. To avoid it, make it a plain button:
<button id="addCarBtn" type="button">
I am currently attempting to write a function that applies unique ids to list item dynamically by ticking checkboxes, though I have encountered a problem, when appending the unique id to the list item I get the following error message in the console:
Uncaught TypeError: Object SpTU 4, 183:false<br /> has no method 'append'
Here is the code that is causing the error:
strng += name+":"+val+"<br />";
var i = 1;
strng.append($({ type: "text", id:+i }));
I need help with this quickly so any help would be greatly appreciated!
Thanks in advance
-------EDIT----------
Here is the whole function so it is easier to understand, I am new to programming to it may be very messy and unproffesional.
var dataToShow = {};
function check(tickbox){
dataToShow[tickbox.value] = tickbox.checked == true;
showDataOnScreen(dataToShow);
function showDataOnScreen(dataToShow){
var $strng = "";
jQuery.each(dataToShow,function(name,val){
$strng += name+":"+val+"<br />";
var i = 1;
$strng.append($({ type: "text", id:+i }));
});
jQuery("#list").html(strng);
Ensure that strng is a JQUERY object, assuming you are using JQUERY
If you are trying to build a list of checked items, I would go about it this way.
// create an array to store the checked items
var checkedItems = new Array();
// loop through the checked check boxes contained in the list element
// and add them to the array
$("#list :checked").each(function (){
var item = { name: $(this).attr("name"), value: $(this).val() };
checkedItems.push(item);
});
Or, even better, if you plan on displaying the results in a different element, you can cut out the array.
// loop through the checked check boxes contained in the list element
// and add them to a different element
$("#list :checked").each(function (){
var item = "<div>"+ $(this).attr("name") + ": " + $(this).val() + "</div>";
$("#selectedList").append(item);
});
Here's a working example on jsFiddle.
References:
Array: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array
jQuery each(): http://api.jquery.com/jQuery.each/
jQuery :checked selector: http://api.jquery.com/checked-selector/
jQuery append(): http://api.jquery.com/append/