1

I have a service :

@Injectable()
export class LostFoundEditService {
    public lostForm: FormGroup;
    public countries: any[] = [];
    private countriesUrl = 'assets/countries.json';

    constructor(private http: HttpClient) { }

    init() {
        this.initForm();

        this.http.get(this.countriesUrl).subscribe(data => {
            this.countries = this.countries.concat(data['countries']);
        },
        (err: HttpErrorResponse) => {
            console.log(err.message);
        });
    }

    private initForm() {
        this.lostForm = new FormGroup({
            'title': new FormControl('', Validators.required),
            'description': new FormControl('', Validators.required),
            'country': new FormControl('', Validators.required),
            'state': new FormControl('', Validators.required),
            'city': new FormControl('', Validators.required),
            'zipCode': new FormControl(''),
            'street': new FormControl('')
        });
    }
}

and a class thats uses this service :

@Component({
  selector: 'app-lost-edit',
  templateUrl: './lost-edit.component.html',
  styleUrls: ['./lost-edit.component.css']
})
export class LostEditComponent implements OnInit {
  lostForm: FormGroup;
  countries: any[] = [];
  states: any[] = [];
  cities: any[] = [];

  constructor(
    private http: HttpClient,
    private lostFoundEditService: LostFoundEditService) { }

  ngOnInit() {
    this.lostFoundEditService.init();
    this.lostForm = this.lostFoundEditService.lostForm;
    this.countries = this.lostFoundEditService.countries;
  }

  onCancel() {
  }

}

Also I have the template associated with that class :

(...)
                  <select
                    id="country"
                    formControlName="country"
                    class="form-control">
                    <option value="">Countries</option>
                    <option *ngFor="let country of countries" value="{{country['id']}}">{{country['name']}}</option>
                  </select>
                </div>
            </div>
          </div>
          (...)

My question is : how to wait for the end of subscribe method (in init() of LostFoundEditService) to have all countries of the json file entered in countries array of LostEditComponent. Nothing appears in the dropdown list for the moment...

evolmind
  • 359
  • 1
  • 10
  • 30
  • you should be initializing the form inside the subscribe – Aravind Mar 08 '18 at 14:13
  • 1
    `public countries: Observable` in init() `this.countries = this.http.get(this.countriesUrl).map(data=> data['countries'])` and in html: `` It's better to avoid subscribing as much as possible. Angular's Async pipe handles subscribing for you – SebOlens Mar 08 '18 at 14:20
  • @Aravind With that it gives me an error : formGroup expects a FormGroup instance. Please pass one in. It seems that the form is not initialized... – evolmind Mar 08 '18 at 14:23
  • you could make the init() return this.http.get(this.countriesUrl); after the initForm(). then in the LostEditComponent you can do the this.lostFoundEditService.init().subscribe(data => { // set countries property in here after you get the data }); – Molik Miah Mar 08 '18 at 14:23
  • @SebOlens It gives me compilation error : property map does not exist on type Observable ... – evolmind Mar 08 '18 at 14:42
  • @MolikMiah I don't want to externalize all my service code into my component, in that way it works but I don't want that... – evolmind Mar 08 '18 at 14:46
  • you need to import the map operator than `import 'rxjs/add/operator/map';` in the file where you're using it – SebOlens Mar 08 '18 at 14:49
  • ok, in that case an alternative would be to make your countries in your service a BehaviourSubject and then from your component you can subscribe to that property so that when it changes the countries array in your component can be set/updated. please look here for an example: https://stackoverflow.com/a/36404625/1876576 – Molik Miah Mar 08 '18 at 14:52
  • @SebOlens thanks for your knowledgement, that way it works. – evolmind Mar 08 '18 at 15:10
  • @simslay No problem :) When I have time I'll write an answer so others can see it – SebOlens Mar 09 '18 at 06:37

1 Answers1

1

You could possibly try this.

What i'm doing here is changing the countries property from an Array to a BehaviourSubject which means your component can subscribe to this property. We can subscribe by using the async pipe in your template which in the angular world calls the subscribe.

In your service, when we finish getting the data via the subscribe you can set the value by doing this.countries.next(data['countries']).

service :

import {BehaviorSubject} from 'rxjs/BehaviorSubject';

@Injectable()
export class LostFoundEditService {
    public lostForm: FormGroup;
    public countries: Subject = new BehaviorSubject<Array<any>>(null);
    private countriesUrl = 'assets/countries.json';

    constructor(private http: HttpClient) { }

    init() {
        this.initForm();

        this.http.get(this.countriesUrl).subscribe(data => {
            this.countries.next(this.countries.concat(data['countries']));
        },
        (err: HttpErrorResponse) => {
            console.log(err.message);
        });
    }

    private initForm() {
        this.lostForm = new FormGroup({
            'title': new FormControl('', Validators.required),
            'description': new FormControl('', Validators.required),
            'country': new FormControl('', Validators.required),
            'state': new FormControl('', Validators.required),
            'city': new FormControl('', Validators.required),
            'zipCode': new FormControl(''),
            'street': new FormControl('')
        });
    }
}

component :

@Component({
  selector: 'app-lost-edit',
  templateUrl: './lost-edit.component.html',
  styleUrls: ['./lost-edit.component.css']
})
export class LostEditComponent implements OnInit {
  lostForm: FormGroup;
  countries;
  states: any[] = [];
  cities: any[] = [];

  constructor(
    private http: HttpClient,
    private lostFoundEditService: LostFoundEditService) { }

  ngOnInit() {
    this.lostFoundEditService.init();
    this.lostForm = this.lostFoundEditService.lostForm;
    this.countries = this.lostFoundEditService.countries;
  }

  onCancel() {
  }

}

template :

(...)
                  <select
                    id="country"
                    formControlName="country"
                    class="form-control">
                    <option value="">Countries</option>
                    <option *ngFor="let country of countries | async" value="{{country['id']}}">{{country['name']}}</option>
                  </select>
                </div>
            </div>
          </div>
          (...)
Molik Miah
  • 132
  • 7