How can I split my table row elements between columns when I use table row from different component. All the row goes to 'First Name' <th> column
client-list.html
<table mdbTable>
<thead class="black white-text">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone number</th>
<th>Procedure</th>
<th>Doctor</th>
<th>Registration</th>
<th>Registration</th>
<th>Edit</th>
<th>Serve</th>
</tr>
</thead>
<tbody>
<div *ngFor="let c of clients">
<tr *ngIf="!c.isAlreadyServed" client-list-item [client]="c"></tr>
</div>
</tbody>
</table>
client-list-item.html
<td>{{client.firstName}}</td>
<td>{{client.lastName}}</td>
<td>{{client.phone}}</td>
<td>{{client.procedure}}</td>
<td>{{client.doctorsName}}</td>
<td>{{client.registrationDate | date: 'medium'}}</td>
<td>Edit</td>
<td>Serve</td>
client-list-item.ts
#Component({
selector: '[client-list-item]',
templateUrl: './client-list-item.component.html',
styleUrls: ['./client-list-item.component.css']
})
export class ClientListItemComponent {
#Input() client: Client;
}
Replacing the div with a ng-container should do the trick. ng-container element does not make it to the final rendered DOM and is used for having structural directives without polluting the DOM.
<ng-container *ngFor="let client of clients">
<tr *ngIf="!c.isAlreadyServed" client-list-item [client]="c"></tr>
</ng-container>
Related
I built the following stackblitz example
https://stackblitz.com/edit/angular-y454qb?file=src%2Fapp%2Ftable-header%2Ftable-header.component.css
As you can see I have parent table table which has one child component called table-header
If I write this code directly in my table component then my th colspan attribute will get applied
and will get the whole width of the table
<thead>
<th class="tableHeader" colspan="12">my table header</th>
</thead>
but if I put the same code inside nested component - in my casetable-header
then the code does not work and the colspan attribute does not get applied to the table and does not get the full width of the table.
How can I fix this?
The problem is how the app-table-header component is rendered by Angular. If you look at the result of the table being rendered you will see something like....
result of original table render
<table>
<thead>
<th class="tableHeader" colspan="12">my table header</th>
</thead>
<app-table-header>
<thead>
<th colspan="12">my table header</th>
</thead>
</app-table-header>
</table>
When app-table-header rendered there is an extra element between the <table> and the <thead> which breaks the table.
A possible solution is to make app-table-header an attribute selector, [app-table-header] and use a thead in your table with the attribute selector <thead app-table-header>.
table-header.compnonent.ts
#Component({
selector: 'thead[app-table-header]',
templateUrl: './table-header.component.html',
styleUrls: ['./table-header.component.css']
})
export class TableHeaderComponent implements {
#Input()
public heading: string = '';
}
table-header.component.html
<!-- Remove the thead from here -->
<th class="tableHeader" colspan="12">{{ heading }}</th>
table.component.html
<table>
<thead>
<th class="tableHeader" colspan="12">my table header</th>
</thead>
<thead app-table-header heading="Passing heading down with #Input"></thead>
</table>
This will result in the below html
<table>
<thead>
<th class="tableHeader" colspan="12">my table header</th>
</thead>
<thead app-table-header>
<th colspan="12">Passing heading down with #Input</th>
</thead>
</table>
See stackblitz below
https://stackblitz.com/edit/angular-bojuuf
EDIT
Updated the selector to thead[app-table-header] as suggested by #
Mazedul Islam.
Added #Input() to show you can pass values down with inputs.
Updated stackblitz
Iv been trying to create an angularJS component for constructing a dynamic html table from a provided array.
The components template includes some ng-transclude directives as 'placeholders'/slots for templates provided by the component consumer.
Is it possible to transclude a <tr> template (with nested <th>), to be used inside the table <thead>?
I have tried using all variations for transclution:
transclude: true, transclude: 'element'
and transclude: { header: 'header'}
(the third option seems as the most suitable, as I will eventually required multiple elements to be transcluded).
Component:
app.component("virtualTable", {
bindings: {
someArray: "<"
},
transclude: {
header: "header"
},
templateUrl: () => {
return "/app/components/virtual-table.component.html";
});
Component Template:
<div>
<table>
<thead>
<tr ng-transclude="header"></tr>
</thead>
<tbody>
<tr ng-repeat="item in vt.someArray">
...another place for transclution...
</tr>
</tbody>
</table>
</div>
Consuming HTML (component declaration):
<virtual-table some-array="vm.personList">
<header>
<th>First Column</th>
<th>Second Column<th>
</header>
</virtual-table>
I excpect the compiled DOM to look like this:
<table>
<thead>
<tr>
<th>First Column</th>
<th>Second Column</th>
</tr>
</thead>
...
But instead I get the innerHTML of the transcluded element (header) as Text:
<table>
<thead>
<tr ng-transclude="header">
<header class="ng-scope">
First Column
Second Column
</tr>
</header>
...
I Suspect the browser (chrome 76) to somehow strip the <tr> tags from the transcluded element before it is being provided to the component (as it illegal us to use <tr> outside of a <table>).
I would like to maintain an html table structure.
Is The Any Way to Solve This?
How can I get v-for to display table data in the same form as the following html:
<tr>
<th scope="col">Name</th>
<th scope="col">Price</th>
<th scope="col">Product ID</th>
<th></th>
</tr>
Currently I am using the following vue v-for code(below) but it is adding the table header(th) one below another. I would like the table header to display side by side.
<tr v-for="(column, index) in schema" :key="index">
<th scope="col">{{column}}</th>
</tr>
You just need to place v-for on the element you want to repeat, not it's parent.
For loop should be put on <th></th>
<tr>
<th v-for="(column, index) in schema" :key="index">{{column}}</th>
</tr>
Here is the official vue doc for list rendering: https://v2.vuejs.org/v2/guide/list.html
bind grid header and data separately.
<template>
<table>
<thead>
<tr>
<th v-for="(header,index) in gridHeader" :key="index">
{{header.displayName}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(data, index) in gridData" :key="index" >
<td>
{{data.name}}
</td>
<td>{{data.age}}
</td>
<td>{{data.place}}
</td>
</tr>
</tbody>
</table>
</template>
<script lang="ts">
import Vue from 'vue';
export default class HelloWorld extends Vue {
private gridHeader: object[] = [
{name: 'Name', displayName: 'Name'},
{name: 'Age', displayName: 'Age'},
{name: 'Place', displayName: 'Place'}
];
private gridData: any =[{name:'Tony',age:'31',place:'India'},
{name:'Linju',age:'26',place:'India'},
{name:'Nysa',age:'12',place:'India'}];
};
</script>
<style scoped>
</style>
I am trying to update my array of contacts type on DOM. However I am getting every value when I am calling that array in a function but that value of array is not getting updated in DOM.
import {Component} from 'angular2/core';
#Component({
selector:'contacts',
templateUrl:'./dev/RouteComponents/contacts.component.html'
})
export class ContactsComponent{
checking=false;
contacts=[
{firstname:'vishu',lastname:'handa',contactno:'12654',gender:'male'},
{firstname:'lalit',lastname:'gupta',contactno:'56489',gender:'male'},
{firstname:'aman',lastname:'singh',contactno:'48984',gender:'male'},
{firstname:'gaurav',lastname:'gupta',contactno:'5485',gender:'male'}
];
addContactToContactList(firstname,lastname,contact,gender)
{
console.log(firstname.value+"--"+lastname.value+"--"+contact.value+"--"+gender.value);
this.contacts.push({firstname:firstname.value,lastname:lastname.value,contactno:contact.value,gender:gender.value});
this.run();
}
run()
{
console.log(this.contacts.length);
this.checking = true;
}
}
<p *ngIf="checking">checking</p>
<table class="table table-bordered table-hover table-condensed">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Contact Name</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<tr *ngFor="#contact of contacts">
<td>{{contact.firstname}}</td>
<td>{{contact.lastname}}</td>
<td>{{contact.contactno}}</td>
<td>{{contact.gender}}</td>
</tr>
</tbody>
</table>
Value is not getting updated in DOM
Change your table rows tr tag for *ngfor as below and check it again :
<tr *ngFor="let contact of contacts">
<td>{{contact.firstname}}</td>
<td>{{contact.lastname}}</td>
<td>{{contact.contactno}}</td>
<td>{{contact.gender}}</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;
}