Debugging jquery .map that generates html - javascript

I'm trying to generate some rows and cells in a given table based on an object's key-value pairs.
As seen in the jQuery below, I'm trying to use .map to do this.
JavaScript object:
response = {
...
'details': {
'Email': employee.email_work,
'Slack': employee.username_slack,
}
}
jQuery:
$.map(response.details, function(key, val) {
$("#details-tbl").append([
$("td").addClass('detail-key').text(key),
$("td").addClass('detail-value-holder').append(
$("span").attr('data-resp', key).text(val)
)
]);
});
desired html:
<table id="details-tbl">
<tr>
<td class="detail-key">
"[KEY]"
</td>
<td>
<span class="detail-value" data-resp="[KEY]">
"[VAL]"
</span>
</td>
</tr>
</table>
The desired HTML is not showing up. There are no errors being thrown.
Can I use object keys as strings?

Related

How can I split the following string into an array that I can use to populate a html table

I have a string that looks like:
var str = '{ "abc": {
"decline_reason": "Business rule switched off"
},
"def": {
"decline_reason": "No response by interface"
},
"ghi": {
"decline_reason": "Requested incorrect size" }';
I would like to split that string into an array that I can use to populate a table on a webpage. I intend to use the initial reference ('abc'), with the reason ('Business rule switched off') on row 1, initial reference ('def'), with the reason ('No response by interface') on row 2, etc...
I have tried regex to break it down, and I've managed to find one that removes quotes, but not to break the string down.
I intend to populate the table with code like:
<table id="declinesTable">
<tr>
<th onclick="sortTable(0)">Reference Code</th>
<th>Decline Reason</th>
</tr>
<tr id="lender1">
<td id="lender1"><script>document.getElementById("lender1").innerHTML = declines[0];</script>
</td>
<td id="declineReason1"><script>document.getElementById("declineReason1").innerHTML = declines[2];</script>
</td>
</tr>
</table>
skipping out the value "decline_reason" from the table.
Any suggestions?
Couple of things - your string is missing a final }. Not sure where you're getting the string from, but it's in JSON format, so use JSON.parse to get it into an object, then iterate over the object to do something with each individual nested object. I would strongly recommend using a library like jQuery to help you append it to the table. You can google and very quickly find out how to add jQuery to your project. See below.
function stringParse(str) {
const json = JSON.parse(str);
const html = Object.entries(json).reduce((h, [k, v]) =>
h += `<tr><td>${k}</td><td>${v.decline_reason}</td></tr>`
, "");
$('#declinesTable').append(html);
}
const str = '{ "abc": {"decline_reason": "Business rule switched off"},"def": {"decline_reason": "No response by interface"},"ghi": {"decline_reason": "Requested incorrect size"}}'
stringParse(str);
<table id="declinesTable">
<tr>
<th>Reference Code</th>
<th>Decline Reason</th>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

Formatting data before render it

I am displaying some data in the view, but I need to formatted first, I was doing something like
val.toFixed(2) and that is OK, it works but the problem is that val sometimes comes with letters, and toFixed(2) is not taking that into account so is not displaying the letters.
So I need something that takes into account letters and numbers, the letters don't have to change, only the numbers which comes like 234235.345345435, and obviously I need it like this 234235.34.
Here is some of the code I am using
<table>
<tr>
<th ng-repeat='header in headers'>{{header.th}}</th>
</tr>
<tr>
<td ng-repeat='data in headers'>
<div ng-repeat='inner in data.td'>
<span ng-repeat='(prop, val) in inner'>{{val.toFixed(2)}}</span>
</div>
</td>
</tr>
</table>
and in the controller
$scope.LoadMyJson = function() {
for (var s in myJson){
$scope.data.push(s);
if ($scope.headers.length < 1)
for (var prop in myJson[s]){
prop.data = [];
$scope.headers.push({th:prop, td: []});
}
}
for (var s in $scope.data){
for (var prop in $scope.headers){
var header = $scope.headers[prop].th;
var data = myJson[$scope.data[s]][header];
$scope.headers[prop].td.push(data);
console.log($scope.headers[prop].td);
}
}
};
and I prepared this Fiddle
the way it is right now, is displaying the table properly, but as you see, the table is missing the name, it is because of the toFixed method.
So, what can I do ?
Create a custom filter to use on your template.
<table>
<tr>
<th ng-repeat='header in headers'>{{header.th}}</th>
</tr>
<tr>
<td ng-repeat='data in headers'>
<div ng-repeat='inner in data.td'>
<span ng-repeat='(prop, val) in inner'>{{val|formatValue}}</span>
</div>
</td>
</tr>
</table>
angular.module('whatever').filter('formatValue', function () {
return function (value) {
if (isNaN(parseFloat(value))) {
return value;
}
return parseFloat(value).toFixed(2);
}
});
You can try this :
That is a clean way to render formated data in view using angularjs as MVC
frontend framework :
Create a filter in your angular application.
Include your filter in your index.html.
use your filter like this : {{somedata | filterName}}
That is a simple angular filter to solve your problem, hope it will help you :
angular.module('app')
.filter('formatHeader', function() {
return function(data) {
if(angular.isNumber(data)) {
return data.toFixed(2);
}
return data;
}
});
And us it like this :
<table>
<tr>
<th ng-repeat='header in headers'>{{header.th}}</th>
</tr>
<tr>
<td ng-repeat='data in headers'>
<div ng-repeat='inner in data.td'>
<span ng-repeat='(prop, val) in inner'>{{val | formatHeader}}</span>
</div>
</td>
</tr>
You can take a look about these references :
angular functions
filter doc.
angular tutorials

