1

I'm returning an object from server and when I'm trying to assign the object to a variable in an angular component object I'm receiving an exception. Does somebody know what I'm missing?

product-component.ts

import { Component, OnInit } from '@angular/core';
import { Product } from './product';
import { ProductsService } from './products.service';
import { ActivatedRoute, Params }   from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/map';

@Component({
  selector: 'product',
  templateUrl: './app/products/product.component.html'
})
export class ProductComponent implements OnInit {
    data: Product;

    constructor(private productSrv: ProductsService, 
                private route: ActivatedRoute) {}

    ngOnInit() {
        this.route.params.map( params => params['id'] ).subscribe(
            id => { 
                if (id)
                    this.productSrv.obtainProduct(+id).subscribe(
                            product => {
                                console.log(product);
                                this.data = <Product>product;
                            },
                            error => console.log(error));
                else 
                    this.data = <Product> {
                            id: 0,
                            name: '',
                            code: ''
                        };
           },
           error => console.log(error));
    }
}

products-service.ts

import { Product } from './product';
import { PagingDetails } from './paging-details';
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

@Injectable()
export class ProductsService {

    constructor(private http: Http) { }

    obtainProduct(id: number): Observable<Product> {
        return this.http.get('/srv/product/' + id)
                        .map(this.extractData2)
                        .catch(this.handleError);
    }

    private extractData2( res: Response ): Product {
        let body = res.json();
        console.log(body);
        return <Product> (body || {});
    }

    private handleError( error: Response | any ) {
        // In a real world app, you might use a remote logging infrastructure
        let errMsg: string;
        if ( error instanceof Response ) {
            const body = error.json() || '';
            const err = body.error || JSON.stringify( body );
            errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
        } else {
            errMsg = error.message ? error.message : error.toString();
        }
        console.error( errMsg );
        return Observable.throw( errMsg );
    }
}

product.ts

export interface Product {
    id: number;
    name: string;
    code: string;
}

Exception Exception image

david
  • 109
  • 8
  • And where is this `co.data`? You haven't provided http://stackoverflow.com/help/mcve . Nobody can debug the application for you. – Estus Flask Apr 18 '17 at 13:11

1 Answers1

0

I managed to reproduce the issue, so it seems that in Firefox, if you do not safeguard null/undefined values, there is an co. error thrown, in this case, co.data since data is undefined. You are probably trying to use this in your template, e.g

<div>{{data.code}}</div>

and at the point when template is rendered, data is undefined. You can solve this using the safe navigation operator in your template:

<div>{{data?.code}}</div>

... or *ngIf. More here: Cannot read property "totalPrice" of undefined

When this is solved, you will instead get undefined in your console. The issue is the casting in your subscribe:

.subscribe(product => {
    console.log(product);
    this.data = <Product>product; // here
}

This seemingly causes data to be undefined. Remove the casting, as you have already marked data to be of type Product. So change it to simply:

.subscribe(product => {
    console.log(product);
    this.data = product; // here
}

So the above should solve your issue. Even though you make the changes in the subscription, so that data won't be undefined, you must safeguard null/undefined values by using for example the safe navigation operator in the template as the http-request is asynchronous and at the time template is rendered data will be undefined.

Community
  • 1
  • 1
AT82
  • 71,416
  • 24
  • 140
  • 167