I'm encountering a strange problem and I cannot understand why it's happening.
I want to render an HTML table using Angular 4.
If I output the table using the following syntax everything works fine
<tbody>
<tr *ngFor="let athlete of athletes">
<td></td>
<td>{{athlete.name}}</td>
<td>{{athlete.country}}</td>
<td>{{athlete.time}}</td>
</tr>
</tbody>
And the table is rendered correctly:
But if do the same thing delegating the rending of the row to a component the table is not rendered correctly in Chrome (but is correct in Edge).
<tbody>
<app-athlete [athlete]="athlete" *ngFor="let athlete of athletes">
</app-athlete>
</tbody>
athlete.component.html
<tr>
<td></td>
<td>{{athlete.name}}</td>
<td>{{athlete.country}}</td>
<td>{{athlete.time}}</td>
</tr>
Could it be due to the fact that the "rendered" DOM is something like this when looking at Google Dev tools?
I also tried putting the <tr> with the *ngFor outside of the component but the problem is always the same.
I've reproduced the problem on Plunkr: https://plnkr.co/FZAFEP5S8KhzvdKwBtbH
Use attribute selector for your component
athlete.component.ts
#Component({
selector: 'tr[app-athlete]',
template: `
<td></td>
<td>{{athlete.name}}</td>
<td>{{athlete.country}}</td>
<td>{{athlete.time}}</td>
`,
})
export class AthleteComponent {
#Input() athlete: Athlete;
}
Now template of parent component should look like:
<tr app-athlete [athlete]="athlete" *ngFor="let athlete of athletes">
</tr>
Plunker Example
Related
As stated i want to access an iterable from a sibling tag. Unfortunatly its in a table so i cant just do it by wrapping the stuff with a diff and push the iteration one lvl outside. Also the items are tablerows so i cant make the sibling to a child. I guess this is easier with an example(thats what i want to do):
<table>
<tr v-for="element in elements">
...
</tr>
<tr v-for="hit in element.hits">
...
</tr>
</table>
Obviously this doesnt work since once i close the first tr i drop out of scope. Is there any work around that?
Regardiest regards,
Sean
v-for can be used on <template> that wraps <tr>, in this case it isn't rendered itself:
<template v-for="element in elements">
<tr>
...
</tr>
<tr v-for="hit in element.hits">
...
</tr>
</template>
I have a table that is created in one componentA that has several table-row elements in the table. I then have another componentB that just has several table-row elements that will be reused throughout the app in the template code. The issue is that when using componentB inside of the table of componentA the table-row elements are not spanning the entire width of the table and seem to be broken outside of the table.
I have found references to several other similar issues, but they are using dynamic rows based on data that is passed in for each row. My issue is that I have a fixed set of rows that will be used throughout the app. I tried using the following examples:
--- componentA
<table>
<tr><td>Name</td></tr>
<tr componentB></tr> --- does not work
</table>
--- componentB --- selector: '[componentB]'
<tr><td>Phone Number</td></tr>
<tr><td>Email</td></tr>
--- componentA
<table>
<tr><td>Name</td></tr>
<componentB></componentB> --- does not work
</table>
--- componentB --- selector: 'componentB'
<tr><td>Phone Number</td></tr>
<tr><td>Email</td></tr>
Here is an example stackblitz of exactly the problem: https://stackblitz.com/edit/angular-ydsgaz
The elements in componentB should span the width of the table just like a normal element used in componentA, but they are not. Any help would be great!
ANSWER: either one of the following examples will work for this scenario
content-projection: https://stackblitz.com/edit/angular-dr6fqs
template reference (my preferred way): https://stackblitz.com/edit/angular-qgxzhv
Use angular content projection.
You just have to add a directive selector to table body.
app.component.html
<table>
<tbody app-table-rows>
<tr>
<td>name</td>
<td>bob</td>
</tr>
<tbody>
</table>
and then in table-rows.component.html add ng-content element. Angular will replace this ng-content element with content inside directive host element.
<ng-content></ng-content>
<tr>
<td>email</td>
<td>bob#gmail.com</td>
</tr>
...
Working example https://stackblitz.com/edit/angular-dr6fqs
The code with the css makes the checkboxes disappear for cash.
They have been initialised as boolean variables in the model(using django).
<table>
<thead>
<tr>
<th>Payment Method:</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ seller_event_form.cash_payment }}</td>
</tr>
</tbody>
</table>
Without the css, the checkboxes appear. Because of this, none of the data inputted gets stored in the database.
edit with more info
I'm trying to unpack a model form here. When I unpack without adding any css, the boolean value in the model gets converted to a checkbox in the html. However, when I add css, the checkbox disappears. What am I doing wrong?
Can I use ngIf without an extra container element?
<tr *ngFor="...">
<div *ngIf="...">
...
</div>
<div *ngIf="!...">
...
</div>
</tr>
It doesn't work in a table because that would make invalid HTML.
ng-container is preferred over template:
<ng-container *ngIf="expression">
See:
Angular 2 ng-container
https://github.com/angular/angular.io/issues/2303
I found a method for that on: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#star-template.
You can simply use the <template> tag and replace *ngIf with [ngIf] like this.
<template [ngIf]="...">
...
</template>
You can't put div directly inside tr, that would make invalid HTML. tr can only have td/th/table element in it & inside them you could have other HTML elements.
You could slightly change your HTML to have *ngFor over tbody & have ngIf over tr itself like below.
<tbody *ngFor="...">
<tr *ngIf="...">
...
</tr>
<tr *ngIf="!...">
...
</tr>
..
</tbody>
adding brackets resolves this issue
<ng-container *ngIf="(!variable| async)"></ng-container>
You can try this:
<ng-container *ngFor="let item of items;">
<tr *ngIf="item.active">
<td>{{item.name}}</td>
</tr>
</ng-container>
Here, I have iterate loop in ng container so it will not create extra dom and later in tr tag check condition if I want to render or not.
Working on some array projects but Stuck on point where *ngFor did't accept dynamic value provided by another *ngFor.
<table border="2">
<tr>
<th rowspan="2">Subject</th>
<th colspan="4" *ngFor='#category of json.category_name'>{{category}}</th>
<th colspan="4">Overall</th>
</tr>
<tr>
<div *ngFor="#category of json.category_name">
<th *ngFor="#fa of json.total_fa.category">{{fa}}</th> //Not Working
</div>
</tr>
</table>
here in the commented line i want to provide json.total_fa.category where this category is coming from another *ngFor which is declared just above. but getting no result it seems angular try to find out json.total_fa.category itself which is not present.
but i want to load json.total_fa_term1 (which is first index from the category). how can i achive this.
Can i use more than one *ngFor on same HTML component ?
sometimes *ngFor and *ngIf is not working properly while embed on the same element why ?
here is my workground demo
You need to use .total_fa[category] instead of .total_fa.category otherwise you will try to access a property with name category:
<div *ngFor="#category of json.category_name">
<th *ngFor="#fa of json.total_fa[category]">{{fa}}</th>
</div>
See the updated plunkr: http://plnkr.co/edit/v08AdzNsR4GHMlZWQNsR?p=preview.