Select does not load the options using Angular

Asked

Viewed 162 times

-1

Hello, I am doing a register of employees at the corner, and, for the address of the employee I am using the web service via cep, but I would like to put the field of the state in a select and for that I used a json with all the Brazilian states, I can save the data in an array called 'states' (tested with a console.log) but I cannot load the data saved in the select options.

follows below the codes, of the component:

import { CepService } from './../../services/cep.service';
import { EstadoBr } from './../../models/estados-br.model';
import { EstadosService } from './../../services/estados.service';

import { SetorService } from './../../setores/setor.service';
import { Setor } from './../../setores/Setor.model';
import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup } from '@angular/forms';
import { FuncionarioService } from '../funcionario.service';

@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.css'],
})
export class POSTComponent implements OnInit {
  setores: Setor[];
  estados: EstadoBr[];
  funcionarioForm: FormGroup;

  constructor(
    private fb: FormBuilder,
    private setorService: SetorService,
    private funcionarioService: FuncionarioService,
    private estadosService: EstadosService,
    private cepService: CepService
  ) {
    this.funcionarioForm = this.fb.group({
      nome: [''],
      matricula: [''],
      email: [''],
      telefone: [''],
      setor: [null],
      estado: [''],
      enderecos: this.fb.array([this.addEnderecosGroup()]),
    });
  }

  ngOnInit(): void {
    this.setorService.findAll().subscribe((resposta) => {
      this.setores = resposta;
      this.funcionarioForm.controls.setor.setValue(this.setores[0]);
      console.log(this.setores)
    });
    this.estadosService.findAllEstados().subscribe((resposta: EstadoBr) => {
      this.estados.push(resposta);
      this.funcionarioForm.controls.estado.setValue(this.estados[0]);
      console.log(this.estados)
    });


  }

  addEnderecosGroup() {
    return this.fb.group({
      cep: [''],
      logradouro: [''],
      complemento: [''],
      numero: [''],
      bairro: [''],
      cidade: [''],
      uf: [''],
    });
  }

  get enderecosArray() {
    return <FormArray>this.funcionarioForm.get('enderecos');
  }

  post() {
    console.log(this.funcionarioForm.value);
    this.funcionarioService
      .post(this.funcionarioForm.value)
      .subscribe((resposta) => {
        console.log(this.funcionarioForm.value);
      });
  }

  consultaCep() {
    let cep = '';
    for (let i = 0; i < this.enderecosArray.length; i++) {
      cep = this.enderecosArray.at(i).get('cep').value;
    }

    if (cep != null && cep !== '') {
      this.cepService.consultaCep(cep).subscribe(resposta => this.populaDadosForm(resposta));
    }
      const validacep = /^[0-9]{8}$/;
    }
    populaDadosForm(resposta) {
      for (let i = 0; i < this.enderecosArray.length; i++) {
        this.enderecosArray.at(i).patchValue({
          logradouro: resposta.logradouro,
          complemento: resposta.complemento,
          numero: resposta.numero,
          bairro: resposta.bairro,
          cidade: resposta.localidade,
        });
      }
    }
  }

of html:

<div >
    <form [formGroup]="funcionarioForm">
        <div>
            <label>Nome</label>
            <input type="text" formControlName="nome">
        </div>
        <div>
            <label>Matrícula</label>
            <input type="text" formControlName="matricula">
        </div>
        <div>
            <label>E-mail</label>
            <input type="text" formControlName="email">
        </div>
        <div>
            <label>Telefone</label>
            <input type="text" formControlName="telefone">
        </div>
        <div>
            <label>Setor</label>
            <select class="form-control" id="setor" formControlName="setor" name="setor">
                <option *ngFor="let setor of setores" [ngValue]="setor">
                    {{setor.nome}}
                </option>
              </select>
            </div>
            <div>
              <label>Estado</label>
              <select   formControlName="estado" >
                  <option *ngFor="let estado of estados" [ngValue]="estado.sigla" >
                      {{estado.nome}}
                  </option>
                </select>
              </div>

        <div formArrayName="enderecos">
            <div *ngFor="let group of enderecosArray.controls; let i = index;" [formGroupName]="i">
            <div>
                <label>Cep</label>
                <input type="text" formControlName="cep" name="cep"
                (blur)="consultaCep()">
            </div>
            <div>
                <label>Logradouro</label>
                <input type="text" formControlName="logradouro">
            </div>
            <div>
                <label>Complemento</label>
                <input type="text" formControlName="complemento">
            </div>
            <div>
                <label>Número</label>
                <input type="text" formControlName="numero">
            </div>
            <div>
                <label>Bairro</label>
                <input type="text" formControlName="bairro">
            </div>
            <div>
                <label>Cidade</label>
                <input type="text" formControlName="cidade">
            </div>

            </div>
        </div>
        <button (click)="post()">Salvar</button>
    </form>
</div>

service of states:


import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class EstadosService {

  constructor(private http: HttpClient) { }

  findAllEstados() {
    return this.http.get('assets/jsons/estadosbr.json').pipe();
  }
}

and staff services:

import { Observable } from 'rxjs';
import { Funcionario } from './Funcionario.model';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class FuncionarioService {

  Url = "http://localhost:8080/Funcionarios/";

  constructor(private http: HttpClient) { }

  post(funcionario: Funcionario): Observable<Funcionario>{
    return this.http.post<Funcionario>(this.Url, funcionario)
  }
}

state model:

