7

This is my UsersList component on clicking the table. A new page will be opened

enter image description here

Upon changing the user values and saving it, The saved value is not reflected in the grid for the first time. But when I do the same operation again it is getting reflected .

Below is my Save user code

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { UserService } from './../../shared/services/user.service';
import {User} from './../../shared/models/user';

@Component({
  selector: 'app-user-add-edit',
  templateUrl: './user-add-edit.component.html',
  styleUrls: ['./user-add-edit.component.css']
})
export class UserAddEditComponent implements OnInit {
   private user: User;
   private id:Number;
  constructor(private userService: UserService, private route: ActivatedRoute,private router: Router) { }

 ngOnInit() {
    this.id = Number(this.route.snapshot.params['id']);
    if (this.id) {
      this.userService.read(this.id).subscribe(
      users => this.user = users,
      err => {
        console.log(err);
      }
    );

     }

 }

 saveUser(){
   this.userService.update(this.user.client,this.user.firstName,this.user.lastName,this.user.id,this.user.key).subscribe(
      users => this.user = users,
      err => {
        console.log(err);
      }
    );
    this.router.navigateByUrl("users");
 }

}

What I did not understand was even though this.router.navigateByUrl("users"); is called after the save receives response from the observable, Why is not getting updated in the table for the first time?

User-Edit-Component

<div class="container">
    <h1 class='text-info' >Edit Users</h1>
    <div class="form-container">
        <form (ngSubmit)="saveUser()">
            <div class="form-group">
              <hr>
                <label for="name" class='text-info'><b> Client</b></label>
                <input type="text" name="client" [(ngModel)]="user.client" class="form-control" required />
            </div>
            <div class="form-group">
                <label for="name" class='text-info'><b>FirstName</b></label>
                <input type="text" name="firstName" [(ngModel)]="user.firstName" class="form-control" required />
            </div>
            <div class="form-group">
                <label for="name" class='text-info'><b>LastName</b></label>
                <input type="text" name="lastName" [(ngModel)]="user.lastName" class="form-control" required />
            </div>
            <div class="form-group">
                <a class="btn btn-default" routerLink="/users">Cancel</a>
                <button  class="btn btn-primary">Save</button>
                  <button class="btn xs btn-danger" (click)="deleteUser(user.id)">Delete</button>
            </div>
        </form>
    </div>
</div>

User Service

