1
votes

I am new to angular and started leaning angular 4. Data not binding with ngfor directive on a component using the async pipe. Please help

user service uses HTTP request to get data from API:

user.service.ts

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import { User } from "../Models/user";

@Injectable()
export class UserService {
    constructor(private http: Http) { }

    get(url: string): Observable<User[]> {
        return this.http.get(url)
            .map(response => response.json() as User[])
            // .do(data => console.log("All: " + JSON.stringify(data)))
            .catch(this.handleError);
    }
    private handleError(error: Response) {
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }
}

Here i am using observable User[] interface for user list:

user.component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { UserService } from '../Services/user.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { User } from '../Models/user';
import { DBOperation } from '../Shared/enum';
import { Observable } from 'rxjs/Observable';
import { Global } from '../Shared/global';

@Component({
    templateUrl: 'app/Components/user.component.html'
})

export class UserComponent implements OnInit {
    @ViewChild('modal') modal: ModalComponent;
    users$: Observable<User[]>;
    user: User;
    msg: string;
    indLoading: boolean = false;
    userForm: FormGroup;
    dbops: DBOperation;
    modalTitle: string;
    modalBtnTitle: string

    constructor(private fb: FormBuilder, private userService: UserService) 
   { }

   ngOnInit(): void {
    this.userForm = this.fb.group({
        Id: [''],
        UserName: ['', Validators.required],
        Password: ['', Validators.required],
        FirstName: ['', Validators.required],
        LastName: ['', Validators.required],
        Gender: ['', Validators.required]
    });
    this.LoadUsers();
    }
    LoadUsers(): void {
        this.indLoading = true;
        this.users$ = this.userService.get('http://localhost:29712/api/userapi/');
        this.indLoading = false;
    }   
}

Template for the async pipe to subscribe observable users variable:

user.component.html

<div class='panel panel-primary'>
    <div class='panel-heading'>
        User Management
     </div>
     <div class='panel-body'>
         <div class='table-responsive'>
        <div class="alert alert-info" role="alert" *ngIf="indLoading"><img src="../../images/loading.gif" width="32" height="32" /> Loading...</div>
        <div *ngIf='users && users.length==0' class="alert alert-info" role="alert">No record found!</div>
        <table class='table table-striped' *ngIf='users && users.length'>
            <thead>
                <tr>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Gender</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let user of users$ | async">
                    <td>{{user.FirstName}}</td>
                    <td>{{user.LastName}}</td>
                    <td>{{user.Gender}}</td>
                </tr>
            </tbody>
        </table>
        <div>
        </div>
    </div>
    <div *ngIf="msg" role="alert" class="alert alert-info alert-dismissible">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
        <span class="sr-only">Error:</span>
        {{msg}}
    </div>
</div>

2
Since you are subscribing, you should not need the async pipe.DeborahK
Your /api/userapi/ request will be executed twiceyurzui
i'd check if response => response.json() as IUser[] resolves to null. are you sure that service responds with the same data structure as your IUser is?dee zg
@deezg His response is correct. Look at template ngIf="users && users.length" where users is Observableyurzui
Yes, I am also getting users json array in LoadUsers functionSajan Chhipa

2 Answers

0
votes

Since you are using async. Try removing susbcribe. on your original code. Here's a video of something similar. It's really helpful to use $ for Observable properties...

0
votes

Your *ngIf is making issue you cannot check directly your observable length without async pipe. Try this,

*ngIf="(users$ | async)?.length==0"