I have 2 components here: app.component.html and app-server.component.html
app.component.html
<table class="table" style="width:200px;">
<tr>
<td>Names</td>
<td>Age</td>
</tr>
<tr><app-server-element *ngFor="let student of students" [student]='student'></app-server-element></tr>
</table>
server-element.component.html:
<td class="column">{{student.name}}</td>
<td class="column">{{student.age}}</td>
but the result is like this why?:
In addition to the problem others have suggesting - there seems to be another problem. Your <app-server-element *ngFor="let student of students" [student]='student'></app-server-element> acts as a cell because it is a direct child of your tr. The td elements inside app-server-element have no effect. You could use replace in your directive to get rid of the wrapper - that way the td element would be a direct child of the tr element and it would work as expected.
Edit
After gathering more information regarding your problem, please make the following changes to your code:
Change the server-element.component.ts to:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: '[appServerElement]',
templateUrl: './server-element.component.html',
styleUrls: ['./server-element.component.css']
})
export class ServerElementComponent implements OnInit {
#Input()
appServerElement: { name: string, age: string };
constructor() {
//
}
ngOnInit() {
//
}
}
and change selector: 'app-server-element' to selector: '[appServerElement]'.
Change the app.component.html to the following:
<table class="table" style="width:200px;">
<tr>
<td>Names</td>
<td>Age</td>
</tr>
<tr [appServerElement]="student" *ngFor="let student of students"></tr>
</table>
As ankit suggested you need to iterate of <tr>:
<table class="table" style="width:200px;">
<tr>
<td>Names</td>
<td>Age</td>
</tr>
<tr *ngFor="let student of students"><app-server-element *ngFor="let student of students" [student]='student'></app-server-element></tr>
your code iterate over app-server-element which results:
<tr>
<app-server-element></app-server-element>
<app-server-element></app-server-element>
<app-server-element></app-server-element>
<app-server-element></app-server-element>
</tr>
while you want: <tr><app-server-element></app-server-element></tr>
<tr><app-server-element></app-server-element></tr>
<tr><app-server-element></app-server-element></tr>
Related
I have a very puzzling problem. I have in my component a variable teams defined like this:
import { DateFunctionTeams } from '../_models/teams';
import { User } from '../_models/user';
import { AccountService } from '../_services';
import { first } from 'rxjs/operators';
#Component({
selector: 'app-raport-test',
templateUrl: './raport-for-date.component.html',
styleUrls: ['./raport-for-date.component.less']
})
export class RaportForDateComponent implements OnInit {
teams: Team[] = [];
...
}
The relevant part of my HTML looks like this:
<fieldset *ngFor="let team of teams">
<legend>{{team.function}} Users:</legend>
<div class="border border-primary">
<table id=scheduledTable class="table table-striped">
<thead>
<tr>
<th style="width:30%">Function</th>
<th style="width:30%">User</th>
<!--th style="width:30%">UserAvailability</th-->
<th style="width:10%"></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of team.users">
<td>{{user.function}} </td>
<td>{{user.firstName}} </td>
</tr>
</tbody>
</table>
</div>
</fieldset>
The line with fieldset *ngFor="let team of teams" in HTML causes the error Type 'HTMLSelectElement' is not assignable to type 'NgIterable<any>'.
Interesting bit is that if I change the name teams to something else (e.g. tms) it works just fine.
Any help appreciated.
I have a table contains several rows and an add button with each row.When I click add button a new row should be created just below that row similar to that row.Here is the code below
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
ngOnInit() {
}
groups=[
{
"name": "pencils",
"items": "red pencil"
},
{
"name": "rubbers",
"items": "big rubber"
},
];
//console.log(this.groups);
}
app.component.html
<div class="container">
<h2>Basic Table</h2>
<p>The .table class adds basic styling (light padding and only horizontal dividers) to a table:</p>
<table class="table border">
<tbody>
<tr *ngFor="let row of groups">
<td> {{row.name}} </td>
<td> {{row.items}} </td>
<td> <button>Add</button> </td>
</tr>
</tbody>
</table>
</div>
Just add it to the array and the view will update.
<td> <button (click)="addItem()">Add</button> </td>
public addItem(): void {
this.groups.push({name: 'foo', items: 'bar});
}
When I click add button a new row should be created just below that
row similar to that row.
Pass the current index where the button is clicked and insert an item at that index.
HTML:
<tr *ngFor="let row of groups; let i = index">
<td> {{row.name}} </td>
<td> {{row.items}} </td>
<td> <button (click)="addItem(i)">Add</button> </td>
</tr>
Component:
We are using JavaScript's splice() method to insert an item at that specific index.
addItem(index) {
var currentElement = this.groups[index];
this.groups.splice(index, 0, currentElement);
}
Live demo on StackBlitz: https://stackblitz.com/edit/angular-1pd6yx
a. Add click handler to the button
<button (click)="addRow(row)">Add</button>
b. Add method to the component
addRow(row: {name: string; items: string;}): void {
this.groups.push(row);
},
I have this code which parses JSON and list data into the table using ngFor.
The result will be like.
Yes, listing data into the table is working fine.
But how can I implement it to output single data of specific ID?
For example - I want the name of id=3 the output should be "Edward".
I can't figure out how to do this. Can someone help me or guide me?
Thanks.
app-components.ts
import { Component } from '#angular/core';
import {Http, Response} from '#angular/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
private data;
constructor(private http:Http){
}
ngOnInit(){
this.getData();
}
getData(){
this.http.get('/localhost/data.json')
.subscribe(res => this.data = res.json());
}
}
app-component.html
<table>
<tr>
<th>#</th>
<th>Name</th>
<th>Amount</th>
</tr>
<tr *ngFor="let info of data">
<td>{{info.id}}</td>
<td>{{info.name}}</td>
<td>{{info.amount}}</td>
</tr>
</table>
data.json
[
{
"id":"1",
"name":"John",
"amount":"112"
},
{
"id":"2",
"name":"Maria",
"amount":"44"
},
{
"id":"3",
"name":"Edward",
"amount":"40"
}
]
Please tell me that am I providing sufficient information or not.
You can use <ng-container> for the same, this have to use because you cannot apply two directives on a single element like we are using *ngIf and *ngFor.
<table>
<tr>
<th>#</th>
<th>Name</th>
<th>Amount</th>
</tr>
<ng-container *ngFor="let info of data">
<tr *ngIf='info.id == 3'>
<td>{{info.id}}</td>
<td>{{info.name}}</td>
<td>{{info.amount}}</td>
</tr>
</ng-container>
</table >
working example
Instead of adding an *ngIf directive , why don't you create a component separately to output only one table row ?
For example :
table.component.html will have :
<table>
<tr>
<th>#</th>
<th>Name</th>
<th>Amount</th>
</tr>
<tr>
<td>{{info.id}}</td>
<td>{{info.name}}</td>
<td>{{info.amount}}</td>
</tr>
</table>
and table.component.ts will have :
#Input() info : any;
Now you can loop over the <app-table [info]='info'></app-table> inside app-component.html also , you can just pass <app-table [info]='info[3]'></app-table> .
I have a lot of html tables that share the same 15 columns along with custom columns that are specific for each table. I would like to create these common 15 columns as a component that takes in a set of data and shows up as the 15 td's without a wrapper. I can't figure out how to create an Angular component that doesn't show the wrapper tag in the DOM and allows me to pass in input. Below is kind of what I'd like to do:
<tr *ngFor="let item of items">
<td>Column 1</td>
<my-common-columns [data]="item"></my-common-columns>
<td>Another column</td>
</tr>
Unfortunately with the above code, <my-common-columns> tag shows up in the rendered DOM, which messes up the table. I can only have td's under the tr tag.
I also tried <ng-container *ngComponentOutlet="myCommonColumns"> since ng-container's don't show up in the DOM, but I can't figure out how to pass data into it.
import { Component, TemplateRef, ViewChild } from '#angular/core';
#Component({
selector: 'my-common-columns',
template: `<ng-template let-item>
<td>inner item1:{{item}}</td>
<td>inner item2:{{item}}</td>
</ng-template>`
})
export class CommonComponent {
#ViewChild(TemplateRef) template: TemplateRef<any>;
}
#Component({
selector: 'my-app',
template: `
<table>
<tr *ngFor="let item of data">
<td>first</td>
<ng-template [ngTemplateOutlet]="common.template"
[ngTemplateOutletContext]="{$implicit: item}">
</ng-template>
<td>last</td>
</tr>
</table>
<my-common-columns #common></my-common-columns>
`
})
export class AppComponent {
data = [1, 2, 3, 4, 5];
}
live example
result:
ngComponentOutlet will show tag in HTML too.
Either, you should use abstraction to display tables for complex problems.
Depending on your data structure you could probably do something like:
<td *ngFor="let col of item">{{ col }}</td>
You have to use your component as a attribute.
So put it to <td my-common-column></td> and in your component change selector: [my-common-column]. These [ ] brackets allows you to use component as attribute.
Why don't you use the code below?
<tr *ngFor="let item of items">
<td>Column 1</td>
<td> {{ item }}</td>
<td>Another column</td>
</tr>
I'm trying to make a table with angularJs2 2.0.0-beta.0. This table lists items. I would decouple the item from the list.
I have this code:
app.item.list.html
<table class="table table-condensed" [hidden]="items?.length==0">
<thead>
<tr>
<th >id</th>
<th >col 2</th>
<th >col 3</th>
<th >col 4</th>
<th >col 5</th>
<th >col 6</th>
</tr>
</thead>
<tbody>
<tr *ngFor="#item of items" >
<item-detail [item]="item"></item-detail>
</tr>
</tbody>
</table>
The app.item.list.ts
import {Component, EventEmitter, Output, Input, OnChanges, SimpleChange} from 'angular2/core';
import {FORM_DIRECTIVES} from 'angular2/common';
import {Item} from './model/model.item';
#Component({
selector: 'item-list',
templateUrl: 'app/app.item.list.html',
directives: [FORM_DIRECTIVES, Item]
})
export class ItemList{
#Input() Items:Array<Item> = new Array();
public item: Item;
}
the app.item.html
<td >{{item.id}}</td>
<td >{{item.col1}}</td>
<td >{{item.col2}}</td>
<td >{{item.col3}}</td>
<td >{{item.col4}}</td>
<td >{{item.col5}}</td>
And the app.item.ts
import {Component, Input, EventEmitter, Output, OnChanges, SimpleChange} from 'angular2/core';
import {FORM_DIRECTIVES, NgFor} from 'angular2/common';
#Component({
selector: 'item-detail',
templateUrl: 'app/app.item.html',
directives: [ FORM_DIRECTIVES, NgFor]
})
export class Item{
#Input() item:Item;
}
The Items informations are all displayed, but there is a format problem. All my items are raggrouped under the first column of the header (the id column).
But I want to have the item.id under the id header, the item.col1 under col1 ....
What can I do having the list and the item decoupled?
P.S.: When they were in a single html and ts file, it worked well
Ok I recived an answer on Github, and I post the solution here:
I have to change app.item.list.html
and app.item.ts
#Component({
selector: '[item-detail]',
...
})
export class Item{
#Input('item-detail') item:Item;
}