I am trying to parse a json file using jquery getJson. I have no problem looping through the first layer, but I need to assign a nested array to li as well.
My JSON Code
{"Controls":[
{
"Object":"Button",
"ButtonAttr": [{"x": "1","y": "2","width": "3","height": "4"}]
},
{
"Object":"Image",
"ButtonAttr": [{"x": "5","y": "6","width": "7","height": "8"}]
},
{
"Object":"TextField",
"ButtonAttr": [{"x": "9","y": "10","width": "11","height": "12"}]
}
]}
My JS/JQUERY Code where I have no problem bringing in the first layer of the JSON and appending it to a li. I need to figure out how to get the 'ButtonAttr' layer
//Get JSON File which contains all Controls
$.getJSON('controls.json', function(data) {
//Build Objects List
var objectList="<ul>";
for (var i in data.Controls) {
objectList+="<li>" + data.Controls[i].Object +"</li>";
}
objectList+="</ul>";
$('#options').append(objectList);
//Add new Code Object based on #Options LI Index
$(document).on('click','#options li', function() {
var index = $('#options li').index(this);
$('#code').append('<li>' + data.Controls[index].Object + '</li>');
//Shows Selected LI Index
$('#optionsIndex').text("That was div index #" + index);
});
});
I cannot for the life of me get it to loop through the second array and list out the x,y,width, and height fields.
Here is my desired output
<ul>
<li>Button</li>
<ul>
<li>x:1</li>
<li>y:2</li>
<li>width:3</li>
<li>height:4</li>
</ul>
<li>Image</li>
<ul>
<li>x:5</li>
<li>y:6</li>
<li>width:7</li>
<li>height:8</li>
</ul>
<li>TextField</li>
<ul>
<li>x:9</li>
<li>y:10</li>
<li>width:11</li>
<li>height:12</li>
</ul>
</ul>
Any help would be greatly appreciated
I worked through this in another question.
How to handle comma separated objects in json? ( [object Object],[object Object] )
You want a recursive function that starts a <ul> and adds <li> for each item in the list. It also tests items, and if they are themselves lists, it calls itself with that piece of data as the argument. Each time the function is called from within the function you get a <ul> within a <ul>.
function buildULfromOBJ(obj){
var fragments = [];
//declare recursion function
function recurse(item){
fragments.push('<ul>'); // start a new <ul>
$.each(item, function(key, val) { // iterate through items.
if((val != null) && (typeof val == 'object') && // catch nested objects
((val == '[object Object]') || (val[0] == '[object Object]'))){
fragments.push('<li>[' + key + '] =></li>'); // add '[key] =>'
recurse(val); // call recurse to add a nested <ul>
}else if(typeof(val)=='string'){ // catch strings, add double quotes
fragments.push('<li>[' + key + '] = \"' + val + '\"</li>');
}else if($.isArray(val)){ // catch arrays add [brackets]
fragments.push('<li>[' + key + '] = [' + val + ']</li>');
}else{ // default: just print it.
fragments.push('<li>[' + key + '] = ' + val + '</li>');
}
});
fragments.push('</ul>'); // close </ul>
}
// end recursion function
recurse(obj); // call recursion
return fragments.join(''); // return results
} // end buildULfromOBJ()
save your self the pain of trying to do with with for loops etc. and use client-side templating like json2html.com
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src='http://json2html.com/js/jquery.json2html-3.1-min.js'></script>
<ul id='out'></ul>
<script>
var data =
{"Controls":[
{
"Object":"Button",
"ButtonAttr": [{"x": "1","y": "2","width": "3","height": "4"}]
},
{
"Object":"Image",
"ButtonAttr": [{"x": "5","y": "6","width": "7","height": "8"}]
},
{
"Object":"TextField",
"ButtonAttr": [{"x": "9","y": "10","width": "11","height": "12"}]
}
]};
var template = {"tag":"li","children":[
{"tag":"span","html":"${Object}"},
{"tag":"ul","children":[
{"tag":"li","html":"x: ${ButtonAttr.0.x}"},
{"tag":"li","html":"y: ${ButtonAttr.0.y}"},
{"tag":"li","html":"width: ${ButtonAttr.0.width}"},
{"tag":"li","html":"height: ${ButtonAttr.0.height}"}
]}
]};
$('#out').json2html(data.Controls,template);
</script>
You can do it like this.. using the $.each and a for in loop
var str = '<ul>';
$.each(data.Controls, function(k, v) {
str += '<li>' + v.Object + '</li><ul>';
for(var kk in v.ButtonAttr[0]){
str += '<li>' + kk + ':' + v.ButtonAttr[0][kk] + '</li>';
}
str += '</ul>';
});
str += '</ul>';
FIDDLE
or with 2 $.each loops
var str = '<ul>';
$.each(data.Controls, function(k, v) {
str += '<li>' + v.Object + '</li><ul>';
$.each(v.ButtonAttr[0],function(kk,vv){
str += '<li>' + kk + ':' + vv + '</li>';
});
str += '</ul>';
});
str += '</ul>';
FIDDLE
You can loop through the second array just as easily as the first, like so:
$(document).on('click','#options li', function() {
var index = $('#options li').index(this);
$('#code').append('<li>' + data.Controls[index].Object + '</li>');
// Create a new sub-UL to after the LI
var $subUl = $(('<ul>')
// Iterate through each attribute in ButtonAttr
$.each(data.Controls[index].ButtonAttr, function(key, value){
// Append a new LI with that attribute's key/value
$subUl.append('<li>' + key + ':' + value + '</li>');
});
// Append that new sub-UL we made after the last LI we made
$('#code li:last').after($subUl);
//Shows Selected LI Index
$('#optionsIndex').text("That was div index #" + index);
});
Related
i have been tasked by my senior to print values of line items using higher order functions (.filter/.map/.reject/.reduce). I m confused how to write the higher order function instead of a for loop(for printing the line values in Invoice Printout). I need to print the line only when the qty is more than 3. I m an intern and i dont know how it will work, kindly help.
Link to The code snippet: https://drive.google.com/file/d/1uVQQb0dsg_bo53fT3vk9f0G8WwZomgQg/view?usp=sharing
I always used if condition for printing the row only when the quantity field has value more than 3. I even know how to .filter but i dont know how to call it and where to call it. Please help
I don't believe Array.from works in server side code. If it does then use that. What I have been using are the following functions. They don't conform to the higher order functions specified but they work with Netsuite syntax and go a long way towards simplifying sublist handling and encapsulating code:
//SS2.x
//I have this as a snippet that can be included in server side scripts
function iter(rec, listName, cb){
var lim = rec.getLineCount({sublistId:listName});
var i = 0;
var getV = function (fld){
return rec.getSublistValue({sublistId:listName, fieldId:fld, line:i});
};
for(; i< lim; i++){
cb(i, getV);
}
}
// to use it:
iter(ctx.newRecord, 'item', function(idx, getV){
if(parseInt(getV('quantity')) >3){
...
}
});
or for SS1 scripts I have the following which allows code to be shared between UserEvent and Scheduled scripts or Suitelets
function forRecordLines(rec, machName, op, doReverse) {
var i, pred, incr;
var getVal = rec ? function(fld) {
return rec.getLineItemValue(machName, fld, i);
} : function(fld) {
return nlapiGetLineItemValue(machName, fld, i);
};
var getText = rec ? function(fld) {
return rec.getLineItemText(machName, fld, i);
} : function(fld) {
return nlapiGetLineItemText(machName, fld, i);
};
var setVal = rec ? function(fld, val) {
rec.setLineItemValue(machName, fld, i, val);
} : function(fld, val) {
nlapiSetLineItemValue(machName, fld, i, val);
};
var machCount = rec ? rec.getLineItemCount(machName) : nlapiGetLineItemCount(machName);
if(!doReverse){
i = 1;
pred = function(){ return i<= machCount;};
incr = function(){ i++;};
}else{
i = machCount;
pred = function(){ return i>0;};
incr = function(){ i--;};
}
while(pred()){
var ret = op(i, getVal, getText, setVal);
incr();
if (typeof ret != 'undefined' && !ret) break;
}
}
// User Event Script:
forRecordLines(null, 'item', function(idx, getV, getT, setV){
if(parseInt(getV('quantity')) >3){
...
}
});
// in a Scheduled Script:
forRecordLines(nlapiLoadRecord('salesorder', id), 'item', function(idx, getV, getT, setV){
if(parseInt(getV('quantity')) >3){
...
}
});
Usually its a straight forward task, but since you are getting length and based on that you are iterating, you can use Array.from. Its signature is:
Array.from(ArrayLikeObject, mapFunction);
var tableData = Array.from({ length: countItem}, function(index) {
vendorBillRec.selectLineItem('item', index);
var item = vendorBillRec.getCurrentLineItemText('item', 'item');
var description = nlapiEscapeXML(vendorBillRec.getCurrentLineItemValue('item', 'description'));
var quantity = parseFloat(nullNumber(vendorBillRec.getCurrentLineItemValue('item', 'quantity')));
return { item, description, quantity}
});
var htmlData = tableData.filter(...).map(getRowMarkup).join('');
function getRowMarkup(data) {
const { itemName, descript, quantity } = data;
return '<tr>' +
'<td colspan="6">' +
'<p>' + itemName + ' ' + descript + '</p>'+
'</td>' +
'<td colspan="2" align="right">' + quantity + '</td>' +
'</tr>';
}
Or if you like to use more functional approach:
Create a function that reads and give you all data in Array format. You can use this data for any task.
Create a function that will accept an object of specified properties and returns a markup.
Pass the data to this markup after any filter condition.
Idea is to isolate both the task:
- Getting data that needs to be processed
- Presentation logic and style related code
var htmlString = Array.from({ length: countItem}, function(index) {
vendorBillRec.selectLineItem('item', index);
var item = vendorBillRec.getCurrentLineItemText('item', 'item');
var description = nlapiEscapeXML(vendorBillRec.getCurrentLineItemValue('item', 'description'));
var qty = parseFloat(nullNumber(vendorBillRec.getCurrentLineItemValue('item', 'quantity')));
return getRowMarkup(item, description, qty)
}).join('');
function getRowMarkup(itemName, descript, quantity) {
return '<tr>' +
'<td colspan="6">' +
'<p>' + itemName + ' ' + descript + '</p>'+
'</td>' +
'<td colspan="2" align="right">' + quantity + '</td>' +
'</tr>';
}
I'm trying to create an expanded search where you can find people not only using there names but some combinations... for instance i have this list of players and this peace of code work fine, but if i want to find for such features like - keeper England. this line of code doesn't work ((val.position.search(myExp) != -1) || (val.nationality.search(myExp) != -1))
$("#search").keyup(function() {
var field = $("#search").val();
var myExp = new RegExp(field, "i");
$.getJSON("players.json", function(data) {
var output = "<ul>";
$.each(data, function(key, val) {
if ((val.name.search(myExp) != -1) || (val.position.search(myExp) != -1) || ((val.position.search(myExp) != -1) || (val.nationality.search(myExp) != -1))) {
output += "<li>";
output += '<p class="name">' + val.name + '</p>';
output += '<p>' + val.position + '</p>';
output += '<p>' + val.dateOfBirth + '</p>';
output += '<p>' + val.nationality + '</p>';
output += '<p>' + val.contractUntil + '</p>';
output += '<p>' + val.marketValue + '</p>';
output += "</li>";
}
});
output += "</ul>";
$("#update").html(output);
});
});
{
"id":2138,
"name":"Thibaut Courtois",
"position":"Keeper",
"jerseyNumber":13,
"dateOfBirth":"1992-05-11",
"nationality":"Belgium",
"contractUntil":"2019-06-30",
"marketValue":"35,000,000 ˆ"
},
{
"id":2140,
"name":"Jamal Blackman",
"position":"Keeper",
"jerseyNumber":27,
"dateOfBirth":"1993-10-27",
"nationality":"England",
"contractUntil":"2019-06-30",
"marketValue":"250,000 ˆ"
},
You have to do multiple search queries because you have multiple words in your query:
"england keeper" => "england" and "keeper"
So you want to filter the items by "england" and also by "keeper"..
The best would be to create a small functions, each will do a part of it:
// Note: this function returns the filter function
var myFilter = function(regex) {
return function(item) {
return regex.test(item.name)
|| regex.test(item.position)
|| regex.test(item.nationality)
}
}
// this is a higher order function, takes the items and the full searchString as arguments
var findMatches = function(items, searchString) {
// make a copy of the items / data
var found = items.slice(0, item.length);
// split the searchString, and filter the items by it
searchString.split(' ').forEach(function(part) {
found = found.filter(myFilter(new RegEx(part, 'i'))
});
return found;
}
Now you can use it in your code:
...
var output = "<ul>";
var filteredData = findMatches(data, field);
$.each(filteredData, function(key, val) {
// filteredData should be fine, you can just render it
}
...
I am trying to fetch objects from a main object. An array in the main object holds
these other objects, I can access the first element by calling 'oData.events.event[0]' but I would like to loop through to get [1], [2], [3] and so on.
//this works
var collection = oData.events.event[0];
$("<li>description: " + collection.description + "</li>").appendTo("#shower");
//this does not work :(
var collection = oData.events.event[0];
var output = "<ul>";
for (var i = 0; i < collection.length; i++)
{
output += "<li>" + collection.description + "</li>";
$(output).appendTo("#shower");
collection = collection + 1 //shift to next array
}
output += "</ul>";
Maybe use a foreach loop
oData.events.event.forEach(function(result) {
console.log(result);
});
Alternatively, try jQuery's .each() function:
$.each(oData.events.event, function(index, value) {
console.log( index + ": " + value );
});
EDIT: It's worth noting that the output of these calls will be an object - you still have to access the data beneath the objects you've looped to!
Fiddle here - however, you can do something like this...
var oData = {
events: {
event: [{ description: '1' },
{ description: '2' },
{ description: '3' }]
}
}
var collection = oData.events.event;
var output = "<ul>";
collection.forEach(function(item, i, arr) {
output += "<li>" + item.description + "</li>";
if (i === arr.length-1) {
output += "</ul>";
$("#shower").append(output);
}
});
I have multiple items in my JSON list. I want to loop through it and display it on my page. I can't seem to get to the next object though.
{
"room":[
{"campusName":"A",
"buildingCode":"B",
"roomNumber":"208",
"times":["7-8", "9-10"]
}],
"room2":[
{"campusName":"C",
"buildingCode":"D",
"roomNumber":"208",
"times":["7-8", "9-10"
]}
]}
$(document).ready(function(){
$.getJSON("data.json", function(data){
$.each(data.room, function(){
for(var i = 0; i < data.length; i++){
$("ul").append("<li>campus: "+this['campusName']+"</li><li>building: "+this['buildingCode']+"</li><li>times: "+this.times+"</li>");
}
});
});
});
Try this
var list = '';
$.each(data, function (i, root) {
$.each(root, function (i, el) {
list += "<li>campus: " + this.campusName + "</li><li>building: " + this.buildingCode + "</li><li>times: " + this.times.join(' ') + "</li>";
});
});
$('ul').html(list);
Example
If root's has only one element in array
var list = '';
$.each(data, function (i, root) {
list += "<li>campus: " + root[0].campusName + "</li><li>building: " + root[0].buildingCode + "</li><li>times: " + root[0].times.join(' ') + "</li>";
});
$('ul').html(list);
Example
$.each(data, ..) --> Each element will be:
"room":[
{"campusName":"A",
"buildingCode":"B",
"roomNumber":"208",
"times":["7-8", "9-10"]
}]
Then, this[0] will provide the object you need to construct your li:
$.each(data, function(){
$("ul").append("<li>campus: "+this[0]['campusName']+"</li><li>building: "+this[0]['buildingCode']+"</li><li>times: "+this[0].times+"</li>");
});
Fiddle
I have json with array of objects in it. I build my page depends on elements in this array. If there is no duplicate values of key called points, i render page with some info and description, using value of points to find this element in array. However if i have 2 and more duplicate values of key called points i render list of these elements. In this case i cant use value of points to find element in array. I know i can use index number of array element, and then pass it as parameter to my function that find and build info and description, but i'm not sure how to do that. How do i get index number of element in array?
P.S. Can provide my code if needed
Code that i'm using
var allRewards = null;
$("#reward").live('pagecreate', function(e) {
var request = $.ajax({
type: "GET",
url: "example.com/test.json"
dataType: "json",
error: function (data, textStatus){
console.log( "it`s error" );
console.log( status );
console.log( data );},
success: function (data, textStatus){
console.log( "success" );
console.log( status );
console.log( data );
}
})
request.success(function(data, textStatus){
var lis = "";
var arr = [];
var iter = 0;
allRewards = data
$.each(data.rewards, function(key, val){
if ($.inArray(val.points, arr) == -1)
{
lis += "<div data-points='"+ val.points +"'align=CENTER class = 'rewards-block ui-block-" + String.fromCharCode(97 + iter%3) + "'><a href ='#' class ='ui-link-inherit' onclick='showreward("+val.points+")'><img src ='./img/reward-icon.png'/><span>" + val.points + " pts</span></a></div>";
arr.push(val.points);
iter += 1;
}
});
$("#rewards_table").html(lis);
})
});
function showreward(point)
{
$.mobile.changePage('show-rewards.html')
console.log(allRewards);
$("#showrewards").live('pagecreate', function(e) {
var items = "";
var arr = [];
var counter = 0;
var result = $.grep(allRewards.rewards, function(e){ return e.points == point; });
if (result.length > 1)
{
$.each(result, function(key, val){
items += "<div style='color:white;'>" + val.title + "</div>"
console.log(val.title);
})
}
else if (result.length == 1)
{
// $.each(result, function(key, val){
// items += "div style='color:white;'"+ val.points + "></div>"
// console.log(val.points);
// })
$.each(result, function(key, val){
items += "<div style='background:white; padding:5px 5px 20px 5px;'><img style ='float:right; width:45%; margin-top:22px; padding: 0 0 10px 10px;' src ='" + val.main_photo_url + "'/><h3>"+ val.title + "</h3><p>" + val.description + "</p><p style='font-weight:bold; font-size:13px;'>Reedem below for " + val.points + " Zingle Points</p><table class='pagemenu' style='width:200px;'><tr><td class='width_5'><input type='submit' data-theme='w' value='Reedem Now' data-inline='true'></td><td><a data-role='button' data-icon='pagemenu-share' data-iconpos='notext' href='index.html' data-shadow='false' data-corners='false'></a></td></tr></table></div>"
});
}
console.log(items);
$("#rewards-list").html(items);
});
}
I think you're looking for Array.indexOf.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
PS. This is available in Underscore as _.indexOf.