Create multiple elements in loop Angular2 - javascript

Edit: About the possible answer: I came across that question/answer too and implemented it that way. However, with the new version of Angular2 the syntax is different. The documentation about ngFor wasn't updated (this is where I looked). So I wrote the wrong code. The documentation about ngFor is updated in the Template Syntax - ngFor. Günter wrote a correct example on how to use it in the newer versions of Angular2 (beta17 or higher).
I'd like to create multiple elements in a loop. This is what I have now:
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
<tr *ngFor="let item of items" class="info">
<td>{{ item['id'] }}</td>
<td>{{ item['name'] }}<td>
</tr>
</tbody>
</table>
What I'd like is under ever tr another tr with details. The desired output should look like this in the browser:
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
<tr class="info">
<td>1</td>
<td>Item 1<td>
</tr>
<tr class="details">
<!-- More detailed info about item 1 -->
</tr>
<tr class="info">
<td>2</td>
<td>Item 2<td>
</tr>
<tr class="details">
<!-- More detailed info about item 2 -->
</tr>
</tbody>
</table>
How can I achieve the desired result?

<template ngFor [ngForOf]="items" let-item> is the canonical for of *ngFor and allows to repeat more than one element.
import {Component} from '#angular/core'
#Component({
selector: 'my-app',
providers: [],
template: `
<div>
<h2>Hello {{name}}</h2>
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
<template ngFor [ngForOf]="items" let-item>
<tr class="info">
<td>{{ item['id'] }}</td>
<td>{{ item['name'] }}<td>
</tr>
<tr class="details">
<td>{{ item['description'] }}<td>
</tr>
</template>
</tbody>
</table>
</div>
`,
directives: []
})
export class App {
items = [
{name: 'name1', id: 1, description: 'description1'}
{name: 'name2', id: 2, description: 'description2'}
{name: 'name3', id: 3, description: 'description3'}
];
constructor() {
this.name = 'Angular2 (Release Candidate!)'
}
}
Plunker example
In contrary to Polymer (for example), using <template> within <tbody> (or other table elements <tr>, ...) also works fine in IE with Angular2, because Angular2 processes the template internally and never adds it to the DOM. In Polymer this would not work because IE removes "unexpected" tags from table elements (which breaks Poymers <template is="dom-repeat">)
See also http://caniuse.com/#search=template

Use following component code:
import { Component } from '#angular/core';
#Component({
selector: 'demo-app',
templateUrl: 'app/app.component.html',
pipes: []
})
export class AppComponent {
constructor() {
this.items = [
{id: 1, name: 'Bob', details: 'Bob details'},
{id: 2, name: 'Sarah', details: 'Sarah details'},
{id: 3, name: 'Sam', details: 'Sam details'},
{id: 4, name: 'Susan', details: 'Susan details'}
];
}
}
With following app.component.html file:
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
<template ngFor [ngForOf]="items" let-item>
<tr class="info">
<td>{{ item['id'] }}</td>
<td>{{ item['name'] }}<td>
</tr>
<tr class="details">
<td colspan=2>{{ item['details'] }}</td>
<!-- More detailed info about item -->
</tr>
</template>
</tbody>
</table>
Result is something like this:
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
<tr class="info">
<td>1</td>
<td>Bob</td><td>
</td></tr>
<tr class="details">
<td colspan="2">Bob details</td>
</tr>
<tr class="info">
<td>2</td>
<td>Sarah</td><td>
</td></tr>
<tr class="details">
<td colspan="2">Sarah details</td>
</tr>
<tr class="info">
<td>3</td>
<td>Sam</td><td>
</td></tr>
<tr class="details">
<td colspan="2">Sam details</td>
</tr>
<tr class="info">
<td>4</td>
<td>Susan</td><td>
</td></tr>
<tr class="details">
<td colspan="2">Susan details</td>
</tr>
</tbody>
</table>
For more information read https://coryrylan.com/blog/angular-2-ng-for-syntax

