'Angular not passing object to html page
I am having issues with learning angular, I didn't use to have these problems before, but now when I do these demos things work great until I switch from using an object directly defined in the *.component.ts file to pulling the object from somewhere else. In 2 different instances use 2 different mechanisms (microservice, service component serving an object directly). This particular one is the best example. The code below works fine, but the code below that doesn't pass the card object to the page. Debug is showing that the object is being filled, but when it gets to the HTML page it is undefined.
import { Component } from '@angular/core';
import { map } from 'rxjs/operators';
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { AppService } from '../app.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent {
/** Based on the screen size, switch from standard to one column per row */
//cards = [];
cardsForHandset = [];
cardsForWeb = [];
//isHandset: boolean = false;
cards = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
map(({ matches }) => {
if (matches) {
return [
{ title: 'Card 1', cols: 2, rows: 1 },
{ title: 'Card 2', cols: 2, rows: 1 },
{ title: 'Card 3', cols: 2, rows: 1 },
{ title: 'Card 4', cols: 2, rows: 1 }
];
}
return [
{ title: 'Card 1', cols: 2, rows: 1 },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 2 },
{ title: 'Card 4', cols: 1, rows: 1 }
];
})
);
constructor(private breakpointObserver: BreakpointObserver,
public appService: AppService,
) { }
}
HTML
<div class="grid-container">
<h1 class="mat-h1">Todays Deals</h1>
<mat-grid-list cols="2" rowHeight="350px">
<mat-grid-tile *ngFor="let card of cards | async" [colspan]="card.cols" [rowspan]="card.rows">
<mat-card class="dashboard-card">
<mat-card-header>
<mat-card-title>
{{card.title}}
</mat-card-title>
</mat-card-header>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
</div>
This is the code that doesn't work.
import { Component } from '@angular/core';
import { map } from 'rxjs/operators';
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { AppService } from '../app.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent {
/** Based on the screen size, switch from standard to one column per row */
cards = [];
cardsForHandset = [];
cardsForWeb = [];
isHandset: boolean = false;
isHandsetObserver: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
map(({ matches }) => {
if (matches) {
return true;
}
return false;
})
);
constructor(private breakpointObserver: BreakpointObserver,
public appService: AppService,
) { }
ngOnInit() {
this.isHandsetObserver.subscribe(currentObserverValue => {
this.isHandset = currentObserverValue;
this.loadCards();
this.cards.push();
});
this.appService.getDeals().subscribe(
response => {
this.cardsForHandset = response.handsetCards;
this.cardsForWeb = response.webCards;
this.loadCards();
},
error => {
// alert('There was an error in receiving data from server. Please come again later!');
}
);
}
loadCards() {
this.cards = this.isHandset ? this.cardsForHandset : this.cardsForWeb;
}
}
HTML - Is the same above, but with the async removed.
Service
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AppService {
constructor(public httpClient:HttpClient) { }
getDeals(): Observable<any> {
return this.httpClient.get('http://localhost:3000/deals');
}
}
Server Side Microservice
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
let jsaonResponse = {
"handsetCards": [
{ title: 'Card 1', cols: 2, rows: 1 },
{ title: 'Card 2', cols: 2, rows: 1 },
{ title: 'Card 3', cols: 2, rows: 1 },
{ title: 'Card 4', cols: 2, rows: 1 }
],
"webCards": [
{ title: 'Card 1', cols: 2, rows: 1 },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 2 },
{ title: 'Card 4', cols: 1, rows: 1 }
]
}
res.json(jsaonResponse);
});
module.exports = router;
Here are the errors:
Solution 1:[1]
This is a typescript typing error. Due to cards
being an array and your getDeals
returning a single object typescript doesn't know what that type is.
A good solution would be to create a model:
card.model.ts
:
export interface Cart {
title: string;
cols: number;
rows: number;
}
getDeals
in app.service.ts
would return an array of Card
(don't forget to import your model):
getDeals(): Observable<Card[]> {
return this.httpClient.get('http://localhost:3000/deals');
}
And your variables in home.component.ts
would look like this:
cards: Card[] = [];
cardsForHandset: Card[] = [];
cardsForWeb: Card[] = [];
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Halil Bahar |