I'm having some trouble displaying my data in the browser. To explain my problem I'm using some dummy code. I have some nested objects that are causing my problem. Here I'll display one nested object to showcase my problem.
First of all, I only make http calls for the Car-object. So saveCar acts like updating the car as well, depending on what the user does in the app. All the methods in the service works as they should.
So my service looks something like this:
@Injectable()
export class Service {
constructor(private http: Http) { }
saveCar(car: Car) {
return this.http.post ....
}
getCars(){
return this.http.get...
}
getById(id: string) {
return this.http.get...
}
}
Then I have a Car-class, where the nested object "Brand" comes in to play, Brand then has it's own class, but I'll leave it out.
export class Car {
private brands: Array<Brand>;
constructor(public id: string, public name: string) {
this.brands = new Array<Brand>();
}
public getBrands(): Array<Brand> {
return this.brands;
}
public addBrand(value: Brand): void {
this.brands.push(value);
}
//some other methods.
}
Then I have a list-component that lists all cars, this works as it should!
@Component({
selector: 'car-list',
template: `
<h1>Add Car</h1>
<form (submit)="saveCar()">
<input required [(ngModel)]="name" placeholder="Add car">
</form>
<br>
<table>
<tr *ngFor="let car of cars" >
<td>{{car.name}}</td>
<td><button (click)="goToDetail(car)">Detail</button></td>
</tr>
</table>
`,
})
export class ListComponent implements OnActivate {
id: string
name: string;
cars: Array<Car>
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(): void {
this._service.getCars()
.subscribe(cars => this.cars = cars);
}
saveCar() {
let car = new Car(this.id, this.name)
this._service.saveCar(Car)
.subscribe(car => this.cars.push(car));
this._service.getCars()//
.subscribe(cars => this.cars = cars);
}
goToDetail(car:Car) {
this._router.navigate(['/cardetail', car.id]);
}
}
The problem I have is in the detail-component, where the user gets navigated after clicking a specific car. The routing and retrieving the Car from the db works as it should. That I know, because if I remove all the template except <h1>Car: {{car?.name}}</h1> the name gets printed out fine with the elvis operator.
But my detail-component looks something like this:
@Component({
selector: 'car-detail',
template: `
<h1>Car: {{car?.name}}</h1>
<hr>
<button (click)="addBrand()">Add Brand</button>
<div *ngFor="let brand of car.getBrands(); let i=index">
<h2>Brand {{i+1}}</h2>
</div>
`,
})
export class DetailComponent implements OnActivate {
@Input() car: Car;
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(curr: RouteSegment): void {
let id = curr.getParam('id');
this._service.getById(id)
.subscribe(car => {
this.car = car;
});
}
addBrand() {
this.car.getBrands().push(new Brand());
}
//some other methods
}
So in my detail component I call all methods like: car.someMethod() and further on the nested Brand object like: brand.someMethod() in the template. So the error comes at the call of the method e.g in the template 'cannot get getBrands of undefined' I've tried putting the elvis operator like this: car?.getBrands() It doesn't work. I've tried to wrap the whole thing in a div, both with elvis operator and a <div *ngIf = "car"></div>, doesn't work. Even tried with <template *ngIf="car"></template>, well that doesn't work either....
Edit: my mess-up, wrapping like below, it does "kind of" work, meaning, it gives a new error....
Template:
@Component({
selector: 'car-detail',
template: `
<h1>Car: {{car?.name}}</h1>
<hr>
<button (click)="addBrand()">Add Brand</button>
<div *ngIf="car">
<div *ngFor="let brand of car.getBrands(); let i=index">
<h2>Brand {{i+1}}</h2>
</div>
</div>
?tocar?.getBrands()? Do you get the error in initial rendering or when you click theAdd Brandbutton??at both? Might sound like a dumb question but from your question and comments you tried adding?first at{{car?.name}}and then at... of car?.getBrands()but it needs to be added at both.getBrands() of undefinedeven though I have it on both places.