Using nested ng-repeat with object arrays angular - javascript

Here is what I am trying to do:
<tr ng-repeat = "data in tabularData track by $index" >
<td ng-repeat ="(key,value) in usedAttributes" >{{data[key]}}</td>
</tr>
This DID work when the tabular Data was structured like this:
[3920F0-3434D3-ADF-3SDF:[{CreatedBy: "John Doe", CreatedDate: "10-20-2016"}]
However when I flattened it out, it looks more like this:
[{CreatedBy: "John Doe", CreatedDate: "10-20-2016",PrimaryID:"3920F0-3434D3-ADF-3SDF"}]
This does not work. I feel like I'm missing something very obvious.
usedAttributes is just a simple object array containing attributes (column data). The idea is that the user can choose the attributes they want to get so the data table is very dynamic. For this example, the usedAttributes may look like this:
["CreatedBy": [{Checked:false}],"CreatedDate":[{Checked:true}]]
Thus the user wants to see these two attributes although more exists.

You can do this,
<div ng-controller="listController">
<table class="table table-striped">
<thead>
<tr>
<th ng-repeat="(key, value) in tabularData[0]">{{key | uppercase }}
</th>
</tr>
<tbody>
<tr ng-repeat="val in tabularData">
<td ng-repeat="cell in val">
<input type="text" ng-model="cell">
</td>
</tr>
</tbody>
</table>
</div>
DEMO

Related

How to bind an object to HTML table in Vue.js, where its properties are dynamically created?

I am using vue.js library for front-end development.
I came a cross a scenario where my JavaScript method returns a list, which has objects, object's number of properties can change each time after method execution.
example my list can contain these type of objects in 2 different executions.
var obj = {
Name : "John",
2020-Jan: 1,
2020-Jul: 2
}var obj = {
Name: "John",
2020-Jan: 1,
2020-Jul: 2,
2021-Jan: 3,
2021-Jul: 4
}
Since Property name is dynamically changes is there any way to bind to HTML ?
<div >
<table>
<thead>
<tr>
<th v-for ="row in Result.Headers">
{{row}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in Result.Data ">
<td>
{{item.2020-Jan}} // Because don't know the number of properties until run time
</td> // No of <td/>'s can change on no of properties.
<td> // exactly don't know how many <td>'s needed there.
{{item.2020-Jul}}
</td> <td>
{{item.2021-Jan}}
</td>
</tr>
</tbody>
</table>
</div>
Is there way to bind these type of object to fronted in vue.js ?
You need to loop over the item's keys again. This will show all the values in the object
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="(value, key, index) in item">
{{value}}
</td>
</tr>
</tbody>
If you want to filter some of them, for instance check that the keys are valid dates you need to add a v-if and use Date.parse to check for this.
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="(value, key, index) in item" v-if="Date.parse(key) !== NaN">
{{value}}
</td>
</tr>
</tbody>
if u wana show all attr-> u can use this:
<ul v-for="item in Result ">
<li v-for="(value,key,index) in item">{{value}}</li>
</ul>
if u wana show all days u can use v-if and compute to complete youself fillter
<div id="app">
<ul v-for="item in Result" >
<li v-for="(value,key,index) in item" v-if="canShow(key)"> index:{{index}}------ key: {{key}} ------ value:{{value}} </li>
</ul>
</div>
<script>
var vue=new Vue({
el:'#app',
data:{
Result:[{
name: 'SkyManss',
2020-Jan: 1,
2020-Jul: 2
},{
name: 'SkyManss2',
2020-Jan: 1,
2020-Jul: 2,
2021-Jan: 3,
2021-Jul: 4
}]
},
computed:{
canShow(){
return function(skey){
return skey.indexOf('-') > -1;
}
}
}
});
</script>
after some research and some of your suggestions I came up with an answer.
<div>
<table>
<thead>
<tr>
<th v-for ="row in Result.Headers">
{{row}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="row in Result.Headers">
{{item[row]}}
</td>
</tr>
</tbody>
</table>
</div>
Javascript code
this.Result.Headers = Object.keys(result.data[0]);
this.Result.Data = result.data;
But this code only worked for the first time. second time data didn't get updated. So I updated JavaScript code to following code.
Vue.set(self.Result, 'Headers', []);
Vue.set(self.Result, 'Result', []);
this.Result.Headers = Object.keys(result.data[0]);
this.Result.Data = result.data;
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. That I got to know from following post.
vue.js is not updating the DOM after updating the array
Thank You All !!!

ng-repeat issue with JSON Object

So I'm trying to print the keys and values of a simple JSON object inside an HTML table with ng-repeat but not able to print it on the html page. The JSON object has been received from the backend and am trying to populate that in the frontend. I understand that I am doing a silly mistake somewhere but can't understand where.
JSON Object
json_data ={
user1 : "matt",
user2 : "kim",
user3 : "Tim"
}
$scope.rows = json_data;
HTML code..
<table ng-if="displayTable">
<caption>Results</caption>
<tr>
<th>Username</th>
<th>Name</th>
</tr>
<tr ng-repeat="(key, value) in rows">
<td> {{key}} </td> <td> {{ value }} </td>
</tr>
</tr>
</table>
Can't understand what silly mistake I am doing here.
Try {{rows.key}} and {{rows.value}}. Although I don't thing this is the answer. Give it a try..
Alternative ly you can try to see if it works with just one , either key or value...
First at all, the (key, value) is more well represented by (index, value).
A correct version of this piece of code will output this:
0 {"user1":"matt","user2":"kim","user3":"Tim"}
which 0 is the first index of an array and the json is the entire value.
So, i guess you are using a bad approach.
Try to modify your array to something like that:
$scope.rows = [
{key: 'user1', user: 'matt'},
{key: 'user1', user: 'kim'},
{key: 'user1', user: 'Tim'},
];
And modify your HTML to:
<table ng-if="displayTable">
<caption>Results</caption>
<tr>
<th>Username</th>
<th>Name</th>
</tr>
<tr ng-repeat="row in rows">
<td> {{row.key}} </td> <td> {{ row.user }} </td>
</tr>
</tr>
</table>

nested ng-repeat that one depend on the other

I have an issue with angular, I want to use two nested ng-repeat in a data table where the first get the data, and the second get the name of field to be retrieved from the data (retrieved in the first ng-repeat)
here is what I tried to do with code :
<table md-table flex-order-gt-sm >
<thead md-head>
<tr md-row >
//1st : get the name of fields, not a problem
<th md-column ng-repeat="field in fields">{{item.name}}</th>
</tr>
</thead>
<tbody md-body>
<tr md-row ng-repeat="item in items">
<td md-cell ng-repeat="field in fields" >
//here is the problem I want to get the item that it's field name is field
{{item.{{field}} }}</td>
</tr>
</tbody>
</table>
for example if fields contain :{'a','b','c'}
and items contains {'a':'1','b':'2','c':'3'};
I want for example for the 1st iteration of {{item.{{field}} }} to return 1
Use toString() to retrieve the scope data in an scope object.
<tr md-row ng-repeat="item in items">
<td md-cell ng-repeat="field in fields" >
{{item[field.toString()]}}
</td>
</tr>
Here is the plunker
As an alternative you could also use a filter:
<td md-cell ng-repeat="field in fields | filter: { name: 'field' }">
</td>
You need to get fields collection according to item of items collection after
getFieldsByItem(item)
Then you can get field from fields collection
{{field}}

How convert angular object to JS object

I have a table, One column by expressing object with an angular ng-repeat in angular
<table class="table table-bordered table-hover table-condensed " ng-show="vm.CandidatesList">
<thead>
<tr>
<th sortable-header col="FirstName" style="text-align:center">{{::vm.resources.FirstName}}</th>
<th sortable-header col="LastName" style="text-align:center">{{::vm.resources.LastName}}</th>
<th sortable-header col="CandidateTopic" style="text-align:center">{{::vm.resources.CandidateTopic}}</th>
</tr>
</thead>
<tr ng-repeat="c in vm.CandidatesList "
row-id="{{ c.ID }}"
ng-dblclick="vm.goEdit(c.ID)">
<td ng-model="c.FirstName" style="text-align:center">{{c.FirstName}}</td>
<td ng-model="c.LastName" style="text-align:center">{{c.LastName}}</td>
<td style="text-align:center" name="TopicToCandidate" id="TopicToCandidate+{{c.ID}}"><a ng-repeat="t in vm.getTopicToCandidate(c.ID)">{{t.Name}}, </a></td>
</tr>
now I want to recive the value of the TopicToCandidateto js with
var topic= document.getElementById("TopicToCandidate+" + item.ID).innerText
but topic is null because js can not convert the angular object or HTML object to js object.
I'm not sure you understand what angularjs does in the background. Don't extract the information from the DOM if you already have it in your controller.
So in other words just use it like this:
app.controller('candidateController', function($scope) {
$scope.CandidatesList = [
{ID:1 , FirstName:"Dan1", LastName:"Doe1"},
{ID:2 , FirstName:"Dan2", LastName:"Doe2"},
{ID:3 , FirstName:"Dan3", LastName:"Doe3"}
];
//get topic of first candidate for example
var topic = $scope.getTopicToCandidate($scope.CandidatesList[0]);
}
You might want to check out 2 way binding in the angular docs.

Relationship trouble - Mongo collections and MeteorJS

I am using Meteor, and trying to have one mongo collection that will contain products, and one that contains users.
Products have prices, but I also gave one product(as a test for now) a "dealerPrices" subcollection that contains an object like this:
"partprice" : "98",
"dealerPrices" : {
"YH" : "120",
"AB" : "125"
},
My hope is to have a table on my site with a column that displays the 'partprice' and next to it another column that shows the price for the current logged in dealer.
I could do a completely seperate collection for dealerPrices, but I am not sure which way is more efficient since I am new to Mongo.
My issue is targeting that number in the field with the "YH" or "AB" depending on the logged in user, the Users collection has a subcollection called "profile" that has a field called "code" that will match that "YH" or "AB" which is a unique code for each dealer.
I am using handlebars to display the data in Meteor, here is a bit of the html for displaying the table rows.
Larger code section:
<template name="products">
<h2> All Products <span class="productCount"></span></h2>
<table class="table table-condensed table-striped table-hover table-bordered">
<thead>
<tr>
<th class="toHide">Unique ID</th>
<th>Print</th>
<th>Product</th>
<th>FF Code</th>
<th>Base Price</th>
<th>My Price</th>
</tr>
</thead>
{{> AllProducts}}
</template>
<template name='AllProducts'>
{{#each row}}
<tr class='productRow'>
<td class="product-id toHide">{{_id}}</td>
<td class="print"><input type="checkbox" class="chkPrint"/></td>
<td class="product-name">{{partname}}</td>
<td class="product-code">{{code}}</td>
<td class="product-az-price">${{partprice}}</td>
<td class="product-dealer-price">${{dealerPrices.YH}}</td>
</tr>
{{/each}}
</template>
I hope I am explaining this correctly, basically I am trying to find some alternative to joins and having a table for products, a table for the dealer-product-dealerPrice relationship and a user accounts table in a relational database.
You probably want to do this in a Template helper. First, create a template for each loop-through, instead of just using {{#each}}:
<template name="fooRow">
... table rows
<td class="product-dealer-price">{{userBasedThing}}</td>
</template>
Then, add a Template helper for this new fooRow template:
Template.fooRow.userBasedThing = function () {
var result = "";
if (Meteor.userId() && this.dealerPrices)
result = this.dealerPrices[Meteor.user().profile[0].code];
return result;
}
Then just get rid of the stuff in the each loop, and replace it with:
{{#each row}}
{{> fooRow}}
{{/each}}
That should do it!

Categories