You can achieve this by looping on <tbody> instead of <tr>, as tables with mutiple tbody is valid in html refer to.
So your code will be like
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody *ngFor="let item of items; #idx = index">
<tr class="info">
<td>{{idx}}</td>
<td>Item {{idx}}<td>
</tr>
<tr class="details">
<td>{{ item['id'] }}</td>
<td>{{ item['name'] }}<td>
</tr>
</tbody>
</table>
</table>

Since Angular v4 <template> tag is deprecated.
Use <ng-template> instead, as described in tutorial:
ng-template-element

Related

Is it better to use interpolation multiple times to print out data or use a js expression to concatenate the data in vue.js?

This might be a silly question, but I am printing out a very big table with lot's of data using Vue.js, some of which looks best when I concatenate different data bindings in one single <td></td> element.
So I am curious if there there is any difference in performance between the two when loading a lot of data.
Here is an example:
Using interpolation:
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr v-for="person in people">
<th>{{ person.firstName }} {{ person.lastName }}</th>
</tr>
</tbody>
</table>
Using js concatention:
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr v-for="person in people">
<th>{{ person.firstName + ' ' + person.lastName }}</th>
</tr>
</tbody>
</table>
The people array:
people: [
{
firstName: 'Jhon',
lastName: 'Doe'
},
// A lot more data...
]

How to dynamically load the nested array attributes in html table using angularjs?

This is the code that I tried but only values of cardno and cardtype why am I not able to access the rest of them? Any suggestions?
<tr ng-repeat="data in myData17.layouts">
<td ng-show="$index==1">{{data.name}}</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards">
<td>{{card.cardNo}}</td>
</tr>
</table>
</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards">
<td>{{card.cardType}}</td>
</tr>
</table>
</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards.ports">
<td>{{card.portNo}}</td>
</tr>
</table>
</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards.ports">
<td>{{card.portName}}</td>
</tr>
</table>
</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards.ports">
<td>{{card.portType}}</td>
</tr>
</table>
</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards.ports">
<td>{{card.portspeed}}</td>
</tr>
</table>
</td>
<td ng-show="$index==1">
<table>
<tr ng-repeat="card in data.cards.ports">
<td>{{card["ds-scheduler-node-profile"]}}</td>
</tr>
</table>
</td>
</tr>
This is the my data.
{
"name": "twoCardOneEthportAndOne10G",
"cards": [{
"cardNo": "1",
"cardType": "Ethernet",
"ports": [{
"portNo": "1",
"portName": "LAN1",
"portType": "ethernetCsmacd",
"portspeed": "eth-if-speed-1gb",
"ds-scheduler-node-profile": "default"
}]
},
{
"cardNo": "10",
"cardType": "Ethernet",
"ports": [{
"portNo": "1",
"portName": "10GE",
"portType": "ethernetCsmacd",
"portspeed": "eth-if-speed-10gb",
"ds-scheduler-node-profile": "default"
}]
}]
}
data.cards.ports isn’t a thing.
The ports property is of a singular card and cards is an array.
It would have to be accessed like so:
data.cards[0].ports
So, how would this be structured in your code? You would need something like this (this isn’t a solution to your exact implementation just a visual guide to help you access your data in the way you require)
<div ng-repeat=“data in myData17.layouts”>
{{ data.name }}
<div ng-repeat=“card in data.cards”>
{{ card.cardNo }}
<div ng-repeat=“port in card.ports”>
{{ port.portNo }}
</div>
</div>
</div>
Hope that this gives you a better understanding and good luck

Multiple table rows as single component

