render java script object on html page - javascript

I want to render data object in the body as a table with three columns
one for the key like "ASIANPAINT24JUN21FUT"and other two for the links
I don't have any experience with javascript, I tried using renderjson to render the
json object received, but it renders just plain text,
I want to render the object as a table, and the links in it should be clickable
How can I achieve this?
index.html
<body>
// render data object here
<script>
var eventSource = new EventSource("/listen")
eventSource.addEventListener("message", function(e) {
console.log(e.data)
}, false)
eventSource.addEventListener("online", function(e) {
let data = JSON.parse(e.data)
}, true)
</script>
</body>
data object
{
"ASIANPAINT24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:ASIANPAINT1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/ASIANPAINT21JUN2980CE/15044354"
],
"DEEPAKNTR24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:DEEPAKNTR1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/DEEPAKNTR21JUN1820CE/20372738"
],
"DRREDDY24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:DRREDDY1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/DRREDDY21JUN5350CE/20732162"
],
"ESCORTS24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:ESCORTS1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/ESCORTS21JUN1220CE/20892674"
]
}

You can use following code to display the data in HTML.
<body>
<div id="table-div"></div>
<script>
let data = {
"ASIANPAINT24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:ASIANPAINT1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/ASIANPAINT21JUN2980CE/15044354"
],
"DEEPAKNTR24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:DEEPAKNTR1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/DEEPAKNTR21JUN1820CE/20372738"
],
"DRREDDY24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:DRREDDY1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/DRREDDY21JUN5350CE/20732162"
],
"ESCORTS24JUN21FUT": [
"https://in.tradingview.com/chart/?symbol=NSE:ESCORTS1!",
"https://kite.zerodha.com/chart/ext/tvc/NFO-OPT/ESCORTS21JUN1220CE/20892674"
]
}
let tableDiv = document.getElementById("table-div");
let tableRows = "";
Object.keys(data).map(key => {
tableRows += `
<tr>
<td>${key}</td>
<td>${data[key][0]}</td>
<td>${data[key][1]}</td>
</tr>
`
})
tableDiv.innerHTML = `
<table>
<tr>
<th>Key</th>
<th>Link 1</th>
<th>Link 2</th>
</tr>
${tableRows}
</table>`
</script>
</body>

to do this you should modify the dom using javascript, here the documentation about html5 tables https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table, about links https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a, and i am pretty sure you will also need this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys, using this and some kind of bucle like a foreach, a map or a for, you can access the object info in a dynamic way, also if you need it you have some documentation about dom manipulation https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction, maybe you also find useful methods like document.getElementById

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>

Use JsRender to create a row/column layout from simple array data

