Reputation: 1126
In my first Angular 4 application, I defined a list component :
<edm-document *ngFor="let document of documents" class="column is-one-quarter"></edm-document>
Document
is an interface :
export interface Document {
id?: Number,
name: string,
filePath: string
}
All is working as expected, i.e I get my documents list. But now I would like to access to document variable inside my DocumentComponent
(the edm-document
tag component)
Inside my DocumentComponent
template, if I try this it's not working :
<p>{{ document.name }}</p>
I get this error : DocumentComponent.html:1 ERROR TypeError: Cannot read property 'name' of undefined.
I need to enforce document definition like this, and specify document as an input :
<edm-document *ngFor="let document of documents" [document]="document" class="column is-one-quarter"></edm-document>
Now it works but seems a bit redundant to me as I defined a let
in loop. Does that mean the variable defined with let
is only available in tag where ngFor
directive is set ?
Am I missing something?
Thanks,
Nicolas
Upvotes: 4
Views: 4980
Reputation: 23529
it works but seems a bit redundant to me as I defined a let in loop
It is not as redundant as it might seem, which becomes obvious when rewriting things a bit:
When not explicitly defining what the component should use (with [document]="document"
in your example) then how would your component know that the parent variable is named document
? Consider:
<edm-document *ngFor="let d of documents" [document]="d"></edm-document>
One could argue that Angular could introduce some parent
variable to access the outer loop variable, but then the component would know how it's going to be used, and could only be used in a loop. Reusable components should not be aware of that.
How would it know that it can use that loop variable directly, and does not need some child property instead? Like:
<edm-document *ngFor="let d of documents" [document]="d.text"></edm-document>
So: your code is just fine.
Upvotes: 4
Reputation: 56
well you can also do something like this
<edm-document *ngFor="let document of documents" class="column is-one-quarter">
<span class="something">{{document.name}}</span>
</edm-document>
and in the edm-document.component.html do something like
<ng-content select=".something"></ng-content>
Upvotes: 1
Reputation: 41
The value (document) of the loop is valid inside of that block where the *ngFor placed. In your case between: <edm-document>..</edm-document>
In your example:
<edm-document *ngFor="let document of documents"class="column is-one-quarter">
<p>{{ document.name }}</p> <!-- document.name is valid -->
</edm-document>
<p>{{ document.name }}</p> <!-- document.name is invalid -->
Upvotes: 0
Reputation: 41533
Initially during DOM rendering the documents object will undefined
Use a typesafe ?
operator
<p>{{ document?.name }}</p>
Use a *ngIf
with a array length condition as below,
<span *ngIf="documents.length > 0">
<edm-document *ngFor="let document of documents" [document]="document"
class="column is-one-quarter"></edm-document>
</span>
Upvotes: 1