I'm using Knockout.js to realize my web app.
I get data from a database and i use Json to pass data to html page that is rendered through data-bind.
I would like to set the more dynamic possible my app so i would like to iterate through json keys without "hardcoding" the field name
I have the following json: {"id_user":"63","email":"mail#email.it","flag":"1"}
and iterate using:
<table data-bind="foreach:page().users">
<tr>
<td data-bind="text:$data.email"></td>
<td data-bind="text:$data.flag"></td>
</tr>
</table>
but i would like to avoid the .email and .flag and using [0] or [1] to reuse this structure for all the models. How can i do it?
You could do this with a custom binding:
<table data-bind="foreach:page().users">
<tr data-bind="createHeaderRow: $data">
</tr>
<tr data-bind="createTableRow: $data">
</tr>
</table>
Then create these methods:
ko.bindingHandlers.createHeaderRow = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
for (var property in valueAccessor()) {
$(element).append('<td>' + property + '</td>');
}
}
};
ko.bindingHandlers.createTableRow = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
for (var property in valueAccessor()) {
$(element).append('<td data-bind="text: ' + property + '"></td>');
}
}
};
I've created a jsFiddle to demonstrate it too.
Here is some updated html to get a header and the rows with thead and tbody
<table class="table" >
<thead data-bind="with: page().users()[0]">
<tr data-bind="createHeaderRow: $data">
</tr>
</thead>
<tbody data-bind="foreach: page().users()">
<tr data-bind="createTableRow: $data">
</tr>
</tbody>
</table>
Related
I am using a node JS app to send an email using amazon SES using the ses.sendTemplatedEmail API
I have also mentioned the template's pure html file for reference if need be
how do i achieve expected output ? i don't know what is going wrong and why it is using scientific when decimal is specified in JSON
test.js
const aws=require('aws-sdk')
const ses = new aws.SES({ apiVersion: "2020-12-01",region:"us-east-1"});
var a = {
"Items": [
{
"timeSinceInactive": 0.00011574074074074075,
"id": "myid1",
"ssid": "myssid",
"deviceName": "devicename1"
},
{
"timeSinceInactive": 0.00009259259259259259,
"id": "myid2",
"ssid": "myssid2",
"deviceName": "devicename2"
}
]
}
b = JSON.stringify(a)
console.log(b)
async function sesSendEmail(b,ses) {
var params = {
Source: "abc#gmail.com",
Template: "mytemplatename",
Destination: {
ToAddresses: ["xyz#gmail.com"] // Email address/addresses that you want to send your email
},
TemplateData: b,
}
try {
await ses.sendTemplatedEmail(params).promise()
}
catch (err) {
console.log(err)
throw new Error(err)
}
};
function setAwsCredentials() {
awsCredentials = {
region: "us-east-1",
accessKeyId: "",
secretAccessKey: ""
};
aws.config.update(awsCredentials);
console.log("Set credentials successfully")
}
setAwsCredentials()
sesSendEmail(b,ses)
template.html
<table border='2' width='1000'>
<tr>
<th>timeSinceInactive</th>
<th>id</th>
<th>ssid</th>
<th>deviceName</th>
</tr>
<thead>
<tr>
{{#each Items.[0]}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each Items}}
<tr>
{{#each this}}
<td>
{{this}}
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
Current output:
timeSinceInactive id ssid deviceName
1.1574074074074075E-4 myid1 myssid devicename1
9.259259259259259E-5 myid2 myssid2 devicename2
desired output
timeSinceInactive id ssid deviceName
0.00011574074074074075 myid1 myssid devicename1
0.00009259259259259259 myid2 myssid2 devicename2
EDIT
I need to sort the data as well so converting it to a string is not a feasible alternative unfortunately.
Note
I am using createTemlate API from Amazon SES which supports handlebars.. so the html code is using handlebars by default... that is causing the issue its making it in scientific notation for some reason how do i make it decimal only ?
You might consider converting the numbers to strings before passing them to the template. That way you have control over the formatting.
To my mind you should switch to a template that is less generic and make a call to a custom helper that would display the number as you want. The template will look like this one :
<table border='2' width='1000'>
<tr>
<th>timeSinceInactive</th>
<th>id</th>
<th>ssid</th>
<th>deviceName</th>
</tr>
<thead>
<tr>
{{#each Items.[0]}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each Items}}
<tr>
<td>
{{customFormatNumber timeSinceInactive}}
</td>
<td>
{{id}}
</td>
<td>
{{ssid}}
</td>
<td>
{{deviceName}}
</td>
</tr>
{{/each}}
</tbody>
</table>
And here is the custom helper that you could write (this is just an example, probably not the one you want exactly) :
Handlebars.registerHelper('customFormatNumber ', function(item, options) {
retrun item.toPrecision(10)
});
I want to populate my grid with the data which i am receiving from API
below is my API response which i am getting
[
{
"intUserId": 1109,
"vcrFirstName": "sdvlbs",
"vcrLastName": "dsbvsdfn",
"vcrLoginName": "!##DBASDI?\"|}",
"vcrPassword": "eclerx#123",
"vcrStatus": "InActive",
"vcrIsClient": "eClerx",
"vcrEmail": "sdvlbs.dsbvsdfn#eClerx.com",
"vcrRole": "Analyst,Auditor,Team Lead,Manager",
"Agreements_Selected": "ISDA,CSA,Repo,SLA,PBA"
}
]
But at the time of passing this data to HTML by grid is still blank
Below is my .ts code
arrBirds:Array<string> = [];
userdata(){
this.http.get(this.url).subscribe((res)=>{
this.arrBirds = Array.of(res.json()) ;
console.log(this.arrBirds)
});
}
Below is my HTML
<table cellpadding="0" width="100%" cellspacing="0" border="0" class="search_grid_view table-striped">
<thead>
<tr>
<th style="min-width: 100px;">Login Name</th>
<th>First Name</th>
<th>Last Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let char of arrBirds">
<td >
{{char.vcrPassword}}
</td>
<td >
{{char.vcrStatus}}
</td>
<td >
{{char.Agreements_Selected}}
</td>
<td >
{{char.vcrEmail}}
</td>
</tr>
</tbody>
</table>
i am trying to iterate the data which i am receiving from API response
Below is my API code
public HttpResponseMessage GetCheckBoxes()
{
HttpResponseMessage response;
UserDB userDB = new UserDB();
DataSet ds = userDB.UserGridDetails();
string json = JsonConvert.SerializeObject(ds.Tables[0], Formatting.Indented);
//response = Request.CreateResponse(HttpStatusCode.OK, "[" + json + "]");
response = Request.CreateResponse(HttpStatusCode.OK, json);
return response;
}
my grid doesn't populate with the data.
i am struggling since last 5 days.
I think html file is not in sync with http response
<tr *ngFor="let char of arrBirds">
<td > {{char?.vcrPassword}}</td>
<td > {{char?.vcrStatus}} </td>
<td > {{char?.Agreements_Selected}}</td>
<td > {{char?.vcrEmail}} </td>
</tr>
Change this in tr,it will work.
If it still don't work then import ChangeDetectorRef from angular/core
inject it in constructor and use detectchanges method in ChangeDetectorRef
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '#angular/core';
constructor(private ref: ChangeDetectorRef) {}
userdata(){
this.http.get(this.url).subscribe((res)=>{
this.arrBirds = Array.of(res.json()) ;
this.ref.detectChanges();
console.log(this.arrBirds)
});
}
Hope It helps.
By parsing the JSON data it is working now.
userdata(){
this.http.get(this.url).subscribe((res)=>{
this.arrBirds = JSON.parse(res.json()) as Application[];
console.log(this.arrBirds)
});
}
I have a template like this, and I want ro make the table vertical(using partials is not an option in my environment, and I don't want to do it with inverted condition or duplicating html elements)
<table>
<tr>
<td>row1</td>
<td>row1</td>
<td>row1</td>
<tr>
</table>
The result should be:
<table>
<tr>
<td>row1</td>
</tr>
<tr>
<td>row1</td>
</tr>
<tr>
<td>row1</td>
<tr>
</table>
I already tried
var data = {
foo:true
}
<table>
<tr>
<td>row1</td>
{{#foo}}</tr><tr> {{/foo}}
<td>row1</td>
{{#foo}}</tr><tr> {{/foo}}
<td>row1</td>
<tr>
</table>
and
var data = {
foo:'</tr><tr>'
}
<table>
<tr>
<td>row1</td>
{{{foo}}}
<td>row1</td>
{{{foo}}}
<td>row1</td>
<tr>
</table>
A common misconception about Ractive is that because it uses the Mustache syntax, people think it acts like Mustache.
Mustache does string interpolation, where it replaces {{ }} to values that correspond in an object, and you get HTML. Ractive, on the otherhand, compiles the template into an AST. Then it uses that tree to create the DOM. It is similar to how Babel converts JSX into its object representation before feeding it to React, or how an HTML parser parses HTML, then constructing the DOM.
So for your scenario to work, you'll have to think in terms of properly-formed HTML:
Ractive.DEBUG = false;
const VerticalTableComponent = Ractive.extend({
template: `
<table border="1">
{{#tableItems}}
<tr>
<td>{{.}}</td>
</tr>
{{/}}
</table>
`
});
const app = VerticalTableComponent ({
el: '#app',
data: {
tableItems: ['foo', 'bar', 'baz', 'quz']
}
});
<script src="https://unpkg.com/ractive#0.8.12/ractive.min.js"></script>
<div id="app"></div>
given the following object:
{
key1: ["val1","val2","val3","val4"],
key2: ["val2","val5","val22","val4","val8","val1"],
key3: ["val1"],
key4: ["val11","val12"]
}
Is it possible to iterate over all the values in one time using ng-repeat?
My motivation is:
1. I use ng-repeat in a <tr> tag, which CANNOT be placed in the <tbody> and i need to create a row in the table for each value e.g:
<tr>
<td>key1.val1</td>
</tr>
<tr>
<td>key1.val2</td>
</tr>
<tr>
<td>key1.val3</td>
</tr>
<tr>
<td>key1.val4</td>
</tr>
<tr>
<td>key2.val2</td>
</tr>
<tr>
<td>key2.val5</td>
</tr>
... and so on ...
I do not know the keys or value in advanced. I get them through an API
Any Ideas?
Thanks!
As your keys are properties of an object I would convert it to an array in a first step:
$scope.keys = [];
for (var property in object) {
if (object.hasOwnProperty(property)) {
$scope.keys.push(object.property);
}
}
Then you may display all values with a nested ng-repeat directive:
<div ng-repeat="key in keys">
<div ng-repeat="val in key[$index]">
{{val}}
Edit: There's also a way to iterate over the object properties directly
<div ng-repeat="(key, value) in myObj"> ... </div>
Like documented here:
$scope.allValues = [];
angular.forEach(object, function(array) {
array.forEach(function(value) {
$scope.allValues.push(value);
});
});
Then simply use an ng-repeat on allValues.
I am using knockout binding to bind some data into html tables. My knockout view Model had multiple products and each product will have multiple chars. I want to display the products in one table and when i select the link "show chars" it should display the corresponding chars in below table.
This is my View Model
var ProductViewModel = function(items) {
this.items = ko.observableArray(items);
this.itemToAdd = ko.observable("");
this.addItem = function() {
if (this.itemToAdd() != "") {
this.items.push(this.itemToAdd());
this.itemToAdd("");
}
}.bind(this);
};
And this is my html tables
<div id="productTable">
<table class="ui-responsive table">
<thead>
<tr>
<th >Product Name</th>
<th >Description</th>
<th >Parent?</th>
</tr>
</thead>
<tbody id="pBody" data-bind="foreach: items">
<tr class="success" >
<td><span data-bind="text: name"></span>
</td>
<td><span data-bind="text: desc"></span>
</td>
<td>show chars</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="productChars">
<div id="productCharTable">
<table class="ui-responsive table">
<thead>
<tr>
<th >Char Name</th>
<th >Description</th>
<th >Length</th>
<th >Type</th>
</tr>
</thead>
<tbody id="pBody" data-bind="foreach: $data['chars']">
<tr class="success">
<td><span data-bind="text: name"></span>
</td>
<td>asdf asdfasdf</td>
<td>10</td>
<td>String</td>
</tr>
</tbody>
</table>
</div>
I am able to bind the products into first table. But for characteristics i am not sure how to achieve the same.
Could someone please help me in figuring out how to achieve the same.
Here is the jsfiddle
https://jsfiddle.net/sirisha_k/0Ln7h2bo/7/
As #supercool pointed out you can use "data-bind='with selectedItem'" to populate the second table with chars data. For that you need to add one more item into your model called selectedItem and every time you select or add a row, you point the selectedItem to that elementdata. And use "data-bind='with selecteItem'" for second table.
var ProductViewModel = function(items) {
this.items = ko.observableArray(items);
this.selectedItem = ko.observableArray();
this.itemToAdd = ko.observable("");
this.addItem = function() {
if (this.itemToAdd() != "") {
this.items.push(this.itemToAdd());
this.itemToAdd("");
}
}.bind(this);
};
and on row select call some function selectedItem($data) where $data refers to the current item.
then set that data to selectedItem in model.
function selectedItem(prod){
ProductViewModel.selectedItem(prod);
}