What would be a way to have multiple table rows in a single Angular component ?
I would like to display two rows per item of a given list, and have it in an HTML table.
I tried using ng-template with a component as attribute to avoid having a component tag breaking the table flow, but the input won't work in that case. Ideally I'm looking for a way to remove the component tag from the dom...
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container app-located-person
*ngFor="let person of persons"
[person]="person">
</ng-container>
</tbody>
</table>
App located person
<tr>
<td>{{ person.name }}</td>
<td>{{ person.city }}</td>
</tr>
<tr *ngIf="details">
<td>Last connection</td>
<td>{{ person.lastConnection }}</td>
</tr>
I finally made it not to break the table dom flow by using display: table-row-group; on the component node :)
Why don't you include the tr's inside the ng-container tag?
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container
*ngFor="let person of persons"
[person]="person">
<tr>
<td>{{ person.name }}</td>
<td>{{ person.city }}</td>
</tr>
<tr *ngIf="details">
<td>Last connection</td>
<td>{{ person.lastConnection }}</td>
</tr>
</ng-container>
</tbody>
</table>
If you want to use a component:
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container
*ngFor="let person of persons">
<app-located-person [person]="person"></app-located-person>
</ng-container>
</tbody>
</table>
Try the following:
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container *ngFor="let person of persons">
<tr>
<td>{{person.name}}</td>
<td>{{person.city}}</td>
</tr>
<tr *ngIf="person.lastConnection">
<td>Last connection</td>
<td>{{person.lastConnection}}</td>
</tr>
</ng-container>
</tbody>
</table>
Stackblitz: Link

rowspan for 3 columns using angularJS

I have a category list that contains name and subject list.
The subject list contains name and course list.
The course list contain name.
I want to display this data in table that will rowspan category or subject if they are the same. For example:
Category Subject Course
cat1 sub1 ''
sub2 cour1
cour2
sub3 ''
cat3 ''
Currently I have it working for two columns using this:
<table class="curvetable5" style="width:99%">
<thead>
<tr>
<th width="30%">Category</th>
<th width="30%">Subject</th>
</tr>
</thead>
<tbody ng-repeat="category in organization">
<td rowspan="{{category.subjectList.length+1}}">{{category.categoryName}}</td>
<tr ng-repeat="subject in category.subjectList">
<td>{{ subject.name }}</td>
</tr>
</tbody>
</table>
However, I am having trouble doing it for 3 columns. This is the code I have that is not working. The course name are not being displayed and subject name become listed in column order instead of row order. Any suggestion:
<table class="curvetable5" style="width:99%">
<thead>
<tr>
<th width="30%">Category</th>
<th width="30%">Subject</th>
<th width="40%">Course</th>
</tr>
</thead>
<tbody ng-repeat="category in organization">
<td rowspan="{{category.subjectList.length+1}}">{{category.categoryName}}</td>
<tr ng-repeat="subject in category.subjectList">
<td rowspan="{{subject.courseList.length+1}}">{{ subject.name }}</td>
<tr ng-repeat="course in subject.courseList">
<td>{{ course.name }}</td>
</tr>
</tr>
</tbody>
</table>
Sample Data:
[
{"id":95,"categoryName":"A new catagory",
"subjectList":[{"id":112,"subjectname":"2ndnewcat","curcount":0,
"courseList":"[{\"name\":\"-\",\"curcount\":0}]"},
{"id":76,"subjectname":"ZZZZZZZZZZZZZZZZZZ_class","curcount":0,
"courseList":[{"coursename":"thiswillbenew111111111112","curcount":1}]}]},
{"id":93,"categoryName":"David Test",
"subjectList":[{"id":75,"subjectname":"This is a test","curcount":1,
"courseList":[{"coursename":"newewst1","curcount":0}]}]},
{"id":116,"categoryName":"New Category",
"subjectList":[{"id":79,"subjectname":"New Subject","curcount":2,
"courseList":[{"coursename":"ISO training part 2","curcount":0}]}]},
{"id":0,"categoryName":"cat1",
"subjectList":[{"id":15,"subjectname":"test","curcount":4,
"courseList":"[{\"name\":\"-\",\"curcount\":0}]"}]},
{"id":11,"categoryName":"cat2",
"subjectList":[{"id":68,"subjectname":"asdasd","curcount":5,
"courseList":[{"coursename":"david1","curcount":0},{"coursename":"thisisatest","curcount":0}]}]},
{"id":12,"categoryName":"cate3",
"subjectList":[{"id":12,"subjectname":"newest1","curcount":6,
"courseList":[{"coursename":"cous1","curcount":0}]}]},
{"id":163,"categoryName":"emptylist",
"subjectList":"[{\"name\":\"-\",\"curcount\":0}]"}
]
This is current code I am testing. It will will rowspan the category, display each subject once and then display all the courses for each subject in list in a single cell. I would prefer to rowspan subject too, but this is what I got working so far.
<table class="curvetable5" style="width:99%">
<thead>
<tr>
<th width="30%">Category</th>
<th width="30%">Subject</th>
<th width="40%">Course</th>
</tr>
</thead>
<tbody ng-repeat="category in organization">
<td rowspan="{{category.subjectList.length+1}}">{{category.categoryName}}</td>
<tr ng-repeat="subject in category.subjectList">
<td>{{ subject.subjectname }}</td>
<td> <li ng-repeat="course in subject.courseList" >{{ course.coursename }} </li></td>
</tr>
<td ng-if="category.subjectList.length==27"> </td>
<td ng-if="category.subjectList.length==27"> </td>
</tbody>
</table>
Thanks,
AB
The two column case should be:
<tbody ng-repeat="dept in org.deptList">
<tr ng-repeat="subj in dept.subjList">
<td rowspan="dept.subjList.length+1">
{{dept.name}}
</td>
<td>
{{subj.name}}
</td>
</tr>
</tbody>
For the three column case, nest a <table> in the <td> element:
<tbody ng-repeat="dept in org.deptList">
<tr ng-repeat="subj in dept.subjList">
<td rowspan="dept.subjList.length+1">
{{dept.name}}
</td>
<td>
<table>
<tr ng-repeat="class in subj.classList">
<td rowspan="subj.classList.length+1">
{{subj.name}}
</td>
<td>
{{class.name}}
</td>
</tr>
</table>
</td>
</tr>
</tbody>

