searching deeper than 1 into json - javascript

im trying to figure out how to search deeper than just one deep in my JSON file.
its structure is as follows
json>data>movies>
in movies the different movies are enumerated 0, 1, 2, 3, 4, etc so
json>data>movies>3>
would contain movie information for the 4th movie
each containing key value pairs.the code i am using only seems to look one deep, and i cant seem to get it to go deeper.
code is as follows
$('#search').keyup(function () { // i understand this to watch the form id search
var searchField = $('#search').val(); // sets variable searchfield from typed content, .val grabs the content
if (searchField.length) // this sets the length to false by default ensuring the code only runs when it is supposed to and not all the time
{
var myExp = new RegExp(searchField, "i"); // sets variable myexp to regular expression using "i" for case insensitive
var found = 0; // sets variable found to 0 to keep div hidden until match is found
$.getJSON('/secure/movies.json', function (data) { //gets movies.json file pushes to data function
var output = '<ul class="searchresults">';
$.each(data, function (key, val) { // this should make key pairs from data
if (val.title.search(myExp) !== -1) { // this is the problem i think
console.log(val); // this should show our search term results in console
found = 1;
output += '<li>';
output += '<h2>' + val.title + '</h2>';
output += "<a href=" + val.image + ' target="_blank" ></a>';
output += '</li>';
}
});
output += '</ul>';
if (found == 1) {
$('#update').removeClass('update-hidden');
$('#update').html(output);
} else {
$('#update').addClass('update-hidden');
}
});
} else {
$('#update').addClass('update-hidden');
}
});
ive tried manipulating val.title.search(myexp) but i might be missing the boat on whats happening here with val.title.search. thanks in advance

Related

Loop through Array and count

Been struggling with counting through this array. I was able to do it previously but I don't think I quite understand how the parameters of a function are assigned its data.
I am bringing in an array with from JSON data over AJAX, then using a .each loop to go through the data and count it. But I can't seem to count it when using the index parameter. It is just giving me the actual objects and not counting how many objects there are.
I was hoping that someone could help me understand why I am getting the object and not the count of objects in the array. What I have now is just my final attempt at getting it to count, I know it's wrong.
I am trying to count how many "results" there are in the array (that came from the JSON file).
I have added snippets of my code and attached a link to the JSON file. I have also marked the problem area with a comment saying Problem Area
CODE -
$.getJSON('http://api.fixer.io/latest?base=ZAR', {
action: "query",
list: "search",
format: "json",
}
, function (data) {
var baseCurr = data.base;
var baseDate = data.date;
$('#curr-cont').append('<div class="base row1" id="row1"><div class="base flag" id="flag"><i class="famfamfam-flag-za"></i></div><div class="base country-name"><p class="c-name" id="count-name">' + baseCurr + '</p></div><div class="base currency"><p class="c-amount" id="curr">' + baseDate + '</p></div></div>');
//***Problem Area***
var rates = [data];
$.each(rates[0], function (i, obj) {
console.log(obj);
});
$.each(data.rates, function (i, item) {
var amount = [item];
var name = [i];
var maxLength = 4;
var string = amount.toString();
string = string.substr(0, maxLength);
// amount = amount.substr(0, maxLength);
$('#curr-cont').append('<div class="row1" id="row1"><div class="flag" id="flag"><i class="famfamfam-flag-' + name + '"></i></div><div class="country-name"><p class="c-name" id="count-name">' + name + '</p></div><div class="currency"><p class="c-amount" id="curr">' + string + '</p></div></div>');
// if(i > 0){
// $('#list1').append('<li>' + name + '</li>');
// }
// else{
// $('#list2').append('<li>' + name + '</li>');
// }
});
});
JSON Data File
edit:
since rates is an object and not an array, you can do: Object.keys(data.rates).length.
Object.keys(...) will give you an array with all the keys in the object.
original:
If you want to know the number of rates in that file: data.rates.length will give you the length of the rates Array that is returned in the data.
No need to count it

How can I only select some JSON objects?