I am using jsrender to write a bootstrap based HTML template and render the HTML content using javascript. My data is as follows
var data = [
{
'img': 'img/books/kiterunner.jpg',
'title': 'The Kite Runner',
'authors': 'Khaled Hosseini'
},
{
'img': 'img/books/tokillamockingbird.jpg',
'title': 'To Kill A Mocking Bird',
'authors': 'Harper Lee'
},
{
'img': 'img/books/hungergames.jpg',
'title': 'The Hunger Games',
'authors': 'Suzanne Collins'
}
.....
]
And the corresponding HTML I want to generate is as follows
<div class="row-fluid" id="result">
<script id="template" type="text/x-js-render">
<div class="col-md-3 col-sm-6">
<div class="image-tile outer-title text-center">
<img alt="{{:title}}" src="{{:img}}" style="max-height:350px;">
<div class="title mb16">
<h5 class="uppercase mb0">{{:title}}</h5>
<span>{{:authors}}</span>
</div>
</div>
</div>
</script>
</div>
Currently each object in data gets displayed individually but sometimes, the images are larger in size and disrupt the way the row looks. So I want to repeat the div.row-fluid creation with the content after every 4 objects from data. I currently do the following to register the template and render the data into the required HTML. I can't seem to figure out how to use {{for}} without changing the values in data.
var template = $.templates("#template");
var htmlOutput = template.render(data);
$("#result").html(htmlOutput);
Thank you.
Edit: I have managed to do this by doing explicit HTML string concatenation and then rendering them while using index%4 in the if statements to decide on whether the div.row-fluid needs to be created. However, I would really like a more elegant solution. Adding jquery tag for wider visibility.
You could use a custom {{range}} tag - see this sample.
Here is an example which renders into a table with <td>s grouped by four - for a four column layout:
<script id="myTmpl" type="text/x-jsrender">
<table>
{{for rows ~last=rows.length-1}}
{{if #index%4===0 ~ind=#index}}
<tr>
{{range ~root.rows start=~ind end=~ind+3 max=~last}}
<td>{{:title}}</td>
{{/range}}
</tr>
{{/if}}
{{/for}}
</table>
</script>
using this version of a custom {{range}} tag:
$.views.tags("range", function(array) {
var ret = "",
start = this.tagCtx.props.start,
end = this.tagCtx.props.end,
max = this.tagCtx.props.max;
end = end > max ? max : end;
for (var i = start; i <= end; i++) {
// Render tag content, for this data item
ret += this.tagCtx.render(array[i]);
}
return ret;
});
var data = {rows: [
{
'title': ...
},
...
]};
...

Knockout foreach binding not rendering anything

I have, what I thought was a fairly straightforward knockout situation. I have a model that comes in from WebApi that has an array of things with a Success element. I need the value of success to determine what of the properties render. I've validated that all the data is coming down from WebApi ok but nothing but the table shell renders. There are no errors in the dev console.
The HTML
<div id="model1Wrapper">
<table class = "table">
<thead >
<tr >
<th >Stuff</th><th>Things</th>
</tr>
</thead>
<tbody data-bind = "foreach: $data.historyArray" >
<!--ko if: Success -->
<tr class = "success" >
<td data-bind = "text: $data.ThingA" > </td>
<td data-bind = "text: ThingB" > </td>
</tr>
<!-- /ko -->
<!--ko ifnot: Success -->
<tr class = "danger" >
<td colspan="3" data-bind = "text: ThingC" > </td>
</tr>
<!-- /ko -->
</tbody>
</table>
</div>
Example Model Data
[{
"ThingA": "A",
"ThingB": "B",
"ThingC": "C",
"Success": false
}, {
"ThingA": "A",
"ThingB": "B",
"ThingC": "C",
"Success": true
}]
This is monitoring a process that has feeds from several endpoints so I have multiple ViewModels on the page. So I framed up a rough example of how that is working elsewhere on the page.
That business
<script>
var sampleModelData = [{
"ThingA": "A",
"ThingB": "B",
"ThingC": "C",
"Success": false
}, {
"ThingA": "A",
"ThingB": "B",
"ThingC": "C",
"Success": true
}]
var viewModel1 = {
historyArray: ko.observableArray()
};
function onNewHistory(data) {
viewModel1.historyArray(data);
}
$(document).ready(function(){
ko.applyBindings(viewModel1, document.getElementById("model1Wrapper"));
onNewHistory(sampleModelData);
})
</script>
I had to mask of some of the speciffics but the gist is, the ajax call returns an array in the example. There is a function that is called to update the new data into the observable and I would expect the table to rerender, it does not.
Other deets
Sometimes there is no model data in the table so I load it and wait
for an update. All the other Viewmodels are loaded like this but this
is the only one with an array and the only one I'm having trouble
with.
I have tried taking out the if/ifnot business and that does not work.
Fiddler hates me and I have not been able to set up a clean version of this to try.
I leafed though some of the related questions and nothing seems to fit my issue. Or the example is much more complicated to apply.
Thanks!
The problem is in this code:
var viewModel1 = {
historyArray = ko.observableArray();
}
You're mixing the syntax for declaring objects with the syntax for code inside functions. When declaring an object, don't use = and ;. Instead use : and ,.
If you change the declaration to something like below, it should work.
var viewModel1 = {
historyArray: ko.observableArray()
}
Just adding another answer to this question in case someone comes across it in future. I had this issue and it was a result of initialising my observable array within the method. I didn't mean to do this (copy paste error) and it didn't produce any errors in the console so was difficult to trace.
For example:
LoadJSArrayIntoObservable(results) {
vm.validationResults = ko.observableArray(); <---- THIS IS INVALID.
vm.validationResults([]); <---- THIS IS WHAT I MEANT TO DO!!
$.each(results, function () {
try {
vm.validationResults.push(new ValidationResult(this));
}
catch (err) {
alert(err.message);
}
});

Customizing DataTables with WEB API OData service for filtering EF - column search not working

I am using DataTables on the client side and ASP.NET WEB API OData queryable service on the server side. The issue with sorting and filtering DataTable columns on the server side is that DataTables are generating that awful super long request with all columns info, even when they are not used for sorting or filtering. I've decided to write custom AJAX call from client to server to create neat odata query, that can be applied easily to EF context. Unfortunately column searching fields have stopped rendering as a inputs. What can be the issue?
JavaScript and HTML code:
$(document).ready(function() {
var options = new Object();
options.searching = true;
options.searchable = true;
options.aoColumns = [{
"sName": "USER_NAME",
"searchable": true
}];
options.bProcessing = true;
options.bServerSide = true;
options.sAjaxSource = "http://localhost/api/list";
options.fnServerData = function(sSource, aoData, fnCallback) {
var filter = "$top=5"; //just as example
$.getJSON(sSource, filter, function(json) {
fnCallback(json);
});
}
$('#myTable').dataTable(options);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js"></script>
<table id="myTable" class="table">
<thead>
<tr>
<th>
First Name
</th>
...
</tr>
</thead>
<tfoot>
<tr>
<th>
First Name
</th>
...
</tr>
</tfoot>
</table>
The service works fine, and looks like this (I've made this code as easy to understand as possible).
C# code:
public HttpResponseMessage List(ODataQueryOptions<User> options)
{
var result = oDataQueryOptions.ApplyTo(_context.Users) as IEnumerable<User>;
JQueryJsonResponse jsonUserResult = new JQueryJsonResponse
{
Draw = xxx,
iTotalRecords = xxx,
iTotalDisplayRecords = xxx,
aaData = result.ToList()
};
return Request.CreateResponse(HttpStatusCode.OK, jsonUserResult);
}
I would expect something like this:
But I get this:
CAUSE
You have server-side processing mode enabled with options.bServerSide = true;. In server-side processing mode filtering, paging and sorting calculations are all performed by a server.
SOLUTION
You need to handle parameters sent by the client on the server and perform filtering, paging and sorting. See full list of parameters sent in server-side processing mode.
Alternative solution is to disable server-side processing mode with options.bServerSide = false; and let DataTables perform filtering, paging and sorting on the client side.
OK, the question is not well formed, sorry. What I meant, that I want to apply column search to my datatables. During the copy-paste phase from other table I just missed some lines of code.
I've added something like this, and now it's working!
// Setup 'Search'
var filterSelector = '#myTable' + ' tfoot th';
$(filterSelector).each(function() {
var searchbox = $(this);
searchbox.html('<input type="text" class="form-control" placeholder="Search" />');
});
//Apply DataTables
var table = $('#myTable').DataTable(options);
$('.dataTables_filter input').attr("placeholder", "Search");
// Apply generic search
table.columns().every(function() {
var that = this;
var thatFooter = $('input', this.footer());
thatFooter.on('keyup change', function() {
that.search(this.value).draw();
});
});

how I get the values of each row and column of a html table in c# codebehind which are dynamically generated by angularjs ng-repeat

I have a html table. the rows of this table are generated automatically by aangular js ng-repeat. I want to get values of each row and column of that table in c# codebehind.
Here is my aspx code:
<table id="stockTable" runat="server" class="table table-bordered">
<thead>
<tr>
<td>Name</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="aMedicine in medicines">
<td>{{aMedicine.Name}}</td>
<td>{{aMedicine.Quantity}}</td>
</tr>
</tbody>
</table>
and script is here:
<script>
var myApplication = angular.module("myApp", []);
var myArray = [];
myApplication.controller("myController", function ($scope) {
$scope.medicines = [];
$scope.AddMedicine = function (name, quantity) {
$scope.medicines.push({ Name: name, Quantity: quantity });
myArray = medicines;
};
});
</script>
how i get the added rows of the table in c# codebehind?
You are thinking about this in a reverse way.
You don't get values out of DOM to process data; instead, the values already exist in your ViewModel (in the controller), and the DOM is constructed based on them. In other words, the DOM is just some reflection of your ViewModel; the ViewModel is your source-of-truth for the data.
And so, if you have something like:
$scope.medicines = [...];
Then this is your ViewModel - just submit that.
If you are asking about how to determine which entries (that manifest themselves as rows, but that should not matter) were added vs. being originally retrieved from the backend, then you could just store the newly created elements in a temp array, until, say, the form is saved:
var newEntries = [];
$scope.AddMedicine = function (name, quantity) {
var newEntry = { Name: name, Quantity: quantity };
$scope.medicines.push(newEntry);
newEntries.push(newEntry);
};
$scope.Save = function(){
// ... Some code that submits to backend using MedicineSvc
MedicineSvc.AddMedicine(newEntries)
.then(function(){
newEntries = [];
});
}

Categories

Resources