Vue.Draggable for tables with more than one tbody

I have table with difficult structure. The real structure of my table is much more difficult.
I try to show it by a simple example.
<table>
<thead>
<th>id</th>
<th>name</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr colspan="2">
<td>1</td>
</tr>
</tbody>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr colspan="2">
<td>1</td>
</tr>
</tbody>
</table>
I use vuejs, and I need to have sortable table (I use vuedraggable component https://github.com/SortableJS/Vue.Draggable).
I have item component with template like this.
<template>
<tbody class="item">
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</tr>
<tr colspan="2">
<td>{{ item.description }}</td>
</tr>
</tbody>
</template>
And I use it with draggable.
<draggable v-model="items" :element="'table'" :options="{draggable: '.item'}">
<item-component v-for="(item, index) in items" :item="item" :key="item.id">
</item-component>
</draggable>
The Draggable component create outer 'table' element. Everything is working, but how can I add 'thead'?
I try to create one more component - items:
<template>
<table>
<thead>
<th>1</th>
<th>2</th>
</thead>
<slot></slot>
</table>
</template>
But this is not working:
<draggable v-model="items" :element="items-component" :options="{draggable: '.item'}">
<item-component v-for="(item, index) in items" :item="item" :key="item.id">
</item-component>
</draggable>
Since VueDraggable is a custom component, when using the DOM as your template eg. table you will be subject to some restrictions that are inherent to how HTML works, because Vue can only retrieve the template content after the browser has parsed and normalized it.
This will lead to issues when using custom components with elements that have such restrictions
A workaround is to use the is special attribute:
https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats
<table>
<thead>
<th>1</th>
<th>2</th>
</thead>
<div is="draggable" element="div" v-model="items">
<tbody v-for="i in items">
<tr>
<td>{{i.id}}</td>
<td>{{i.name}}</td>
</tr>
<tr colspan="2">
<td>{{ item.description }}</td>
</tr>
</tbody>
</div>
</table>

Categories

Resources