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 have a working recursive function that creates an <ul> list from an object, it works fine,
my problem is that I want to keep track of the index, and add it as class to <li> elements,
I need that the "index count system" will count in a particular way, and this is the output that I want:
class0
class0_0
class0_0_0
class0_0_1
class0_1
class0_1_0
class0_1_1
class1
class1_0
class1_0_0
class1_0_1
class1_1
class1_1_0
class1_1_1
by increasing, restarting and have maybe multiple "index count" variables in the recirsive function
This is what I'm trying, but I still can't figure out where to properly set, increase, reset the counters to achieve that result..
var i = 0;
function object2ul(data) {
var json = "<ul>";
for(var key in data) {
json = json + "<li>" +'<b>'+i+'</b>'+ key; i++;
if(typeof data[key] == 'object') {
json = json + object2ul(data[key]);
}else{ i=0;
json = json + '<ul><li>'+ data[key]+'</li></ul>';
}
json = json + "</li>";
}
return json + "</ul>";
}
document.body.innerHTML = object2ul(object);
In this example I omitted to set the classes avoiding to complicate the function
DEMO
Something like this?
var object = {
root0: {
child0: {
leaf: 'text',
leaf: 'text'
},
child1: {
leaf: 'text',
leaf: 'text'
}
},
root1: {
child0:{
leaf: 'text',
leaf: 'text'
},
child1: {
leaf: 'text',
leaf: 'text'
}
}
};
var i = 0;
function object2ul(data, prefix) {
prefix = prefix || '0'; // default
var json = "<ul>";
var childIndex = 0;
for(var key in data) {
json = json + "<li>" +'<b>'+i+'</b>'+ key; i++;
if(typeof data[key] == 'object') {
json = json + object2ul(data[key], prefix + '_' + childIndex);
}else{ i=0;
json = json + '<ul><li>'+ data[key]+'---(' + prefix + ')</li></ul>';
}
json = json + "</li>";
childIndex++;
}
return json + "</ul>";
}
document.body.innerHTML = object2ul(object);
To get the kind of indexing you want, you are going to have to use Object.keys. The following should work for an arbitrary object:
var testObj = { a: { b: '2', d: '5', e: { f: '3' } }, c: '3' };
var indexes = [];
var object2ul = function (data) {
var keys = Object.keys(data);
var json = "<ul>";
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
indexes.push(i);
json += "<li>" + "<b>" + indexes.join('_') + "</b>" + key;
if (typeof(data[key]) === 'object') {
json += object2ul(data[key]);
} else {
json += "<ul><li>" + data[key] + "</li></ul>";
}
json += "</li>";
indexes.pop();
}
return json + "</ul>";
}
document.body.innerHTML = object2ul(testObj);
Here's it in action:
JSFiddle
Yes there are a number of threads questioning similar issues to the following, but I found very few and very little help regarding dynamic keys and pulling single values from jsons holding multiple values per key.
I have a json in which the keys are dynamic and I need to be able to call upon each separate value.
Any ideas?
json example below:
{"AppliedPrepaidBundle":{"id":["14","15","24","25","26","27","28","29","30","31"],"prepaid_bundle_id":["5","5","5","5","5","5","5","5","5","5"]},"Device":{"id":["77","77","91","91","117","117","117","117","117","124"]}}
I have played around with the following code, but currently only managed to spit out a string of values rather than individual ones:
$.each(data, function (key1, value1) {
$.each(value1, function (key, value) {
$('body').append('<li id="' + key + '">' + key1 +' ' + key +' ' + value + '</li>');
});
});
Solved with this:
json = JSON.parse(data);
for (var index in json) {
$.each(json[index], function(key,value) {
for(var i = 0; i< json[index][key].length; i++){
$('body').append('<li>' + index +' ' + key +' ' + json[index][key][i] + '</li>');
}
});
}
JSON returns an object in JavaScript. So you could do something like this:
var json = {"AppliedPrepaidBundle":{"id":["14","15","24","25","26","27","28","29","30","31"],"prepaid_bundle_id":["5","5","5","5","5","5","5","5","5","5"]},"Device":{"id":["77","77","91","91","117","117","117","117","117","124"]}};
for (var i=0; i<json.AppliedPrepaidBundle.id.length; i++) {
console.log("id"+i+": "+json.AppliedPrepaidBundle.id[i]);
}
This prints out all the values of the ID object: 14, 15, 24, 25, etc
Use JSON.parse to create an object. (See How to parse JSON in JavaScript). Then loop through the properties with for (x in yourObject) { ... }.
var jsonObject = JSON.parse('your JSON-String');
for (property in jsonObject) {
// do something with jsonObject[property]
console.log(property + ' ' + jsonObject[property]);
}
you can work with the javascript basic functionality:
http://jsfiddle.net/taUng/
var data = {"AppliedPrepaidBundle":{"id":["14","15","24","25","26","27","28","29","30","31"],"prepaid_bundle_id":["5","5","5","5","5","5","5","5","5","5"]},"Device":{"id":["77","77","91","91","117","117","117","117","117","124"]}};
for (var dataIndex in data) {
console.log(dataIndex, data[dataIndex]);
var subData = data[dataIndex];
for (var subDataIndex in subData) {
console.log(subDataIndex, subData[subDataIndex]);
}
}
And so on...
When your a fit in javascript you can also work with Recursion to don't repeat yourself. (http://en.wikipedia.org/wiki/Dont_repeat_yourself)
From this example you can access all elements
var json = {"AppliedPrepaidBundle":{"id":["14","15","24","25","26","27","28","29","30","31"],"prepaid_bundle_id":["5","5","5","5","5","5","5","5","5","5"]},"Device":{"id":["77","77","91","91","117","117","117","117","117","124"]}};
for (var i=0; i<json.AppliedPrepaidBundle.id.length; i++) {
$('body').append("<li>AppliedPrepaidBundle id"+i+": "+json.AppliedPrepaidBundle.id[i]+'</li>');
}
for (var i=0; i<json.AppliedPrepaidBundle.prepaid_bundle_id.length; i++) {
$('body').append("<li>PrepaidBundleid"+i+":"+json.AppliedPrepaidBundle.prepaid_bundle_id[i]+'</li>');
}
for (var i=0; i<json.Device.id.length; i++) {
$('body').append("<li>Device id"+i+": "+json.Device.id[i]+'</li>');
}
Here is the fiddle
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);
});
i need display the child value, but it display [object, object] like that so
Here my code:
var jsonObj = {"department":{
"Title1":[
{"child1":"Green",
"child2":"Yellow"
},
{"child3":"Black",
"child4":"White"
}
],
"Title2":[
{"child5":"Violet",
"child6":"purple"
},
{"child7":"Pink",
"child8":"Orange"
}
]
}
}
$(document).ready(function() {
var treeList = "";
treeList = "<ul id=\"createTree\">";
for(var key in jsonObj){
for(var subKey in jsonObj[key]){
alert(subKey);
//for(i=0; i<jsonObj[key].length;i++ ) {
treeList += ("<li>" + subKey + "<ul><li>"+jsonObj[key][subKey]+"</li></ul></li>");
//var b = $(c).text();
alert(treeList);
}
}
treeList += "</ul>";
$('#tree').append(treeList);
});
As Quentin said you need to keep drilling down, first into the array then into the objects contained within the array. The code below should access all the variables held in the JSON, you might have to restructure the HTML it outputs to get it looking as you want -
$(document).ready(function() {
var treeList = "";
treeList = "<ul id=\"createTree\">";
for(var key in jsonObj){
for(var subKey in jsonObj[key]){
alert(subKey);
for(i=0; i<jsonObj[key][subKey].length;i++ ) {
for(var arrayKey in jsonObj[key][subKey][i]){
treeList += ("<li>" + subKey + " - " + arrayKey + " - "+jsonObj[key][subKey][i][arrayKey]+"</li></ul></li>");
}
//var b = $(c).text();
alert(treeList);
}
}
}
treeList += "</ul>";
$('#tree').append(treeList);
});
The first jsonObj[key][subKey] will be jsonObj.department.Title1. This is an array.
When you stringify an array, it will, by default, produce the generic "This is an object" text.
If you want to display the data in it, you will have to keep going down to get at the strings.