Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to push data into array in Angular 2 when using similar route

So far, I haven't found a simple example of how to push data into an array in Angular 2. In AngularJs it was easy (example), but I'm struggling for it in Angular 2, maybe because I'm using router and I don't know how to configure it (I was following the angular heroes example).

What I want to do, the whole solution:

app.module.ts:

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { HttpModule } from '@angular/http';
import { ProductsService } from '../services/ProductsService';


import { AppComponent } from "./components/app";
import { Products } from "./components/products";

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        RouterModule.forRoot([
            {
                path: 'products/:class_id/:type_id',
                component: Products
            }
        ], { useHash: true })
    ],
    exports: [RouterModule],
    declarations: [
        AppComponent
        Products
    ],
    providers: [
        ProductsService
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

AppComponent.ts

import { Component} from "@angular/core";

@Component({
    selector: "my-app",
    template: `<div>
                <a [routerLink]="['/products', 1, 1]">Products-1</a>
                <a [routerLink]="['/products', 2, 2]">Products-2</a>
               </div>`
})
export class AppComponent{}

ProductsService.ts

import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class ProductsService {

    private headers = new Headers({ 'Content-Type': 'application/json' });

    constructor(private http: Http) { }

    getProducts(class_id: string, type_id: string, index: number, numberOfObjectsPerPage: number): Promise<any> {
        return this.http.get('Home/GetProducts?pageIndex=' + index +'&classId=' + class_id + '&typeId=' + type_id)
            .toPromise()
            .then(response => response.json() as any)
            .catch(this.handleError);
    }

    private handleError(error: any): Promise<any> {
        console.error('An error occurred', error); // for demo purposes only
        return Promise.reject(error.message || error);
    }
}

Product.ts

import 'rxjs/add/operator/switchMap';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import * as $ from 'jquery';

import { ProductsService } from '../../services/ProductsService';
import { Product } from '../../common/models/Product';

@Component({
    selector: 'products',
    templateUrl: 'Products.html',
})
export class Products implements OnInit {
    products: Array<Product> = [];
    numberOfObjectsPerPage: number = 10;
    index: number = 0;
    constructor(
        private productsService: ProductsService,
        private route: ActivatedRoute
    ) {}

    ngOnInit(): void {
        this.loadProducts();
    }

    loadProducts():void{
        this.route.paramMap
            .switchMap((params: ParamMap) =>
                this.productsService.getProducts(params.get('class_id'), params.get('type_id'), this.index, this.numberOfObjectsPerPage))
            .subscribe(products => {
                this.products = products;
        });
    }

    showMore():void{
        this.index++;
        this.loadProducts();
    }
}

Products.html:

<div class="product" *ngFor="let product of products;">
  {{ product.name }}
</div>
<button (click)="showMore()">Show more</button>

So, what is the problem here: if I go to Products-1 I get 10 products, which is obvious, but if I press Show more then the first 10 products are removed and another 10 are shown - which again is obvious, so to avoid this and keep the first 10 and load 10 more, I replaced Product.ts -> this.products = products; to:

 for (let i = 0; i < products.length; i++) {
  this.products.push(products[i]);
 }

Another problem appears now: when I go to Product-2, the products from Products-1 are shown along with the products of Product-2, so to avoid this, I added this two lines into the Product.ts constructor:

constructor(private productsService: ProductsService, private route: ActivatedRoute) {
        route.paramMap.subscribe(params => this.products = []);
        route.paramMap.subscribe(params => this.index = 0);
}

Now, everything works just fine except: when I go from Products-1 to Products-2 and load more products, and after that return to Products-1, I can see in my network tab that multiple requests of same type are being send to my server.

So my questions are:

  1. Is there a better way to push data when using routing, and avoid to reset the parameters in the constructor ?
  2. If the pushing into the array is okay, and if it is okay to reset the parameters in the constructor, then, how to avoid multiple requests when going from one route to another ?
like image 459
ToTa Avatar asked Sep 09 '17 16:09

ToTa


People also ask

What would you use in angular 2 to define routes?

Instead of “href” attribute of anchor tag, we use the “routerLink” attribute of Angular. The routerLink attribute allows us to link to a specific route of the Application.


1 Answers

There are several things that I would add/change in product.ts:

  1. Add those properties under your index: number = 0; property:

    class_id: string;  
    type_id: string;
    
  2. Remove route.paramMap.subscribe from the constructor

  3. ngOnInit, should look like this:

    ngOnInit(): void {
      this.route.paramMap.subscribe(params => {
        this.products = [];
        this.index = 0;
        this.type_id = params.get('type_id');
        this.class_id = params.get('class_id');
        this.loadProducts();
      });   
    }
    
  4. And finally, loadProducts():

    loadProducts(): void {
      this.productsService.getProducts(this.class_id, this.type_id, this.index, this.numberOfObjectsPerPage).then(
        productArray => {
             this.products = this.products.concat(productArray);
        })
    }
    
like image 170
Ricka Avatar answered Oct 03 '22 05:10

Ricka