I am trying to export common HTML structures (like a bootstrap navbar) into Angular components. Here is my components HTML:
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">{{navBarTitle}}</a>
</div>
<ul class="nav navbar-nav">
<li *ngFor="let item of navBarItems">
<a href="#">{{item.display()}}</a> <!-- The Problem is here -->
</li>
</ul>
</div>
</nav>
Here is the component class:
@Component({
selector: 'bs-navbar',
templateUrl: './bs-navbar.component.html',
styleUrls: ['./bs-navbar.component.css']
})
export class BsNavbarComponent implements OnInit {
@Input() private navBarTitle: string = "Klassenliste";
@Input() private navBarItems: Clazz[] = [];
constructor() { }
ngOnInit() {
}
}
The usage looks like this:
<bs-navbar
navBarTitle="Classes"
[navBarItems]="classes">
</bs-navbar>
An important thing to note is that the classes array is being fetched from
a server in ngOnInit() using the HttpModule.
this.getClasses() // returns an Observable<Clazz[]>
.catch(error => {
console.error(` * ERROR * : ${error}`);
throw new Error(error);
})
.subscribe((clazzes: Clazz[]) => {
console.log(`Fetched classes`);
console.log(clazzes);
this.classes = clazzes;
});
private getClasses(): Observable<Clazz[]> {
return this.http
.get("/api/classes")
.map(response => response.json() as Clazz[]);
}
The items in the collection navBarItems do implement the display method:
export class Clazz { // Edited to "Clazz", just in case
id: number;
name: string;
// constructor etc.
display(): string {
if(this.name) {
return this.name;
}
return "---";
}
}
However, when I run this, the {{item.display()}} call does not seem to return anything. The link just appears with empty text.
When I substitute the {{item.display()}} call with {{item.name}}, the name is displayed correctly. However I'd like this setup to work with any class that implements the display() method.
The console throws the following error:
ERROR TypeError: _v.context.$implicit.display is not a function
at Object.eval [as updateRenderer] (BsNavbarComponent.html:8)
at Object.debugUpdateRenderer [as updateRenderer] (core.js:14727)
at checkAndUpdateView (core.js:13841)
at callViewAction (core.js:14187)
at execEmbeddedViewsAction (core.js:14145)
at checkAndUpdateView (core.js:13837)
at callViewAction (core.js:14187)
at execComponentViewsAction (core.js:14119)
at checkAndUpdateView (core.js:13842)
at callViewAction (core.js:14187)
Sorry if I am missing something obvious here, I am kind of new to Angular.
If you simply typecast a JSON object to a class[], as in:
response.json() as Clazz[]
.. you don't get all the class methods. It's only indicating to Typescript that the type is compatible. Remember that Typescript compiles down to JavaScript which doesn't allow you to directly parse json into a function or ES6 class.
You need to iterate over each item, instantiate a new instance of the class, and fill in the data from there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With