0

I want to assign a json response which contains an array with the following:

0 : {ID: 2, NAME: "asd", PWD_EXPIRY_IN_DAYS: 30}

1 : {ID: 1, NAME: "Admin", PWD_EXPIRY_IN_DAYS: 30}

I have a local variable of type groups, which is like so

    export class Group {
    id: string;
    name: string;
    pwd_expiry_in_days: string;
}

Now I created an object of type Group in my component which I want to assign the json reply into, the following is not working and is showing undefined. Here is my code:

    import { Injectable, Provider, ModuleWithProviders,Component, OnInit } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';

import { Observable } from 'rxjs/Observable';
import {Group} from '../../_models/group'
import 'rxjs/add/operator/map';


interface Validator<T extends FormControl> {
  (c: T): { [error: string]: any };
}

@Component({
  selector: 'form1',
  templateUrl: './form1.html',
  moduleId: module.id,
})
export class Form1Component {

  public roles: Group; // <--- variable to feed response into


   private getGroups() : Observable<any> {
    console.log("In Groups");
    var responseAsObject : any;
    let _url = groupsURL";
    let headers = new Headers();
    headers.append('X-User', sessionStorage.getItem('username'));
    headers.append('X-Token', sessionStorage.getItem('token'));
    headers.append('X-AccessTime', sessionStorage.getItem('AccessTime'));
    headers.append('Content-Type', 'application/json');
    let options = new RequestOptions({ headers: headers });

    return this.http.get(_url, options)
    .map(response => {
      var responseAsObject = response.json();
      console.log(responseAsObject); //<--- proper response
      return responseAsObject;
    })
}


  constructor(private http: Http) {

    this.getGroups()
    .subscribe(data => {
      this.roles = data;
      console.log(this.roles); //<--- proper response
    });

    console.log(this.roles); //<----- undefined, I need the roles variable so I can use it on the front end

}

How can I fix this? I've been told its an Async issue, simply assigning this.roles = data (from the json response) is not working and shows up as undefined in my component (anywhere outside the scope of the subscription).

What is the proper method of assigning a response into my local variable in this case?

UPDATED with template to view the object, also being viewed as undefined:

        <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['group_id'].valid}">
      <label>Group ID</label>
      <div class="row">
        <div class="col-md-4">
          <select name="group_id" id="group_id" class="form-control" [formControl]="complexForm.controls['group_id']" data-width='200px'>
    <option *ngFor="let role of roles" [value]="role.id">  
    {{role.name}}
    </option>
  </select>
        </div>
      </div>
    </div>

thank you!

Mustafa
  • 177
  • 6
  • 20
  • 1
    The 2nd console.log shouldn't see the data since it's not set there yet. But you should be able to use this.roles in your template since when it does evaluate the view will be updated accordingly – Amit Aug 30 '17 at 09:26
  • its not the case though, my template is seeing the object as undefined – Mustafa Aug 30 '17 at 09:42

2 Answers2

1

What is the proper method of assigning a response into my local variable in this case?

You're not doing it wrong. You just need to be better prepared for it for be undefined and/or empty at the initial stages of the component construction.

The easiest thing to do is simply do an *ngIf="someArray.length" on an html node before iteration. something like:

// html
...
<div class="row" *ngIf="roles.length"><!-- Prevents un-populated array iteration -->
    <div class="col-md-4">
        <select class="form-control">
            <option *ngFor="let role of roles" [value]="role.id">
                {{role.name}}
            </option>
        </select>
    </div>
</div>

There are some improvements you can make to your typescript as well, such as not changing the pointer of the array- this may save you some trouble later on -so instead of this.roles = data, use this.roles.length = 0; this.roles.push(...data);. For more info read up on Angular Change Detection.

// ts
export class Form1Component implements OnInit{
    public roles: Array<Group> = []; // <--- isn't this an Array?
    ...
    private getGroups() : Observable<any> {
        var responseAsObject : any;
        ...
        return this.http.get(_url, options)
            .map(response => {
                var responseAsObject = response.json();
                return responseAsObject;
            });
    }

    constructor(private http: Http) {}

    ngOnInit(){
        this.getGroups()
            .subscribe(data => {
                let groups = data.map(item=>{
                                return new Group(item)
                             });//<--- If you want it to be of type `Group`
                this.roles.length = 0;
                this.roles.push(...groups);
            });
    }
    ...
}
P. Moloney
  • 721
  • 8
  • 22
0

You second console log will run before your api call because api calls are asynchronous. Please try to make the type of role any like publice role: any if its works then you have to modify your Group model.

Suhel
  • 927
  • 8
  • 19