Problems implementing Dropdown Waterfall List with Angular 4?

Asked

Viewed 208 times

0

As the title says, I’m having difficulty implementing the Dropdown Cascade, it’s about loading the first Dropdown with the state and the second Dropdown will be automatically loaded according to the state selected in the first Dropdown.

Note the model I found on the internet and is working.

Cascading Dropdown

This above model is working perfectly because I tested it on my local computer, while trying to adapt it to my project not getting.

I’m just needing help to adapt it to my project.

I believe it’s not so complicated!

When making the first modifications it has already started to present problems in the component file without at least compiling, first note the changes made in the service file.

Note the changes

Before it was like this:

import { Cidade, Estado, Country, State } from './../core/model';
import { Injectable } from '@angular/core';
import { Http, URLSearchParams, Headers } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';

@Injectable()
export class CidadesService {

 // cidadesUrl = 'http://localhost:8080/cidades';
 // estadosUrl = 'http://localhost:8080/cidades/estados';



  constructor(private http: HttpClient) { }

  getCountries() {
    return [
     new Country(1, 'USA' ),
     new Country(2, 'India' ),
     new Country(3, 'Australia' )
    ];
  }


  getStates() {
   return [
     new State(1, 1, 'Arizona' ),
     new State(2, 1, 'Alaska' ),
     new State(3, 1, 'Florida'),
     new State(4, 1, 'Hawaii'),
     new State(5, 2, 'Gujarat' ),
     new State(6, 2, 'Goa'),
     new State(7, 2, 'Punjab' ),
     new State(8, 3, 'Queensland' ),
     new State(9, 3, 'South Australia' ),
     new State(10, 3, 'Tasmania')
    ];
  }


}

Then I changed it to look like this:

import { Cidade, Estado, Country, State } from './../core/model';
import { Injectable } from '@angular/core';
import { Http, URLSearchParams, Headers } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';

@Injectable()
export class CidadesService {

 cidadesUrl = 'http://localhost:8080/cidades';
 // estadosUrl = 'http://localhost:8080/cidades/estados';



  constructor(private http: HttpClient) { }

  getCountries(): Observable<any> {
    return Observable.of([
     this.getTodasCidades()
    ]);
  }

  getTodasCidades() {
    return this.http.get<any[]>(`${this.cidadesUrl}`);
  }



  getStates() {
   return [
     new State(1, 1, 'Arizona' ),
     new State(2, 1, 'Alaska' ),
     new State(3, 1, 'Florida'),
     new State(4, 1, 'Hawaii'),
     new State(5, 2, 'Gujarat' ),
     new State(6, 2, 'Goa'),
     new State(7, 2, 'Punjab' ),
     new State(8, 3, 'Queensland' ),
     new State(9, 3, 'South Australia' ),
     new State(10, 3, 'Tasmania')
    ];
  }


}

The only change I made to the service file was in the method getCountries(), now let’s see the component file.

Before it was like this:

import { Estado, Cidade, Country, State } from './../../core/model';
import { CidadesService } from './../cidades.service';
import { Component, OnInit } from '@angular/core';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';


@Component({
  selector: 'app-cidades-pesquisa',
  templateUrl: './cidades-pesquisa.component.html',
  styleUrls: ['./cidades-pesquisa.component.css']

})
export class CidadesPesquisaComponent implements OnInit {

  //cidades: Cidade[];
  //estados: Estado[];



  selectedCountry: Country = new Country(0, 'Rio Branco');
  countries: Country[];
  states: State[];


  constructor(private cidadesService: CidadesService) {
    this.countries = this.cidadesService.getCountries();
   }

  ngOnInit() {
    //    this.carregarCidades();
     //   this.carregarEstados();

  }


  onSelect(countryid) {
    this.states = this.cidadesService.getStates().filter(( item ) => item.countryid == countryid);
  }

}

After the changes it was like this:

import { Estado, Cidade, Country, State } from './../../core/model';
import { CidadesService } from './../cidades.service';
import { Component, OnInit } from '@angular/core';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';


@Component({
  selector: 'app-cidades-pesquisa',
  templateUrl: './cidades-pesquisa.component.html',
  styleUrls: ['./cidades-pesquisa.component.css']

})
export class CidadesPesquisaComponent implements OnInit {

  cidades: Cidade[];
  estados: Estado[];



  selectedCountry: Cidade = new Cidade(1, 'Rio Branco', '1');
 // countries: Country[];
  states: State[];


  constructor(private cidadesService: CidadesService) {
    this.cidades = this.cidadesService.getCountries();
   }

  ngOnInit() {
    //    this.carregarCidades();
     //   this.carregarEstados();

  }


  onSelect(countryid) {
    this.states = this.cidadesService.getStates().filter(( item ) => item.countryid == countryid);
  }

}

