I am new to AJAX/JQuery/JSON, I am using Struts 2 to get a JSON object using AJAX, I can see the object returned but I am unable to iterate over it. The returned object is a list that has just one object(may contain more objects), also every object contains a list of some other object.
This is how the js file looks like:
$.getJSON('GetAllSaleItemsAction', {
customerName : debtorSelection
}, function(jsonResponse){
//alert(jsonResponse);
//populate table
var trHtml = '';
//$("tr:has(td)").remove();
jsonResponse = jsonResponse.saleItemsList;
var responseString = JSON.stringify(jsonResponse);
console.log(responseString);
$.each(jsonResponse, function(i, item) {
var saleEntries = $.parseJSON(item.singleSaleEntries);
var saleEntriesString = JSON.stringify(saleEntries);
console.log(saleEntriesString);
var sseString = '';
$.each(saleEntries, function(n, sse){
sseString += sse.item + ' ' + sse.quantity + ' x ' + sse.price + ' = ' + sse.amount;
});
trHtml+= '<tr><td>' + item.date + '</td><td>' + sseString + '</td><td>' + item.saleAmount + '</td><td>' + item.interest + '</td><td>' + item.totalAmount + '</td></tr>';
});
if(trHtml != ''){
$('#saleRecordTable').append(trHtml);
}
});
Here the first console.log is executed but not the second console.log as javascript inside the each-function is not executed:
[{"customerName":"Tester","date":"2015-02-16T17:36:19","debtorId":1,"interest":0,"saleAmount":14000,"saleId":3,"singleSaleEntries":[{"amount":9000,"item":"DAP_50KG","price":900,"quantity":10,"saleEntry":null,"singleSaleId":4},{"amount":5000,"item":"UREA_50KG","price":500,"quantity":10,"saleEntry":null,"singleSaleId":5}],"totalAmount":14000}]
Please guide me.
The issue was with var saleEntries = $.parseJSON(item.singleSaleEntries);
After changing this statement to var saleEntries = item.singleSaleEntries;
everything works fine, the problem was that the debug point was set to next statement and because of error in this line, the control was never reaching there.
Related
I am using a WebGrid to allow CRUD on my database (using MVC and EF entities). The grid works and filters they way I want it to. There are two columns that use dropdowns to display a value tied to another table (Projects and People) and these both work well for edits/ updates. I am using JQuery for an add new row and want the new row to have select fields like the grid does (so that the user can just find the person by name instead of having to enter the ID for example). I am referencing this post from another similar question, but when I implement the code I get a syntax error that I'm having trouble understanding.
Here is my scripting on the view side that shows my failed attempt. I'm creating an array from the project repository (Text is the name of the project and Value is the ID field), and populating it with the model values: Model.Projects, and then in the add row function I want to loop through the array to add in the options.
<script type="text/javascript">
var ProjectArray = new Array();
#foreach (var proj in Model.projects)
{
#:ProjectArray.push(Text: "#proj.Text", Value: "#proj.Value");
}
</script>
<script type="text/javascript">
$(function ()
{
$('body').on("click", ".add", function () {
var SelectedProject = "#Model.ProjectID";
var newRow = $('.save').length;
console.log('newRow = ' + newRow);
if (newRow == 0) {
var index = "new"+$("#meetingList tbody tr").length + 1;
var ProjectID = "ProjectID_" + index;
var Date = "Date_" + index;
var Attendees = "Attendees_" + index;
var Phase = "Phase_" + index;
var PeopleID = "PeopleID_" + index;
var Save = "Save _" + index;
var Cancel = "Cancel_" + index;
var tr = '<tr class="alternate-row"><td><span> <input id="' + ProjectID + '" type="select"/></span></td>' +
#* This is where I use the array to add the options to the select box*#
ProjectArray.forEach(function (item) {
if (item.Value == SelectedProject) { '<option selected="selected" value="' + item.Value + '">' + item.Text + '</option>' }
else { '<option value="' + item.Value + '">' + item.Text + '</option>' }
+
});
---remaining script omitted----
'<td><span> <input id="' + PeopleID + '" type="text" /></span></td>' +
'<td><span> <input id="' + Date + '" type="date" /></span></td>' +
'<td><span> <input id="' + Attendees + '" type="text" /></span></td>' +
'<td><span> <input id="' + Phase + '" type="text" /></span></td>' +
'<td> SaveCancel</td>' +
'</tr>';
console.log(tr);
$("#meetingList tbody").append(tr);
}
});
I am not sure how to parse the error, but the page source looks like this when creating my client side array:
var ProjectArray = new Array();
ProjectArray.push(Text: "Select Project", Value: ""); //<-- ERROR HERE:
ProjectArray.push(Text: "010111.00", Value: "74");
ProjectArray.push(Text: "013138.00", Value: "2");
So the model getting into the client side works (the text and value pairs are correct), but the error I get is for the first array.push line: missing ) after the argument list. I have played with moving this code block around, putting it in a separate <script> tag and the error likewise follows it around, always on the first array.push line. And regardless of where it is, the rest of my script functions no longer work. I think it must be something silly but I just am not seeing what I'm doing wrong.
The option list does not populate into something I can ever see, it just renders out on the page source as the javascript loop:
var tr = '<tr class="alternate-row"><td><span> <input id="' + ProjectID + '" type="select"/></span></td>' +
ProjectArray.forEach(function (item) {
if (item.Value == SelectedProject) { '<option selected="selected" value="' + item.Value + '">' + item.Text + '</option>' }
else { '<option value="' + item.Value + '">' + item.Text + '</option>' }
+
}); //-- Unexpected token here
And with the push array in its separate script block I get a second error that the last } is an unexpected token. This is some javascripting error I'm sure. But where it is an how to do this are beyond me right now.
I'm not used to javascript, and poor syntax leads to the vague errors I was getting. The first problem was fixed by adding the { . . . } around the array values. Then I created a function to create the arrays I need for people and projects as well as a function to take an array and create the option list to clean up the view code:
function createProjectArray() {
var ProjectArray = new Array();
#foreach (var proj in Model.projects)
{
if (proj.Value != "") {
#:ProjectArray.push({ Text: "#proj.Text", Value: "#proj.Value" });
}
}
return ProjectArray;
}
function createPeopleArray() {
var PeopleArray = new Array();
#foreach (var person in Model.people)
{
if (person.Value != "") {
#:PeopleArray.push({ Text: "#person.Text", Value: "#person.Value" });
}
}
return PeopleArray;
}
function SelectOptionsString(MyArray, SelectedValue) {
console.log(MyArray);
var OptionsList = "";
MyArray.forEach(item => {
if (item.Value == SelectedValue) { OptionsList += '<option
selected="selected" value="' + item.Value + '">' + item.Text + '</option>'; }
else { OptionsList += '<option value="' + item.Value + '">' + item.Text
+ '</option>'; }
})
return OptionsList;
}
Taking this approach allowed me to more easily parse the code and find the syntax errors. The Array.forEach syntax was an interesting hurdle, and this site helped me test out my syntax to eventually get it working as above.
So the server creates the javascript lines to create the array, and then I use the array to create my dropdown options list. This cleans up the add row function code nicely:
$('body').on("click",".addrow", function() {
var SelectedProject = "#Model.ProjectID";
var ProjectArray = createProjectArray();
var ProjectOptions = "";
ProjectOptions = SelectOptionsString(ProjectArray, SelectedProject);
var PeopleArray = createPeopleArray();
var PeopleOptions = "";
PeopleOptions = SelectOptionsString(PeopleArray, "");
var tr = '<tr class="alternate-row"><td><span> <select id="' +
ProjectID + '>' + ProjectOptions + '</select></span></td>' +
'<td><span> <select id="' + PeopleID + '>' + PeopleOptions +
'</select></span></td>' + '</tr>'
$("#myWebGrid tbody").append(tr);
});
And it also allows for some potential code reuse.
Through ajax response I'm passing array data from controller to blade.
On Ajax success I'm looping through array with 2 elements and concatenating string to display later on in my bootstrap popover.
success: function (data) {
var content = "";
var num = 1;
for (var i = 0; i < data.length; i++) {
content = content.concat(num + "." + " " + data[i]);
num++;
}
$("#content").popover({content: content});
}
Result:
I would like to add new line, so that each item or "artikel" would be displayed in new line e.g. :
1.Artikel...
2.Artikel...
I tried to add "\n" (as below) or html break but nothing works, it only appends as string.
content = content.concat(num + "." + " " + data[i] + "\n");
Use this:
content.concat(num + "." + " " + data[i] + "<br/>");
And this:
$("#content").popover({ html:true, content: content });
I am seeking help trying to add a new table in my third function called ingredients. I am not very familiar with javascript so I tried to duplicate code from newDosage which is similar to what I need to do. Unfortunately, right now all I see is 0, 1, or 2 and not the actual text from the ingredient table. If anyone can help me correctly call the table, it would be greatly appreciated. Thank you.
Below is my code. The first function pulls the database, the second function uses the results and the third function is where I have tried to add the ingredient table.
function listTreatmentDb(tx) {
var category = getUrlVars().category;
var mainsymptom = getUrlVars().mainsymptom;
var addsymptom = getUrlVars().addsymptom;
tx.executeSql('SELECT * FROM `Main Database` WHERE Category="' + category +
'" AND Main_Symptom="' + mainsymptom + '" AND Add_Symptom="' + addsymptom + '"',[],txSuccessListTreatment);
}
function txSuccessListTreatment(tx,results) {
var tubeDest = "#products";
var len = results.rows.length;
var treat;
for (var i=0; i < len; i = i + 1) {
treat = results.rows.item(i);
$("#warning").append("<li class='treatment'>" + treat.Tips + "</li>");
$("#warning-text").text(treat.Tips);
$('#warning').listview('refresh');
//console.log("Specialty Product #1: " + treat.Specialty1);
if(treat.Specialty1){
$("#products").append(formatProductDisplay('specialty1', treat.Specialty1, treat.PurposeSpecialty1, treat.DosageSpecialty1, '1'));
}
if(treat.Specialty2){
$("#products").append(formatProductDisplay('specialty2', treat.Specialty2, treat.PurposeSpecialty2, treat.DosageSpecialty2, '0'));
}
}
}
function formatProductDisplay(type, productName, productPurpose, productDosage, Ingredients, aster){
var newDosage = productDosage.replace(/"\n"/g, "");
if(aster=='1'){ productHTML += "*" }
productHTML+= "</div>" +
"</div>" +
"<div class='productdose'><div class='label'>dosage:</div>" + newDosage + "</div>" +
"<div class='productdose'><div class='label'>ingredients:</div>" + Ingredients +
"</div></li>"
return productHTML;
}
You are missing an argument when you call formatProductDisplay(). You forgot to pass in treat.Ingredient.
Change:
$("#products").append(formatProductDisplay('specialty1', treat.Specialty1, treat.PurposeSpecialty1, treat.DosageSpecialty1, '1'));
To:
$("#products").append(formatProductDisplay('specialty1', treat.Specialty1, treat.PurposeSpecialty1, treat.DosageSpecialty1, treat.Ingredients, '1'));
Also do the same thing to the similar 'Specialty2' line right below it.
I have a method called refreshHistory() that basically reads locally stored list of json (using https://github.com/marcuswestin/store.js/) and populates a list in the order they were stored at.
Everytime a user action happens, this method is called. But as the list gets bigger and bigger, it slows down the browser to a crawl.
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? 0 : store.get('history').history;
;
if (records == 0) {
$('#content #historyView').html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
$('#qtip-0-content #historyView').html(xhistory);
}
}
Rendering everything on every event is a simple strategy, which is good, but it does run into the performance problems you are describing. It's hard to give specific advice, but you could either:
Implement a more detailed rendering logic, where only new items are rendered and added to the DOM.
Use ReactJs or Virtual DOM libraries, which allow your code to use the render everything pattern, but make the actual updates to the DOM faster by doing the minimum needed.
The only way to really make this efficient is to implement it in a different way.
I've been using knockout.js personally and am very happy with it. Basically you write a template and the library handles the DOM node changes, only updating the parts needed. You will need to learn how to think slightly differently, but there are some great tutorials available.
That said, one simple trick you can try is move the selectors outside the function so they are only ran once instead of each time you call the function.
For sanity I would also keep records variable the same type whether or not the .get('history') returns undefined.
var contentHistoryView = $('#content #historyView');
var qtipHistoryView = $('#qtip-0-content #historyView');
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? [] : store.get('history').history;
if (records.length) {
contentHistoryView.html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
qtipHistoryView.html(xhistory);
}
}
I doubt this will have a huge impact though, as I suspect most of the execution time is spent in the loop.
Basically this is supposed to find the values in specific columns of the row and add them together to get a total and place that total in the cell specified. It is not working for some reason.
function rating(Irange,Q,Y,AG,AO,AW,BE,BM) {
var sheet = SpreadsheetApp.getActiveSheet();
var values = sheet.getDataRange().getValues();
var range = sheet.getRange(Irange);
var row = Irange.getRow();
var total = Number(values[row][8]) +
Number(values[row][9]) +
Number(values[row][10]) +
Number(values[row][11]) +
Number(values[row][16]) +
Number(values[row][17]) +
Number(values[row][18]) +
Number(values[row][19]) +
Number(values[row][24]) +
Number(values[row][25]) +
Number(values[row][26]) +
Number(values[row][27]) +
Number(values[row][32]) +
Number(values[row][33]) +
Number(values[row][34]) +
Number(values[row][35]) +
Number(values[row][40]) +
Number(values[row][41]) +
Number(values[row][42]) +
Number(values[row][43]) +
Number(values[row][48]) +
Number(values[row][49]) +
Number(values[row][50]) +
Number(values[row][51]) +
Number(values[row][56]) +
Number(values[row][57]) +
Number(values[row][58]) +
Number(values[row][59]) +
Number(values[row][64]) +
Number(values[row][65]) +
Number(values[row][66]) +
Number(values[row][67]);
return total;
}
It looks odd that you're doing
var range = sheet.getRange(Irange);
...and then not using that range for anything. Instead, on the next line, you have:
var row = Irange.getRow();
I haven't done virtually anything with Google Docs Spreadsheets, but perhaps that should be range.getRow() (no I), since Range objects have a getRow method. (Naturally I have no idea what your Irange argument is, but it looks like you're using it as a string when calling getRange(a1Notation)).