import { Router } from '@angular/router';
import { AuthService } from './auth.service';
import { Component, OnInit, Injectable } from '@angular/core';
import { Http, Request, RequestMethod, RequestOptions, Headers, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import {User} from './../../shared/models/user';

@Injectable()
export class UserService implements OnInit {
    private appContent = 'application/json';
    private _router: Router;
   private baseUrl = 'http://localhost:5000/api/v1/';

  //Constructor to initialize authService to authenticate user, http to send the CRUD request and Router for the resource 
  constructor(private authService: AuthService, private http: Http,private router: Router) {
  }
   ngOnInit() {
  }

  //For creating a user Client,Key,Firstname and lastName has to be passed 
   create(client: string, key: string, firstName: string, lastName: string) :Observable<boolean> {
        //createAuthenticatedRequest is called before sending the Http request 
        let request = this.createAuthenticatedRequest(JSON.stringify({client: client, key: key, firstName: firstName, lastName: lastName}),RequestMethod.Post);

       return this.http.request(request).map(r=>{
            r.ok;
        }).catch((error: any) =>{
        return Observable.throw(error);
        });

   }
   update(client: string, firstName: string, lastName: string,id: number, key: string) :Observable<any> {

         var request = this.createAuthenticatedRequest(JSON.stringify({client: client, key: key, firstName: firstName, 
            lastName: lastName, id:id}),RequestMethod.Put, id.toString());
       return this.http.request(request).map(r=>{
            r.json;
            console.log(r);
        }).catch((error: any) =>{
            console.log(error);
        return Observable.throw(error);
        });

   }
   delete(client: string, key: string, firstName: string, lastName: string,id: number):Observable<boolean> {

     var request = this.createAuthenticatedRequest(JSON.stringify({client: client, key: key, firstname: firstName, lastName: lastName}),RequestMethod.Delete, id.toString());
       return this.http.request(request).map(r=>{
            r.ok;
        }).catch((error: any) =>{
        return Observable.throw(error);
        });

   }

   //Read method takes an optional input id, If id is not passed to read it will get the entire list , else it will get the record with specified id
   read(id?: Number):Observable<any> {

         id = (id == undefined) ? 0 : id ;

        if (id >0)
            // Get single resouce from Collection
            var request = this.createAuthenticatedRequest(null,RequestMethod.Get, id.toString());
        else
           // Get the entire collection
             request = this.createAuthenticatedRequest(null,RequestMethod.Get, id.toString());

        return this.http.request(request).map(r=>{
           console.log(r.text());
            return  JSON.parse("[" + r.text() + "]")[0];
        }).catch((error: any) =>{
        return Observable.throw(error);
        });
   }



   //This method accepts json of the attribtes client,key,firstname and lastName and request method(Post/Get/Put/delete) and 
   //an optional parameter id , This method's return type is Request
   createAuthenticatedRequest(json : string, reqMethod: RequestMethod, optionalparam?: string) : Request{
        //checks if the user is authenticated user with authentication service method isAuthenticated
         if (this.authService.isAuthenticated()) {
            console.log('authenticated');
            optionalparam =(optionalparam==undefined || optionalparam =='0') ? "" : optionalparam;
            const request = new Request({
                method: reqMethod,
                url: this.baseUrl + 'creds/' + optionalparam +"",
                body: json
               });
               //request header Authorization is added to specify that the request has an authenticated token
            request.headers.append('Authorization', 'Bearer ' + this.authService.getToken());
            request.headers.append('Content-Type', this.appContent);
            request.headers.append('Accept', this.appContent);
            return request;
            } 

        else {
             console.log('notauthenticated');
             this._router.navigateByUrl('/login');
        }    



   }

}

Userlist COmponent

import { Component, OnInit,NgZone } from '@angular/core';
import { UserService } from './../../shared/services/user.service';
import { Router } from '@angular/router';
import { AuthService } from './../../shared/services/auth.service';
import { Http, Request, RequestMethod, RequestOptions, Headers, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import {User} from './../../shared/models/user';

@Component({
  selector: 'app-userlist',
  templateUrl: './userlist.component.html',
  styleUrls: ['./userlist.component.css']
})
export class UserlistComponent implements OnInit {
    private appContent = 'application/json';
   private baseUrl = 'http://localhost:5000/api/v1/';
   private users: User[];

  constructor(authService: AuthService, private http: Http,private router: Router, private userService: UserService) {

  }

  ngOnInit() {

    console.log("Test");
   this.userService.read().subscribe(
      users => this.users = users,

      err => {
        console.log(err);
      }
    );  
  }

  editUser(id) {

    this.router.navigateByUrl('/users/edit/'+id);
  }


}

Userlist Template

<h1 class='text-info' >Users</h1>
<hr>
<div class="container">
<table class="table table-hover table-bordered thead-inverse">
  <thead>
    <tr class="bg-success">
        <th>Client</th>
        <th>FirstName</th>
        <th>LastName</th>
    </tr>
     </thead>
    <tbody>  
    <tr *ngFor="let user of users" (click)="editUser(user.id)">
      <td>{{user.client}}</td>
        <td>{{user.firstName}}</td>
        <td >{{user.lastName}}</td>
    </tr>
     </tbody>
</table>
</div>

I appreciate if someone can help me on this.

Vega
  • 27,856
  • 27
  • 95
  • 103
karthik gorijavolu
  • 860
  • 3
  • 14
  • 28
  • can you show me the userService.update? – bgraham Oct 05 '17 at 15:44
  • also can we see the component code for your user table? – bgraham Oct 05 '17 at 15:45
  • Thanks @bgraham for your reply added the required – karthik gorijavolu Oct 05 '17 at 16:05
  • How does your component look like that you are routing too? Where does it fetch the users? And by the way, you are navigating away from component most likely before you have received the response. – AT82 Oct 05 '17 at 17:18
  • @AJT_82 Can you check the services and components you will get an idea – karthik gorijavolu Oct 05 '17 at 17:21
  • I did check. But I don't see where you are getting your users. You are obviously navigating away before getting the response back, but if you are refetching it in another component and fetching them all over again. I don't know. Anyway, move the navigation to inside the callback (subscribe) to ensure you have gotten your response before navigating. – AT82 Oct 05 '17 at 17:24
  • @AJT_82 Can you check now I have added the complete code – karthik gorijavolu Oct 05 '17 at 17:38
  • Still I can't see the component you are navigating to... i.e what does this component look like that you are navigating to? `this.router.navigateByUrl("users");` – AT82 Oct 05 '17 at 17:44
  • @AJT_82 Can you please check now – karthik gorijavolu Oct 05 '17 at 18:18

3 Answers3

2

Try changing:

saveUser(){
   this.userService.update(this.user.client,this.user.firstName,this.user.lastName,this.user.id,this.user.key).subscribe(
      users => this.user = users,
      err => {
        console.log(err);
      }
    );
        this.router.navigateByUrl("users");
}

To:

async saveUser(){
   await this.userService.update(this.user.client,this.user.firstName, 
     this.user.lastName,this.user.id,this.user.key)
     .toPromise()
     .then( users => this.user = users)
     .catch( err => console.log(err) );
   this.router.navigateByUrl("users");
}

Or:

saveUser(){
   this.userService.update(this.user.client,this.user.firstName,
     this.user.lastName,this.user.id,this.user.key).subscribe(
     users => { 
         this.user = users;
         this.router.navigateByUrl("users");
      },
      err => {
        console.log(err);
      }
    );            
}
ttugates
  • 5,818
  • 3
  • 44
  • 54
1

I was also facing the same problem. The thing which worked for me was that on successfully saving the details of the user, I called the function in the service which was fetching the whole user list. So, In this way, User list got updated to the latest.

So, In your saveUser function,After update function of userService, call the read function of your userService. It should update your userList.

Humble Dolt
  • 940
  • 2
  • 16
  • 31
0

Maybe Angular is reusing your component as the route remains the same, thus not firing ngOnInit again? Try placing your user load logic in the userlist.component in an ngOnChanges or ngAfterViewInit hook instead of ngOnInit, like this:

ngAfterViewInit() {

    console.log("Test");
   this.userService.read().subscribe(
      users => this.users = users,

      err => {
        console.log(err);
      }
    );  
  }

Another approach that you could try is to subscribe to a route change event in your ngOnInit hook, and then refresh the data. Something like the answer to this question:

this.router.events.subscribe((event) => {
 // your refresh logic
}
Fjut
  • 1,314
  • 12
  • 23