good.learner
good.learner

Reputation: 121

angular 2 - http get returns empty array

My Component code:

products: Product[];
constructor(private productService: ProductService) { }

ngOnInit() {
    this.productService.getProducts()
        .subscribe(
        (products: Product[]) => {
            this.products = products;
        }
        );
}

My HTML Code:

                <tr *ngFor="let product of products">
                    <td>
                        <a [routerLink]="['/product-details', product.SKU]">{{ product.SKU }} </a>
                    </td>
                    <td>
                        <a [routerLink]="['/product-details', product.SKU]">{{ product.mrp }} </a>
                    </td>
                </tr>

My Service Code:

getProducts() {
    return this.http.get('http://localhost:3000/product')
        .map((response: Response) => {
            const products = response.json().obj;

            let transformedMessages: Product[] = [];
            for (let product of products) {
              transformedMessages.push(new Product(product.SKU, product.mrp, 111, 111));
            }
            this.products = transformedMessages;
            return transformedMessages;

            return products;

        })
        .catch((error: Response) => Observable.throw(error.json()));

My Backend route:

router.get('/', function (req, res, next) {
    Product.find().exec(function (err, products) {
        if (err) {
            return res.status(500).json({
                title: 'An error occurred',
                error: err
            });
        }
        res.status(200).json({
            message: 'Success',
            obj: products        //obj comes from here
        });
    });
});

Response:
{
"message": "Success",
"obj": [
{
"0": {
"SKU": "V2620151BR",
"Batch": "1",
"Folder Number": "85",
"MRP": "799",
"Size": "Free",
"Color": "Yellow",
},

My Backend Model Class:

var schema = new Schema({
    sku: { type: String, required: true, unique: true },
    mrp: { type: Number }
});

My Frontend Model:

export class Product {
    constructor(
        public SKU: string,
        public mrp: number,
        public selling_price: number,
        public current_inventory: number
    ) { }
}

enter image description here

My http://localhost:3000/product reutrns the json response correctly. But somehow in the HTML, when the page loads everything is empty.
I am only getting one value - empty empty 111 111

Most of the things are setup fine, I am not sure why the empty HTML when I get the response back from http://localhost:3000/product

Upvotes: 1

Views: 3516

Answers (2)

Pranay Rana
Pranay Rana

Reputation: 176896

I better suggest make change in your backend code and try to return json string structure like

Response:
{
"message": "Success",
"obj": [
{
"ProductId": "0",
"SKU": "V2620151BR",
"Batch": "1",
"Folder Number": "85",
"MRP": "799",
"Size": "Free",
"Color": "Yellow",
},
}

that will resolve your issue , without not much code change in front end i.e. in angular part


if you are not getting sturcture of reponse properly I sugest you make use of this potal : http://json2ts.com/ which helps to convert json string to typscript object.

for this structure given by you : { "0": { "SKU": "V2620151BR", "MRP": "799" }}

this is typescript object got created.

declare module namespace {
    export interface ProductDetail{
        SKU: string;
        MRP: string;
    }

    export interface ProductRoot{
        productDetail: ProductDetail;
    }
}

if you have above kind of structure than your code will be as below (i havent run code at my end but if there is any error please inform it should be like that only )

 getProducts() : Observable<Array<ProductDetail>>
     {
          return this.http.get('http://localhost:3000/product')
            .map((response: Response) => {
               debugger;//try to debug this part specially response returned 
                        //for server 
               let resproducts:Array<ProductRoot> = response.json().obj;

               let transformedMessages: ProductDetail[] = [];
              for (let product of resproducts) {
                 transformedMessages.push(new ProductDetail(product.productDetail.SKU, product.productDetail.mrp, 111, 111));
             }
              return transformedMessages;
        })
        .catch((error: Response) => Observable.throw(error.json()));

code in component

products: ProductDetail[];
constructor(private productService: ProductService) { }

ngOnInit() {
    this.productService.getProducts()
        .subscribe(
        (products: Product[]) => {
            this.products = products;
        }
        );
}

i suggest not to give same name to propeties , better keep name different - try below code

I am guessing here that your server code is returning json array of product

 getProducts() 
 {
      return this.http.get('http://localhost:3000/product')
        .map((response: Response) => {
           debugger;//try to debug this part specially response returned 
                    //for server 
           let resproducts:Array<Product> = response.json();

           let transformedMessages: Product[] = [];
          for (let product of resproducts) {
             transformedMessages.push(new Product(product.SKU, product.mrp, 111, 111));
         }
          return transformedMessages;
    })
    .catch((error: Response) => Observable.throw(error.json()));

component code

products: Product[];
constructor(private productService: ProductService) { }

ngOnInit() {
    this.productService.getProducts()
        .subscribe(
           (res) => {
               this.products = res;
             }
        );
}

Upvotes: 1

andrea06590
andrea06590

Reputation: 1299

You are subscribing to the empty array in your case, because the return is executed before getting all the data. That's why it is better to use Promise

return this.http.get(url)
        .toPromise()
        .then((response) => {doSomething()});

If you want to keep your code, try to create an initial empty product and a real BehaviorSubject and emit the new value, then subscribe to this :

this.initialProduct = EMPTY_PRODUCT;

changeProduct: BehaviorSubject<Product or any> = new BehaviorSubject(this.initialProduct)

then just before the return this.changeProduct.emit(product); and subscribe to the answer instead of the get function : this.changeProduct.subscribe((product) => {doSomething()};

Upvotes: 1

Related Questions