How to ng-repeat array of an object in object?

I have this data:
{
"order":[
{
"id":1,
"table":1,
"foods":"{'foods':[{'id':2, 'name':'Nasi Minyak', 'qty':1}]}",
"drinks":"{'drinks':[{'id':1,'name':'Teh O Ais','qty':1}]}",
"waiter":"ali",
"foods_status":0,
"drinks_status":0,
"created_at":"2015-07-12T00:30:52.637Z",
"updated_at":"2015-07-12T00:30:52.637Z"
},
{
"id":2,
"table":2,
"foods":"{'foods':[{'id':2, 'name':'Nasi Goreng', 'qty':1}]}",
"drinks":"{'drinks':[{'id':1,'name':'Milo Ais','qty':1}]}",
"waiter":"abu",
"foods_status":0,
"drinks_status":0,
"created_at":"2015-07-12T00:51:43.552Z",
"updated_at":"2015-07-12T00:51:43.552Z"
}
]
}
I try to grab all foods name inside table like this:
<table class="table-bordered table table-striped">
<thead>
<tr>
<td>#</td>
<td>Name</td>
<td>Action</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="order in orders">
<td>{{order.id}}</td>
<td>{{order.foods.name}}</td>
<td>
<button class="btn btn-danger" ng-click="">Delete</button>
</td>
</tr>
</tbody>
</table>
And this is my $http.get to get the data:
$http.get("../api/orders")
.success(function(data) {
var order = data.order;
$scope.orders = order;
});
I managed to bind the id but I could't bind the name inside the foods array.
How to get the name inside the foods array of this data?
Plunker:
http://plnkr.co/edit/2oiOc06cZph4en8DJ18n
You need another ng-reapeat. Something like this:
<tr ng-repeat="order in orders">
<td>{{order.id}}</td>
<td>
<span ng-repeat="item in order.foods.foods">{{item.name}}/</span>
</td>
<td>
<button class="btn btn-danger" ng-click="">Delete</button>
</td>
</tr>
Another consideration is about the format of your JSON. this line:
"foods":"{'foods':[{'id':2, 'name':'Nasi Minyak', 'qty':1}]}"
the way it is, "foods" is holding a String, and not a Object. To make the ng-reapeat work, you will need to force JSON from string using
JSON.parse(jsonString);
or change your JSON to:
"foods":{"foods":[{"id":2, "name":"Nasi Minyak", "qty":1}]}
Side note, why repeat the keys "foods" and "drinks"? Doesn't seem logic to me. Change your data structure to:
"order":[
{
"id":1,
"table":1,
"foods":[{"id":1, "name":"Nasi Kerabu", "qty":1},{"id":2, "name":"Nasi Minyak", "qty":1}],
"drinks":[{"id":1,"name":"Sirap Ais","qty":1},{"id":2, "name":"Milo Ais", "qty":1}],
"waiter":"ali",
"foods_status":0,
"drinks_status":0,
"created_at":"2015-07-12T00:30:52.637Z",
"updated_at":"2015-07-12T03:30:35.684Z"
},
...
]
and use:
<td> <span ng-repeat="item in order.foods">{{item.name}}</span> </td>
Here is a plunker with these modifications:
http://plnkr.co/edit/UVvCVzh4hbsEwolyWpDs?p=preview
Here is a plunker that works http://plnkr.co/edit/snE9Em0tCKh0nUHIlTFn?p=preview.
Consider modifying your JSON file. Use double quotation marks instead of single quotation marks.
In your modified JSON file in your new plunker remove double quotations marks here "[{'id':1,
I have made some changes in your data and it fix the issue you are facing.
Here is plunker link
`http://plnkr.co/edit/nxBGMMyuNIzUOvQAu7YY?p=preview`
Each order would be an object like this:
{
"id":2,
"table":2,
"foods":"{'foods':[{'id':2, 'name':'Nasi Goreng', 'qty':1}]}",
"drinks":"{'drinks':[{'id':1,'name':'Milo Ais','qty':1}]}",
"waiter":"abu",
"foods_status":0,
"drinks_status":0,
"created_at":"2015-07-12T00:51:43.552Z",
"updated_at":"2015-07-12T00:51:43.552Z"
}
Note that foods points to an object, whose only key 'foods' points to an array... whose first component should be an object. However, if you read more closely:
"foods":"{'foods':[{'id':2, 'name':'Nasi Goreng', 'qty':1}]}",
Notice the double quotes surrounding foods's value? They mean that it points to a String instead of an object.
First, you need to delete the double quotes surrounding the values of both foods and drinks:
"foods":{'foods':[{'id':2, 'name':'Nasi Goreng', 'qty':1}]},
"drinks":{'drinks':[{'id':1,'name':'Milo Ais','qty':1}]},
And then replace all the single quotes with double ones, to make the object comply with the JSON object definition:
"foods":{"foods":[{"id":2, "name":"Nasi Goreng", "qty":1}]},
"drinks":{"drinks":[{"id":1,"name":"Milo Ais","qty":1}]},
Now, to get 'name', you need to access order.foods.foods[0].name instead of order.foods.name.

