I am having issues with learning angular, I didn't used 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 using 2 different mechanisms (microservice, service component serving an obhject directly). This particular one is the best example. The code below works fine, but the code below that doesn't pass the cards 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 >
<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 >
<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:
CodePudding user response:
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[] = [];