Hi I have a script which parses a local JSON object (at the moment just to display a list).
function generateFamilySelect() {
var implantData = JSON.parse(localStorage.getItem("implantData"));
var implantFamilies = "";
$.each(implantData.implantFamilies, function( index, value ) {
implantFamilies += implantData.implantFamilies[index].familyDisplay + "<br />";
});
$("#holderForFamilySelect").html(implantFamilies);
}
and the JSON object:
{"implantFamilies":[
{"id":"1","familySelector":"aa","familyDisplay":"One","loadInitially":"1"},
{"id":"2","familySelector":"bb","familyDisplay":"Two","loadInitially":"1"},
{"id":"3","familySelector":"cc","familyDisplay":"Three","loadInitially":"1"},
{"id":"4","familySelector":"dd","familyDisplay":"Four","loadInitially":"0"},
{"id":"5","familySelector":"ee","familyDisplay":"Five","loadInitially":"0"},
{"id":"6","famiā€¦
At the moment, the list shows all of the elements. How can I modify this script to only show those with "loadInitially":"1"?
Also, a quick syntax question, I feel like the line
implantFamilies += implantData.implantFamilies[index].familyDisplay + "<br />";
could be written something like
implantFamilies += this[index].familyDisplay + "<br />";
but I can't get that to work...
The easiest is to use the Javascript Array.filter() method
// (or in your case, you get it from localstorage, but here's the data)
var myJson = {"implantFamilies":[
{"id":"1","familySelector":"aa","familyDisplay":"One","loadInitially":"1"},
{"id":"2","familySelector":"bb","familyDisplay":"Two","loadInitially":"1"},
{"id":"3","familySelector":"cc","familyDisplay":"Three","loadInitially":"1"},
{"id":"4","familySelector":"dd","familyDisplay":"Four","loadInitially":"0"},
{"id":"5","familySelector":"ee","familyDisplay":"Five","loadInitially":"0"}] };
//the array of implant families
var implantFamilies = myJson.implantFamilies;
//the filtering function. This is preferable to $.each
function implantFamiliesThatLoadInitially(implantFamily){
return implantFamily.loadInitially === '1';
}
//this is only the ones you want, (filtered by loadInitially property)
var loadInitiallyImplantFamilies = implantFamilies.filter(implantFamiliesThatLoadInitially);
The goal of the second part of your code is to build some html based on the data in the json, stored in teh variable implantFamilies. I will recommend Array.map() as an easier solution, than dealing with this. like before I am breaking this into multiple steps with comments so it is clear what is happening.
//your map function. You can make any html you want, like li's
function toImplantFamilyHtml(family){
return family.familyDisplay + '<br />'
}
//returns a plain string of html
var implantFamilyHtml = loadInitiallyImplantFamilies.map(toImplantFamilyHtml);
//jquery object you can use, or append to the DOM or whatever
var $implantFamilyHtml = $(implantFamilyHtml);
//append to DOM
$("#holderForFamilySelect").html($implantFamilyHtml);
working Fiddle: https://jsfiddle.net/mv850pxo/2/
the_5imian has provided a good answer to your first question, and you have determined the obvious alternate solution, given your current code.
As to your second question (this within jQuery.each()):
Within jQuery.each(), this is the value wrapped as an Object. value is the value of the array element at the current index, not the entire array. In other words, you don't use [index] on value or this within this context to get the current array element. For this code, value and this are the same because value is already an Object.
For what you want, you could just use value (Given that all elements of the array are already Objects, you could use this instead, but using value is a better habit to be in.):
$.each(implantData.implantFamilies, function( index, value ) {
if (value.loadInitially == "1") {
implantFamilies += value.familyDisplay + "<br />";
} else {
//do nothing
}
});
this is the value wrapped as an Object:
The following should show you what the values of value and this are within $.each(array,function(index,value){...});:
var myArray = ['zero','one','two','three','four','five'];
$.each(myArray, function(index,value){
console.log(index + ' value =',value);
console.log(index + ' this =',this); //this is the value wrapped as an Object.
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Well that just seems obvious now.
$.each(implantData.implantFamilies, function( index, value ) {
if (implantData.implantFamilies[index].loadInitially == "1") {
implantFamilies += implantData.implantFamilies[index].familyDisplay + "<br />";
} else {
//do nothing
}
});
How about the second part of my question?

How to check and return data until there are no matches?

I have created a function, that will search for different tags, tags like [image] and [gallery] inside a JSON file. If there is a match, it will return and replace it with a new output. Like an image object or a slideshow.
A JSON object can contain multiple tags of the same type, or contain different ones at the same time. So an object can contain two [image] tags for e.g.
JSON
http://snippi.com/s/bzrx3xi
The problem was, if there are multiple [image] tags found, it was replaced with the same content. I was looking for a script that is searching for the tags, until there will no matches anymore. Many thanks to #debatanu for the solution.
Unfortunately, I have some extra wishes for the script, because now the tags like image, will be replaced for the last image object of the media array inside the JSON and it will only grab and replace the first tag.
I was wondering if it is possible to check each tag and replace each tag with the new output.
Search for tags
filterText: function(data) {
// Loop through JSON data
// Check if [tag] in data.text exists
var dataText = data.text;
var tags = {
"gallery": /\[gallery\]/ig,
"image": /\[image\]/ig
};
if (dataText != undefined) {
var raw_data = dataText;
for (var key in tags) {
if (tags.hasOwnProperty(key)) {
var tag = tags[key];
var tagArr = [];
// Check if [tag] in data.text exists
while ( (tagArr = tag.exec(dataText)) !== null ) {
// Call functions
if (key == "gallery") {
console.error('GALLERY');
parsedHTML = raw_data.replace(tagArr[0], shortcodeController.gallery(data));
raw_data = parsedHTML;
return parsedHTML;
}
if (key == "image") {
console.error('IMAGE');
parsedHTML = raw_data.replace(tagArr[0], shortcodeController.image(data));
raw_data = parsedHTML;
return parsedHTML;
// model.find('p').html(parsedHTML);
}
}
}
}
};
Call the filterText function
getDataPopup: function(data) {
if (data.text != undefined) {
$('.js-popup .article').html(data.text);
var parsed = dataController.filterText(data);
console.log('parsed: ', parsed);
$('.js-popup .article').html(parsed);
} else {
$('.js-popup .article').html(data.intro);
}
},
Above function will search for tags inside a while loop.
This script is called, when the user clicked on an item, that will open a popup screen.
The script that is called by the getDataPopup function when the user clicked on an item, will search for a match, when there is a match found, it will call the function shortcodeController.image(data) that return the new output to the variable: parsedHTML.
The function that generates a new output will look like this:
image: function(data) {
// Development
console.log('shortcodeController.image');
var raw_data = data.text;
var outputHTML;
if (data.media != undefined) {
for (var i = 0; i < data.media.length; i++) {
if (data.media[i].image != undefined) {
outputHTML = '<div class="image">';
// Extract filename
var url = data.media[i].image.src;
var filename = url.substring( url.lastIndexOf('/') + 1, url.lastIndexOf('.') );
// console.log(filename);
outputHTML += '<img src="' + url + '" alt="' + filename + '" />';
//data.media[i].image = undefined;
outputHTML +='</div>';
}
};
return outputHTML;
} else {
// If media doesn't exists return empty string
return '';
}
},
Debatanu has mentioned that I should use data.media[i].image = undefined; directly after the outputHTML that contains the actual image object, but this will result in an undefined error. The first [image] tag is replaced by undefined. When I comment this line out, it will be replaced by the last image object inside the media array, as mentioned before.
Maybe it does not work like properly, because the while loop, however, only looks for the gallery and image tags and if there is a match, running it once, because he already saw the tag. Then it will be called again and replaces the first image tag again with the second image object within the media array. Should there might be a while loop added in the if statements on whether it is a gallery or image, so for each tag within the text object is the function called?
Also I noticed, when I console logged tagArr it will give me an value of null when I past it after the while loop and a empty array [] when I paste it directly after the array is created. Beside that, when I console log tag directly after the while loop is started, it only console log tag once, while there are two image tags set inside the JSON.
You can use exec and loop through it using
var dataText = data.text;
var tags = {
"gallery": /\[gallery\]/ig,
"image": /\[image\]/ig,
};
if (dataText != undefined) {
var raw_data = dataText;
for (var key in tags) {
if (tags.hasOwnProperty(key)) {
var tag = tags[key];
var arr=[];
while ((arr= tag.exec(dataText)) !== null) {
//arr[0] will contain the first match
//var newTag=newTags[key];
//you need to replace the matched output
//so no need for newTag
if (key == "gallery") {
console.error('GALLERY');
//replace the matched output arr[0]
//instead tag or newTag
//Since u have [] to replace we need to ommit the regex literal format /<<exp>>/
parsedHTML = raw_data.replace(arr[0], Triptube.shortcodeController.gallery(data));
//Need to add this line for reflecting the changed data
raw_data=parsedHTML;
model.find('p').html(parsedHTML);
}
if (key == "image") {
console.error('IMAGE');
//replace the matched output arr[0]
//instead tag or newTag
//Since u have [] to replace we need to ommit the regex literal format /<<exp>>/
parsedHTML = raw_data.replace(arr[0], Triptube.shortcodeController.image(data));
console.log(parsedHTML);
//Need to add this line for reflecting the changed data
raw_data=parsedHTML;
model.find('p').html(parsedHTML);
}
}
}
}
}
You can find more about it in MDN
With each loop the exec will give you the next match untill no match is left.
EDIT
I have added the entire filter code from the beginning. You see the raw_data variable should be assigned before the loop. Once that is done, the code below with the image function should give you the proper result.
EDIT 2
First the filterText function will return the parsed html post completion of parsing the html
filterText: function(data) {
// Loop through JSON data
// Check if [tag] in data.text exists
var dataText = data.text;
var tags = {
"gallery": /\[gallery\]/ig,
"image": /\[image\]/ig
};
if (dataText != undefined) {
var raw_data = dataText,
newData=JSON.parse(JSON.stringify(data));//Copy of the data object
for (var key in tags) {
if (tags.hasOwnProperty(key)) {
var tag = tags[key];
var tagArr = [];
// Check if [tag] in data.text exists
while ( (tagArr = tag.exec(dataText)) !== null ) {
// Call functions
if (key == "gallery") {
console.error('GALLERY');
parsedHTML = raw_data.replace(tagArr[0], shortcodeController.gallery(newData));
raw_data = parsedHTML;
//return parsedHTML;
}
if (key == "image") {
console.error('IMAGE');
parsedHTML = raw_data.replace(tagArr[0], shortcodeController.image(newData));
raw_data = parsedHTML;
//return parsedHTML; we will return the parsed HTML only when all the tags have been replaced
// model.find('p').html(parsedHTML);
}
}
}
}
return parsedHTML; //return the parsed HTML here
};
Next is the image function which will parse through the images,
image: function(data) {
// Development
console.log('shortcodeController.image');
var raw_data = data.text;
var outputHTML;
if (data.media != undefined) {
for (var i = 0; i < data.media.length; i++) {
if (data.media[i].image != undefined) {
outputHTML = '<div class="image">';
// Extract filename
var url = data.media[i].image.src;
var filename = url.substring( url.lastIndexOf('/') + 1, url.lastIndexOf('.') );
// console.log(filename);
outputHTML += '<img src="' + url + '" alt="' + filename + '" />';
outputHTML +='</div>';
data.media[i].image = undefined;
//Uncommented the above code, because now the operation will be done on the copy of the original data object
}
};
return outputHTML;
} else {
// If media doesn't exists return empty string
return '';
}
}

JSON to HTML using JSON.parse undefined error

When trying to parse the JSON
[{"title":"First Item","href":"first","children":[{"title":"Sub First Item","href":"sub"}]},{"title":"Second Item","href":"home"}]
into a list for navigation its just returning undefined.
I was using code from another answer which was working fine with hardcoded JSON but when using it from a textbox (as its going to be generated using jquery.nestable.js) it just gived undefined and i cant see why, ive tried escaping the quotation marks too but no luck there.
function convertNav(){
var data = document.getElementById('jsonNav').value;
var jsn = JSON.parse(document.getElementById('jsonNav').value);
var parseJsonAsHTMLTree = function(jsn){
var result = '';
if(jsn.title && jsn.children){
result += '<li>' + jsn.title + '<ul>';
for(var i in jsn.children) {
result += parseJsonAsHTMLTree(jsn.children[i]);
}
result += '</ul></li>';
}
else {
result += '<li>' + jsn.title + '</li>';
}
return result + '';
}
var result = '<ul>'+parseJsonAsHTMLTree(jsn)+'</ul>';
document.getElementById('convertedNav').value = result;
}
Ive put it in a jsfiddle
http://jsfiddle.net/nfdz1jnx/
Your code handles only a single Javascript object but, according to your code, all nodes and sub-nodes are wrapped inside Javascript arrays. You can use Array.prototype.forEach to handle the array objects.
Sample code follows.
function convertNav() {
var data = document.getElementById('seriaNav').value;
var jsn = JSON.parse(document.getElementById('seriaNav').value);
var parseJsonAsHTMLTree = function(jsn) {
var result = '';
jsn.forEach(function(item) {
if (item.title && item.children) {
result += '<li>' + item.title + '<ul>';
result += parseJsonAsHTMLTree(item.children);
result += '</ul></li>';
} else {
result += '<li>' + item.title + '</li>';
}
});
return result + '';
};
var result = '<ul>' + parseJsonAsHTMLTree(jsn) + '</ul>';
document.getElementById('convertedNav').value = result;
}
<textarea class="span7" style="width:400px;height:100px;" id="seriaNav">[{"title":"First Item","href":"first","children":[{"title":"Sub First Item","href":"sub"}]},{"title":"Second Item","href":"home"}]</textarea>
<hr />
<button class="btn btn-primary" onClick="convertNav();return false;">Convert</button>
<hr />
<textarea class="span5" style="width:400px;height:100px;" id="convertedNav"></textarea>
Your jsn variable is an array. You're getting a list of Objects back and you'll need to parse each one.
Add this after you get jsn back and you'll see an example of retrieving your data.
alert(jsn[0].title);
Your JSON is parsed into an array of objects. With this in mind, your paths to extract information are wrong. For example, you have:
if(jsn.title...
...whereas there is no jsn.title. There is, however, json[0].title.
Basically, you're missing a loop, over the objects. After
var result = '';
add
for (var i=0, len=jsn.length; i
...and in code subsequent to that change all references to jsn to jsn[i]
And of course close the loop further down.
(Finally, at the risk of being pedantic, jsn is not the best name for the var; it's not JSON anymore; it used to be, but now it's parsed, so it's an array. JSON is a string.)
[{"title":"First Item","href":"first","children":[{"title":"Sub First Item","href":"sub"}]},{"title":"Second Item","href":"home"}]
This is not JSON, this is an array of objects. You don't need to parse this. It's already parsed. It's a javascript object.
You should be able to just parse it like you would a regular object.
data[0].title
data[0].children[1].title
etc.

How to append data from JavaScript file to the html file dynamically

I have to build JS multi select questionnaire.
In order to read the json details I use the following code:
$(document).ready(function(){
$.getJSON("data.json", function(json) {
var anserFor1st = json.questions[0].answers;
var anserFor2nd = json.questions[1].answers;//If it's more than two use a loop
document.getElementById("content").innerHTML = JSON.stringify(anserFor1st) + "<br/>" + JSON.stringify(anserFor2nd);
var aString = "";
Object.keys(anserFor1st).forEach(function (k) {aString += anserFor1st[k] + "<br/>";});
Object.keys(anserFor2nd).forEach(function (k) {aString += anserFor2nd[k] + "<br/>";});
document.getElementById("content").innerHTML = aString;
});
});
I have to shoe all of the questions&answers in the same page but every time with different content (aka question&answer). I have to move between questions by back and forward buttons. How do I display the values of the different question dynamically in the html?
If you have all the questions in a list, as it appears you do, the jQuery to dynamically change the question content is pretty trivial. We can create a function, and pass parameters to the function telling it to move forwards or backwards in the array of questions, as long as it doesn't extend outside the array. An example of this is here.
var testArray = ["first q", "second q", "third q", "fourth q"];
var questionIndex = 0;
function updateQuestion(direction) {
questionIndex += direction;
if (questionIndex < testArray.length && questionIndex >= 0) {
$(".question").html(testArray[questionIndex]);
} else {
questionIndex -= direction;
}
}
$(document).ready(function () {
updateQuestion(0);
});
You should be able to loop through your questions and append the JSON data to a blank array in place of testArray.

Categories