How to get html table values from multiple columns with single checkbox and submit to servlet?

I have html data table. I want to get values from multiple columns with single checkbox and when click on submit button values should go to servlet. Please help how to do this?
function refile(){
$('#resend').click(function() {
$("input:checked").each(function () {
var id = $(this).attr("id");
var messagePayload = $('#'+id).val();
var messageType = $('#msgType'+id).val();
alert("Payload Alert:"+ messagePayload);
alert("MessageType Alert:"+ messageType);
$.ajax({
type: "POST",
url: "http://localhost:8080/InterfaceMonitoring/ResendServlet",
data: {
messagePayload:messagePayload,
messageType:messageType
}
});
});
});
}
<c:otherwise>
<c:forEach items="${msgs}" var="msg" varStatus="count">
<tr id="check">
<td>
<input type="checkbox" id ="payloadMsg${count.index}" name="payload" value="${msg.messagePayload}">
</td>
<td></td>
<td>${msg.dob}</td>
<td></td>
<td>${msg.name}</td>
<td></td>
<td>
<div class="accordion">
<h3>Payload</h3>
<div id="payloadMsg${count.index}">${msg.messagePayload}</div>
</div>
</td>
<td></td>
<td>
<div id="msgType${count.index}">${msg.messageType}</div>
</td>
</tr>
</c:forEach>
</c:otherwise>
The problem is the way you try to get messageType.
Since you're using the ID of the input element, and prefixing it with #msgType it results in #msgTypepayloadMsgX so that element will never be found.
And since it's a DIV you're looking for you should use .html() to get the content.
Try adding data-index="${count.index}" to each input[checkbox] and get it in the script using $(selector).data('index') so that you can query for $('#msgType' + index)
And you should not make an ajax request for each row. Instead store the payloadMessage and messageType in an object and send it all to the backend at once, after iterating all rows.
An example could be:
Javascript
function refile(){
$('#resend').click(function() {
var payloads = [];
$('input:checked').each(function () {
var $this = $(this),
index = $this.data('index'),
$type = $('#msgType' + index);
payloads.push({
messageType: $type.html(),
messagePayload: $this.val()
});
});
if (payloads.length === 0) {
return;
}
$.ajax({
type: 'POST',
url: 'http://localhost:8080/InterfaceMonitoring/ResendServlet',
data: {
'payload': payloads
}
});
});
}
HTML
<tr id="check">
<td><input type="checkbox" id="payloadMsg${count.index}" data-index="${count.index}" name="payload" value="${msg.messagePayload}"></td>
<td></td>
<td>${msg.dob}</td>
<td></td>
<td>${msg.name}</td>
<td></td>
<td>
<div class="accordion">
<h3>Payload</h3>
<!-- Note that this ID is conflicting with the input#payloadMsg${count.index} -->
<div id="payloadMsg${count.index}">${msg.messagePayload}</div>
</div>
</td>
<td></td>
<td>
<div id="msgType${count.index}">${msg.messageType}</div>
</td>
</tr>
So, from what I've seen, on the front-end, at least, your code SHOULD work, but you've made it REALLY complex. . . . more complicated than you need it to be, I think. Again, while it should work, simplifying it will mean that there are much fewer places in the code where something could go wrong.
I think the best way to do this is make it easy on yourself:
flag the <div> elements that you want to retrieve with a class value that you can use to get their values (rather than relying on the unique IDs)
make the "unique" identifier of the message at the highest level in the table as you can (in this case, the <tr>
simplify your HTML attributes . . . you've got a lot of duplicate data and excess identifiers in your table structure. Try something like this:
HTML
<c:otherwise>
<c:forEach items="${msgs}" var="msg" varStatus="count">
<tr id="payloadMsg${count.index}">
<td>
<input type="checkbox" name="payload">
</td>
<td></td>
<td class="msg-dob">${msg.dob}</td>
<td></td>
<td class="msg-name">${msg.name}</td>
<td></td>
<td>
<div class="accordion">
<h3>Payload</h3>
<div class="msg-payload">${msg.messagePayload}</div>
</div>
</td>
<td></td>
<td>
<div class="msg-type">${msg.messageType}</div>
</td>
</tr>
</c:forEach>
</c:otherwise>
Once you've set that up, you have a much more simple structure, with all of the values that you could ever need, clearly identified. Now, you can pretty easily you can pretty easily get to the values that you need, using jQuery . . . just update your existing code to be something like this:
$(document).ready(function() {
$('#resend').click(function() {
$("input:checked").each(function () {
var currRow = $(this).closest("tr");
var currPayload = currRow.find(".msg-payload").text();
var currType = currRow.find(".msg-type").text();
alert("Payload Alert:"+ currPayload );
alert("MessageType Alert:"+ currType );
$.ajax({
type: "POST",
url: "http://localhost:8080/InterfaceMonitoring/ResendServlet",
data: {
messagePayload: currPayload,
messageType: currType
}
});
});
});
});
NOTE: You were using .val() instead of .text() to retrieve the text in the "type" <div> . . . .val() is only used with input elements.
Not knowing what you are doing on the back-end with this data, I can't really help you make sure that it is storing it correctly, but removing the reliance on the indexes to find the data that you want, should help simplify your logic a lot.
Also, if you ever want any other data from the row, you can capture it pretty easily now . . . for example:
var currMsg = currRow.attr("id");
var currDOB = currRow.find(".msg-dob").text();
var currName = currRow.find(".msg-name").text();
. . . after you have set the currRow value in your code, of course. :)
So, give that a try and see how things go. On the front-end, you should be good with this, at that point, you would need to just focus on the back-end and make sure that everything is working there.

