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.
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>
So basically I want to have child components be in control of generating some content and put each one of them as td element, but it's not working in angular because of the extra div angular generates.
How could I make this work?
Parent-component.html
<table>
<tr>
<td>something1</td>
<td>something2</td>
<app-child-component></app-child-component>
</tr>
<table>
Child-component.html
<ng-container *ngTemplateOutlet="content"></ng-container>
<ng-template #content>
<td>something</td>
<td>something else</td>
<td><app-another-component></td>
</ng-template>
Add this to your CSS to get the child component's container out of the way:
:host{display: contents; }
I'm having trouble understanding why this is happening! So, this block of code:
<div class="container">
<div class="row" v-for="rows in data.Rows"> {{ rows }} </div>
</div>
Will render all the rows in the object.
But, when I use the same syntax in a table instead like this:
<table>
<tr v-for="rows in data.Rows"> {{ rows }} </tr>
</table>
I get the error:
[Vue warn]: Property or method "rows" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
How come there are issues in using the v-for like this in a table? I want a table to display the data as it better suits the purpose in this case. Othewise I would have chosen divs instead of table rows, but I would love for this to works. Any ideas as to why this is happening?
If you use that template directly within an HTML file (as opposed to a template string or SFC) it will be parsed by the browser before it gets to Vue. Browsers are fussy about tables and what elements are allowed inside which other elements.
The example below shows how the browser will parse your template into DOM nodes. Notice how the {{ rows }} gets moved:
let html = document.getElementById('app').innerHTML
html = html.replace(/</g, '<').replace(/>/g, '>')
document.getElementById('output').innerHTML = html
#app {
display: none;
}
<div id="app">
<table>
<tr v-for="rows in data.Rows"> {{ rows }} </tr>
</table>
</div>
<pre id="output">
</pre>
It is this mangled version of the template that Vue is trying to run and as you can see {{ rows }} has been moved outside the v-for, causing the error.
The official documentation covers this here:
https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats
The solution would just be to include a <td> in your template:
<table>
<tr v-for="rows in data.Rows">
<td>{{ rows }}</td>
</tr>
</table>
You cannot directly use "rows" property inside tr tag, you need td tag
like this
<table>
<tr class="row" v-for="rows in data.Rows"> <td>{{ rows }} </td></tr>
</table>
working codepen here: https://codepen.io/chansv/pen/dyyVybK
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
I have the following snippet:
<p>AAA</p>
<div ng-show="files.length == 0">
<p>BBB</p>
<tr class="no-files">
<p>CCC</p>
<td colspan="2">
<p class="no-files">There are no files to load.</p>
</td>
</tr>
</div>
It seems like the ng-show is only marking its own div as (in)visible, and not also the contents of that div. In my application, the "there are no files..." message is displayed regardless of the number of elements in files. I expected entire div to be shown/hidden. Have I done something wrong or is this how ng-show works?
In the example above, when the number of files is greater than zero, AAA and CCC are displayed.
Is this the proper behavior or have I done something wrong?
Firstly, I'd say you have invalid HTML. <div>s can't contain table rows. Try removing the wrapper <div> and putting ng-show on the <tr>.
p can't appear in a table outside of a table cell. Neither can div. Use ng-show on the tr element(s) instead.
<tr class="no-files" ng-show="files.length == 0">
<td colspan="2">
<p class="no-files">There are no files to load.</p>
</td>
</tr>