export class EstadoBr {
    id: Number;
    sigla: string;
    nome: string
}

and the json:

[{
    "id": "1",
    "sigla": "AC",
    "nome": "Acre"
},
     {
    "id": "2",
    "sigla": "AL",
    "nome": "Alagoas"
},
     {
    "id": "3",
    "sigla": "AM",
    "nome": "Amazonas"
},
     {
    "id": "4",
    "sigla": "AP",
    "nome": "Amapá"
},
     {
    "id": "5",
    "sigla": "BA",
    "nome": "Bahia"
},
     {
    "id": "6",
    "sigla": "CE",
    "nome": "Ceará"
},
     {
    "id": "7",
    "sigla": "DF",
    "nome": "Distrito Federal"
},
     {
    "id": "8",
    "sigla": "ES",
    "nome": "Espírito Santo"
},
     {
    "id": "9",
    "sigla": "GO",
    "nome": "Goiás"
},
     {
    "id": "10",
    "sigla": "MA",
    "nome": "Maranhão"
},
     {
    "id": "11",
    "sigla": "MG",
    "nome": "Minas Gerais"
},
     {
    "id": "12",
    "sigla": "MS",
    "nome": "Mato Grosso do Sul"
},
     {
    "id": "13",
    "sigla": "MT",
    "nome": "Mato Grosso"
},
     {
    "id": "14",
    "sigla": "PA",
    "nome": "Pará"
},
     {
    "id": "15",
    "sigla": "PB",
    "nome": "Paraíba"
},
     {
    "id": "16",
    "sigla": "PE",
    "nome": "Pernambuco"
},
     {
    "id": "17",
    "sigla": "PI",
    "nome": "Piauí"
},
     {
    "id": "18",
    "sigla": "PR",
    "nome": "Paraná"
},
     {
    "id": "19",
    "sigla": "RJ",
    "nome": "Rio de Janeiro"
},
     {
    "id": "20",
    "sigla": "RN",
    "nome": "Rio Grande do Norte"
},
     {
    "id": "21",
    "sigla": "RO",
    "nome": "Rondônia"
},
     {
    "id": "22",
    "sigla": "RR",
    "nome": "Roraima"
},
     {
    "id": "23",
    "sigla": "RS",
    "nome": "Rio Grande do Sul"
},
     {
    "id": "24",
    "sigla": "SC",
    "nome": "Santa Catarina"
},
     {
    "id": "25",
    "sigla": "SE",
    "nome": "Sergipe"
},
     {
    "id": "26",
    "sigla": "SP",
    "nome": "São Paulo"
},
     {
    "id": "27",
    "sigla": "TO",
    "nome": "Tocantins"
}]

did not include the app.module or the service to consult the zip code as these are not causing errors in the project, thanks in advance.

2 answers

0

Hello!

Apparently its state return is already an array, so if you do "states.push(reply)" you are inserting an array within an array.

Therefore, just attributes your variable of states to answer.

this.estadosService.findAllEstados().subscribe((resposta: EstadoBr) => {
    this.estados = respota;
    this.funcionarioForm.controls.estado.setValue(this.estados[0]);
});

0

Basically every HTTP request, at the angle, returns observables and these are asynchronous by nature, that is, you are not sure when it will be executed or will return a value. In order to be notified and know the return of this request we need to enroll in the observable through the method subscribe().

A very common "error" when dealing with observables is to use synchronous variables to pick up the observable’s return value. I will use your code as an example.

this.setorService.findAll().subscribe((resposta) => {
      this.setores = resposta;
      this.funcionarioForm.controls.setor.setValue(this.setores[0]);
      console.log(this.setores)
});

Often this approach works, but it is very susceptible to errors, because there may be delays in the request, so the variable setores may not receive the value before first use, and what will be the value of setores at this time? undefined.

If you want to test, put a console.log(this.setores) out of subscribes and will see that possibly the console value will be undefined. It is possible that the log was executed before the request was completed.

If this delay occurs your code will "break" and everything depending on the variable setores won’t work.

In your case, it is not necessary to assign the results of the requests to the synchronous variables, you can use the observables directly in the component, also dispensing with the use of the subscribe(). Another part that is not necessary is the use of patchValue to the fields sector and state form, as these are user’s choice, right?

Making some changes to the component we can fix this "problem"

Component:

setores$:Observable<Setor[]> // substitui a variável setores
estados$:Observable<EstadosBR[]> // substitui a variável estados

ngOnInit(): void {
    setores$=this.setorService.findAll().pipe(
        //qualquer operador do RXJS 
    );
    estados$=this.estadosService.findAllEstados().pipe(
        //qualquer operador do RXJS
    );
}

This way you are assigning observables to HTTP requests, and in the method pipe() you can modify, filter, copy the value of the observable.

Note that until then these operations will not be executed, the request will only happen from the moment we subscribe

Template:

<div>
     <label>Setor</label>
     <select class="form-control" id="setor" formControlName="setor" name="setor">
           <option *ngFor="let setor of setores$ | async" [value]="setor">
                {{setor.nome}}
           </option>
     </select>
</div>
<div>
     <label>Estado</label>
     <select formControlName="estado" >
        <option *ngFor="let estado of estados$ | async" [value]="estado.sigla" >
              {{estado.nome}}
        </option>
     </select>
</div>

The template structure hasn’t changed that much. We only added *ngFor() ASYNC pipe that will subscribe() and unsubscribe() automatically.

That way when the user uses select he can choose the options.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.