Knockout.js, how to change a value of mapped two dimensional array?

I have a controller that returns two dimensional array of objects as json. I make a call from my javascript:
$.getJSON("/Game/GetBoard", function (json) {
data = json;
board = ko.mapping.fromJS({ board: data });
ko.applyBindings(board, $('.board')[0]);
});
I also have the following html:
<table>
<tbody data-bind="foreach: board">
<tr data-bind="foreach: $data">
<td data-bind="attr: { class: Color }"></td>
</tr>
</tbody>
</table>
It generates a nice 2 dimensional html table with nicely colored cells (based on a class that comes from a Color property). How can I now change this color to something else?
I tried: board[1][1]({Color: 'red'});, but I get an error saying that board[1] does not exist...
And another question, how can I add more than one class to the binding? I tried:
...
<td data-bind="attr: { class: Color + ' some-other-class' }"></td>
...
But then I get:
class="function b() { if (0 < arguments.length) { if (!b.equalityComparer || !b.equalityComparer(d, arguments[0])) { b.H(), d = arguments[0], b.G(); } return this; } r.T.Ha(b); return d; } some-other-class"
Is it a bug or am I doing something wrong?
The mapping plugin will turn your array into an observableArray and your properties into observables.
For your first case, you would need to unwrap the observable array by doing: board.board()[1][1]
For the other question, Color is an observable. If you are using it in an expression and want to get its value, then you need to do Color(). So, it would look like:
<td data-bind="attr: { class: Color() + ' some-other-class' }"></td>

Categories

Resources