I am trying to convert a JSON string into a knockout.js observable array.
Here is my js code:
$(document).ready(function(e){
var model = function(dat){
this.tabledata = ko.observableArray(dat);
};
$.ajax({
url: 'http://localhost:1141/rest_service/show_data',
type: 'GET',
success: function(msg){
// var dat = JSON.parse(msg);
alert(msg);
ko.applyBindings(new model(msg));
},
error: function(msg){
alert(JSON.stringify(msg));
},
});
});
and here is my html:
<table id = "example" >
<thead>
<tr>
<th>Employee ID</th>
<th>Employee Name</th>
<th>Employee Status</th>
<th>Date of birth</th>
<th>Age</th>
</tr>
</thead>
<tbody data-bind='foreach: tabledata'>
<tr>
<td data-bind='text: $parent.empId'/></td>
<td data-bind='text: $parent.empStatus'/></td>
<td data-bind='text:$parent.dob'/></td>
<td data-bind='text: $parent.empName'/></td>
<td data-bind='text: $parent.age'/></td>
</tr>
</tbody>
</table>
So here, after an ajax call, I am getting a JSON string as a response from the server and I want to bind this data to html table.
I tried using ko.mapping.fromJs() to convert the incoming JSON to an observable array but received the following error:
Error: The argument passed when initializing an observable array must be an array, or null, or undefined.
The JSON response is as follows:
[
{"empId":100,"empName":"TA","empStatus":"yes","dob":"2000-12-12","age":15},
{"empId":101,"empName":"TA","empStatus":"yes","dob":"2000-12-12","age":15},
{"empId":102,"empName":"TATA","empStatus":"yes","dob":"1997-12-12","age":18},
{"empId":103,"empName":"kljh","empStatus":"yes","dob":"2000-12-12","age":15},
{"empId":111,"empName":"Aria","empStatus":"No","dob":"1995-10-17","age":20}
]
How can I change my code so that the JSON string is converted properly into a Knockout.js observable array?
Do something like below
var json = [{"empId":100,"empName":"TA","empStatus":"yes","dob":"2000-12-12","age":15},{"empId":101,"empName":"TA","empStatus":"yes","dob":"2000-12-12","age":15},{"empId":102,"empName":"TATA","empStatus":"yes","dob":"1997-12-12","age":18},{"empId":103,"empName":"kljh","empStatus":"yes","dob":"2000-12-12","age":15},{"empId":111,"empName":"Aria","empStatus":"No","dob":"1995-10-17","age":20}]
var ViewModel = function() {
this.list = ko.observable(ko.mapping.fromJS(json)());
console.log(this.list());
};
ko.applyBindings(new ViewModel());
In view use $data instead of $parent as per your view structure .
working sample fiddle here
Related
i recently discover Knockout and i'm struggling for getting properties of an object in a foreach:
Here is my code :
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Created By</th>
</tr>
</thead>
<tbody data-bind="foreach: assets">
<tr class="assets" data-bind="click: $parent.detailPage">
<td>
<span data-bind="text: FileName"></span>
</td>
<td>
<span data-bind="text: CreatedBy"></span>
</td>
</tr>
</tbody>
and my script :
<script>
function ViewModel(assets) {
var self = this;
self.assets = assets;
self.detailPage = function (asset) {
location.href = '#Url.Action("Details", "Assets")/' + asset.Id;
};
};
var jsonModel = new ViewModel(#Html.Raw(Json.Encode(Model)));
var viewModel = ko.mapping.fromJS(jsonModel);
ko.applyBindings(viewModel);
In my assets, i have an id and i would like to open my view using the id of the object i click on.
But when i execute that, the url become : http://localhost:62677/Assets/Details/[object Object]
Any idee for doing this properly ?
Thanks !
Assuming that asset.Id is a knockout observable, try this
self.detailPage = function (asset) {
location.href = '#Url.Action("Details", "Assets")/' + asset.Id();
};
Looks like asset.Id is an object.
Try to investigate why it is object and not some number or string.
Below is the classical issue which I am facing during my app development.
I have an array of JSONObjects in my spring controller that I have to iterate in the jsp;
Also another status attribute called JSONArrayStatus is set that suggests if JSON array is empty or not.
Using jquery if JSONArray is empty I will show noDataImageDiv otherwise will show tableDIV (Binding the data from JSONArray using JSTL)
The problem I am facing is as below.
1. Edit a row in the table and click on Update. At this time I make an Ajax Call say, "UpdatedUser", which will return all the records along with the updated records. I could use refresh however thats not a recommended user experience and hence a no no.
To reflect the updated users in the table, I use jquery as below
clearing table rows table.clear().draw()
Loop the result set as follows.
redraw code
function reDrawExternalContactUsers(externalUsers) {
table.clear().draw();
var row = "";
$.each(externalUsers, function (i, field) {
row = '<tr><td></td><td></td><td class="edit">edit</td></tr>';
$("#tableDIV").append(row);
});
}
afetr this redraw or refresh process
This function is NOT working
$(".edit").click(function(){
});
This function is working
$("#tableDIV .edit").click(function(){
});
Suggest a better way of refreshing table rows, if any.
<div id="tableDIV">
<table id="tableID">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
if data exist
loop{
<tr>
<td></td>
<td></td>
<td class="edit">edit</td>
</tr>
} // loops ends
if close
</tbody>
</table>
</div>
<div id="noDataImageDiv"> No data image</div>
html code :
<div id="tableDIV">
<table id="tableID">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
if data exist
loop{
<tr>
<td class="user-name"></td>
<td></td>
<td class="edit" data-user-id="">edit</td> //set user_id in attr data-user-id
</tr>
} // loops ends
if close
</tbody>
</table>
</div>
<div id="noDataImageDiv"> No data image</div>
jquery code :
you should use click event on document
$(document).on('click', '.edit', function () {
var btn = $(this);
var user_id = btn.attr("data-user-id"); //user_id of user will update
// extra user data
$.ajax({
method: "POST",
url: url,
data: {
'id': id,
// extra data to send
},
success: function (data) {
if (data.status) // successfully user updated
{
var user = data.user;
/* you can set user data like this */
btn.closest('tr').find('.user-name').html(user.name);
}
}
});
});
I am getting json.stringyfy data and want to append all json.stringyfy data to table,with each tr editable but I don't know that much part of jquery so unable to get any idea can anyone tell me what should do to achieve this?
Json data got in response
[{"id":"1","name":"abc"}, user id 1 data
{"id":"2","name":"def"}, user id 2 data
{"id":"3","name":"xyz"}, user id 3 data
{"id":"4","name":"aaa"}] user id 4 data
Ajax call with success function to handle stringyfy data
$.ajax({
url: "<?= base_url('Test_controller/show_user') ?>",
type: 'POST',
data: {
},
success: function (response) {
var myJSON = JSON.stringify(response);
// code Here to append data in table one by one with content editable tr
}
});
Html table
<table class="show_data">
<tr>
<th>User id</th>
<th>User name</th>
</tr>
</table>
Just take your data and append it to the table. Loop through each entry in your data and (if using jquery) do .append(). I just create a simple variable with your json but you can do this with your myJSON variable inside of the success function.
var data = [{"id":"1","name":"abc"},
{"id":"2","name":"def"},
{"id":"3","name":"xyz"},
{"id":"4","name":"aaa"}]
data.forEach(user => {
$('.show_data').append(`<tr><td>${user.id}</td><td>${user.name}</td></tr>`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="show_data">
<tr>
<th>User id</th>
<th>User name</th>
</tr>
</table>
Edit
You are getting that in error because you are using JSON.stringify which makes your json a string. You can't iterate on a string. Just use response instead of JSON.stringify(response);
You may use jQuery.each() and build elements on the fly:
var myJSON = [{"id": "1", "name": "abc"},
{"id": "2", "name": "def"},
{"id": "3", "name": "xyz"},
{"id": "4", "name": "aaa"}];
$.each(myJSON, function (idx, ele) {
$('.show_data tbody').append(
$('<tr/>') // create a TR
.append($('<td/>', {text: ele.id})) // append the first TD
.append($('<td/>', {text: ele.name})) // append the second TD
);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="show_data">
<thead>
<th>User id</th>
<th>User name</th>
</thead>
<tbody>
</tbody>
</table>
JSP file
<div class="container">
<table id="headerTable" class="table table-bordered">
<thead>
<tr>
<th colspan="2">Header</th>
</tr>
</thead>
<tbody>
<c:forEach items="${headerList}" var="field">
<tr>
<th>${field}</th>
<td><input id="${field}" type="text" class="form-control "></td>
</tr>
</c:forEach>
</tbody>
</table>
Javascript
$('#parseBtn').click(function() {
var parseMsg = $('#msgText').val();
alert("parse message is " + parseMsg);
$.ajax({
type: "GET",
url: "/parseMessage",
data: {
"msg": parseMsg
},
success: function(data) {
//data format looks like Object {SubsystemChannel: "F", MessageNumber: "200257", DebugQueue: " ", WorkStationNumber: "023", FrontEndNumber: "0000"…}
$('#headerTable input').each(function() {
var id = $(this).attr('id');
var field = data.id;
$(this).val(field);
});
}
});
});
What I am going to do is, go through the $('#headerTable input'), set the value(from data) in it. So, I get the each input id first, then get the value from data using id, but it failed.... Could you help me on this? thank you very much
You should use Bracket notation instead of dot notation to access properties using id variable
$('#headerTable input').each(function () {
var field = data[$(this).attr('id')];
$(this).val(field);
});
I would like to know how I can do order data from API pre-date very time.
How its should be:
<table>
<tr>
<th>2017-02-17</th>
</tr>
<tr>
<td>some date</td>
<td>some date</td>
<td>some date</td>
</tr>
<tr>
<th>2017-02-15</th>
</tr>
<tr>
<td>some date</td>
<td>some date</td>
<td>some date</td>
</tr>
</table>
example:
URL API: http://api.tradingeconomics.com/calendar?c=guest:guest
My code:
$.ajax({
url: "url",
type: "Get",
datatype: "JSON",
contentType: "application/json",
error : function (data) { console.log("error:" + data) },
success: function (response) {
response.forEach(function (data) {
$('.top_table').append(
"<tr>" +
"<th>DATE</th>" +
"</tr>" +
"<tr id='content'>" +
"<td>some text....</td>" +
"<td>some text....</td>" +
"<td>some text....</td>" +
"<td>some text....</td>" +
"</tr>"
);
});
console.log(response);
}
});
But its print like:
date
result
date
result
How I can do it?
I don't know if I've understood your question very well, but I think that could give you some tips.
Your API returns an Array of Objects if you make and Ajax GET request, so you can order this Array before inserting the content into the DOM:
The next example order the data in descending order comparing the Date parameter, there is another date parameter called LastUpdate, I don't know if you want to use it in your logic.
$.get("https://api.tradingeconomics.com/calendar?c=guest:guest", function (data) {
//---Order the array received from the server
data.sort(function (a, b) {
return (new Date(a.Date)) - (new Date(b.Date));
});
//---The data is ordered, you can insert it into the DOM
});
In the other hand, your code inserts a row with the header content and a row with the body content in each iteration, this is not correct. You need to add all the header texts in a single row and each item of the Array needs to be inserted in separated rows.
Here you have a working example to give you an idea of the process:
https://jsfiddle.net/elchininet/ym8qp415/
EDIT: Seeing your comments, I understand now that you want to grouping the data not just ordering it. I recommend you to use the reduce method of the Array class to create a new data separated by dates and after that you can insert the data in the table:
var regdate = /^(\d{4}\-\d{2}\-\d{2})T(\d{2}:\d{2}:\d{2})$/;
//---Sort the data from the server
data.sort(function (a, b) {
return (new Date(a.Date)) - (new Date(b.Date));
});
var group = data.reduce(function (before, current) {
var day = current.Date.replace(regdate, "$1");
var hour = current.Date.replace(regdate, "$2");
if (!before[day]) {
before[day] = [];
}
current.Hour = hour;
before[day].push(current);
return before;
}, {});
//---The data is ordered and grouped, you can insert it into the DOM
Working example with fake data (Because of the example in the API returns only one day):
http://jsfiddle.net/elchininet/nvv4fnon/
Without a plugin, this is going to be difficult to achieve unless the "calendar" information is pulled from a database, it may be worth sorting in PHP, loading and displaying the data in jQuery
<script type="javascript">
$(function() {
$("BODY").on("click", "TH[data-orderby]", function() {
var order = $(this).data("orderby") || "date";
var parent = $(this).parents("table").parent();
$.ajax({
url: 'calendar?c=guest:guest',
data: 'order-by=' + URLEncode(order),
type: 'POST',
success: function(response) {
parent.html(response);
},
error: function(event, request, settings) {
console.warn("Ajax Error", request);
}
})
});
});
</script>
<div class="parent">
<table>
<thead>
<tr>
<th>Heading</th>
<th data-orderby="date">Date</th>
<th>Title</th>
<th data-orderby="last_updated">Last Updated</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
</tbody>
</table>
Because we use $("BODY").on("click", "TH[data-orderby]"), even when the data is reloaded from the server, the sort functionality will remain.
I hope this helps.