The changes that were made were in this code snippet;

cidades: Cidade[];
  estados: Estado[];



  selectedCountry: Cidade = new Cidade(1, 'Rio Branco', '1');

The piece of code that went wrong was this:

constructor(private cidadesService: CidadesService) {
    this.cidades = this.cidadesService.getCountries();
   }

inserir a descrição da imagem aqui

Do you realize he’s complaining about the absence of Observable in the service archive, that’s because the service archive in the method getCountries() is implemented incorrectly, yet I tried to compile and generated this error below;

ERROR in src/app/cidades/cidades-pesquisa/cidades-pesquisa.component.ts(28,5): error TS2322: Type 'Observable<any>' is not assignable
to type 'Cidade[]'.
  Property 'includes' is missing in type 'Observable<any>'.
src/app/core/model.ts(59,12): error TS2554: Expected 3 arguments, but got 0.

For me to continue the adaptation of the code I need to correctly implement the method getCountries() in the service archive.

I will put the mapping of the entity cities only for clarification criterion;

export class Cidade {
  constructor(
    codigo: number,
    nome: string,
    codigoEstado: string)
  { }
  estado = new Estado();
}

1 answer

0

As I already know from the answer I decided to put here to contribute to the forum;

Service archive:

import { Cidade, Estado} from './../core/model';
import { Injectable } from '@angular/core';
import { Http, URLSearchParams, Headers } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';



@Injectable()
export class CidadesService {

 cidadesUrl = 'http://localhost:8080/cidades';
 estadosUrl = 'http://localhost:8080/cidades/estados';



  constructor(private http: Http) { }

  listarTodasCidades(): Observable<Cidade[]> {
    return this.http.get(`${this.cidadesUrl}`)
    .map(response => response.json());
    }

    listarTodosEstados(): Observable<Estado[]> {
    return this.http.get(`${this.estadosUrl}`)
    .map(response => response.json());
    }


}




 /* listarTodas(): Promise<any> {
    return this.http.get(this.cidadesUrl)
      .toPromise()
      .then(response => console.log(response.json()));
  }



   listarTodasCidades() {
    return this.http.get<any[]>(`${this.cidadesUrl}`);
  }

  listarTodosEstados() {
    return this.http.get<any[]>(`${this.estadosUrl}`);
  }




getCountries(): Observable<any> {
    return Observable.of([
     this.getTodosEstados()
    ]);
  }

  getTodosEstados() {
    return this.http.get<any[]>(`${this.estadosUrl}`);
  }




  */

Component files:

import { Estado, Cidade} from './../../core/model';
import { CidadesService } from './../cidades.service';
import { Component, OnInit } from '@angular/core';

import 'rxjs/add/operator/map';



@Component({
  selector: 'app-cidades-pesquisa',
  templateUrl: './cidades-pesquisa.component.html',
  styleUrls: ['./cidades-pesquisa.component.css']

})
export class CidadesPesquisaComponent implements OnInit {

  uf: string;

  cidades: Cidade[];
  estados: Estado[];

  constructor(private cidadesService: CidadesService) { }

  ngOnInit() {
    this.cidadesService.listarTodosEstados()
    .subscribe(estados => this.estados = estados);
  }

  buscarCidades() {
    console.log("Estado: " + this.uf);
      this.cidades = [];

     if(this.uf) {
        this.cidadesService.listarTodasCidades()
        .subscribe(cidades => {
          if (cidades.length > 0) {
            console.log("Qtd total de cidades: " + cidades.length);
          }
          for (let cidade of cidades) {
            if ( parseInt( cidade.codigoEstado) == parseInt(this.uf)) {
              console.log(cidade);
              this.cidades.push(cidade);
          }
        }
      });
    }
  }
}




  /*carregarCidades() {
    return this.cidadesService.listarTodas()
      .then(() => null);

  }

carregarCidades() {
    this.cidadesService.listarTodasCidades()
      .subscribe(dados => {
       console.log(this.cidades = dados);
      });
  }


  carregarEstados() {
    this.cidadesService.listarTodosEstados()
    .subscribe(dados => {
      this.estados = dados;
     });
  }


  console.log(this.cidades.map((e) => <any>e.codigoEstado));


  */

HTML page:

<div class="container">
  <form>
        <div class="ui-g">
                <div class="ui-g-3">
                    <select name="estado" id="estado" [(ngModel)]="uf" (change)="buscarCidades()">
                        <option *ngFor="let estado of estados" [value]="estado.codigo">{{estado.nome}}</option>
                    </select>
                </div>

            <div class="ui-g-3">
                <select name="cidade" id="cidade">
                      <option *ngFor="let cidade of cidades" [value]="cidade.codigoEstado">{{cidade.nome}}</option>
                </select>
            </div>

        </div>

  </form>
  </div>

Browser other questions tagged

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