Search code examples
ngforangular2-observables

How to capture and display data from Observable?


I have a component named 'customer.component.ts'. In this component's view there is a button called 'Search'. What I I am doing is calling a web api method on this 'Search' button click which brings the data from sql db.

For this, I have a customer.service.ts file in which I wrote the below code -

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import "rxjs/add/operator/map";
import 'rxjs/add/operator/toPromise'; 
import { Customer, CustomerContact, CustomerHeaderAndContactsResponse, CustomerSearchRequestObjectClass, CustomerHeaderAndContactsResponse_Read } from '../models/customer';

@Injectable()
export class CustomerService {
    constructor(private _http: Http) {

    }

    baseUrl: string = 'http://localhost/SampleApi/api/Customer/';

searchCustomers(custReqObj: CustomerSearchRequestObjectClass): observable<CustomerHeaderAndContactsResponse_Read> {        
                    let headers = new Headers();
                    headers.append('Content-Type', 'application/json; charset=utf-8');
                    return this._http.post((this.baseUrl + 'search-customer'), JSON.stringify(custReqObj), { headers: headers }).map(res => res.json());
                }
}

my customer.component.ts has the search click function -

import { Component, OnInit } from '@angular/core';
import { strictEqual } from 'assert';
import { ChangeDetectorRef } from '@angular/core';
import { stringify } from '@angular/core/src/facade/lang';
import { Customer, CustomerContact, CustomerHeaderAndContactsResponse_Read } from '../models/customer';
import { Observable } from 'rxjs/Observable';  
import { CustomerService } from '../services/customer.service';
import { ChangeDetectionStrategy } from '@angular/core/src/change_detection/constants';
import { forEach } from '@angular/router/src/utils/collection';
import { AsyncPipe } from '@angular/common';
import { error } from 'util';
import { parse } from 'path';
import { Subscriber } from 'rxjs/Subscriber';

declare var $: any;

@Component({
    selector: 'customer',
    templateUrl: 'app/customer/views/customer.component.html',
})
export class CustomerComponent implements OnInit {
    constructor(private changeDetectorRef: ChangeDetectorRef, private _custSvc: CustomerService) {      
    }

    ngOnInit() {}



customerSearch: CustomerHeaderAndContactsResponse_Read = new CustomerHeaderAndContactsResponse_Read();

 onCustomerSearchClick(): void {

        this._custSvc.searchCustomers(this.custSearchReqObj).subscribe(
            data => {
                this.customerSearch = data;     
            },
            err => console.log(err, 'error has occurred'),
            () => console.log(this.customerSearch)
        );
console.log(this.customerSearch);
 }

And below is my model class -

export class CustomerHeaderAndContactsResponse_Read
{
    custHeader:Customer[];
    custContact:CustomerContact[];
}

Both Customer and CustomerContact classes contain some properties.

And finally here is my template where I am trying to iterate through the object the table rows simply don't display any data. I have used async (AsyncPipe) also but not helping much.

<tr *ngFor="let custItem of customerSearch.custHeader | async; let rowIndex = index">
                                    <td>
                                        <a (click)="onCustomerItemDetailsClick(custItem.acCustomerName, rowIndex)" class="btn">{{custItem.acCustomerName}}</a>
                                    </td>
                                    <td>{{custItem.acCountryId}}</td>
                                    <td>{{custItem.acAreaId}}</td>
                                    <td>{{custItem.acTel}}</td>
                                    <td>{{custItem.acFax}}</td>
                                    <td>{{custItem.acSalesContact}}</td>
                                    <td>
                                        <a (click)="onCustomerContactItemDeleteClick(rowIndex, 'manage-customer')" class="btn" id="btnIconDelete">
                                            <span class="glyphicon glyphicon-trash"></span>
                                        </a>
                                    </td>
                                </tr>

Please help as I am not unable to understand what/where I am doing mistake. Do let me know if more information is required.

Thanks in advance! [email protected]

EDIT -

Tried with BehaviorSubject approach, but now getting an erro like below -

Observable error


Solution

  • The async pipe is used to bind observables directly to the template. So here's what you can do:

    data$: Observable<CustomerHeaderAndContactsResponse_Read>;
    search$ = new BehaviourSubject<boolean>(true);
    
    ngOnInit() {
      this.data$ = this.search$.switchMap(searchObj => this._custSvc.search...(...));
    }
    
    onCustomerSearchClick() {
      this.search$.next(true);
    }
    

    And the template looks like this

    <tr *ngFor="let item of data$ | async>...</tr>
    

    So now every time your search is clicked, it will send a call to the service and the async pipe is taking care of displaying the data in the template