Art
Art

Reputation: 37

Parse String API response containing GeoJson FeatureCollection to Angular and add them as pins with pop-up info on leaflet map

Below is the service method (JsonObjectBuilderService) that converts an object (FeatureCollectionForGeoJson) to a jsonStr. This service method is used in the Get RequestMapping to send a response to the front-end.

The FeatureCollectionForGeoJson object is a class mapped for GeoJson FeatureCollection.

The GeometryForGeoJson is another class that contains the string type with "Point" value and the array that contains the latitude and longitude for the point.

The PropertyForGeoJson class contains information/properties about that pin that will be displayed in the pop-up when the pin is clicked on on the map.

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class FeatureForGeoJson {

    private final String type = "Feature";
    private GeometryForGeoJson geometry;
    private PropertyForGeoJson properties;

}
@Service
public class JsonObjectBuilderService {

    public String transformObjectToGeoJson(FeatureCollectionForGeoJson featureCollectionForGeoJson){
        ObjectMapper Obj = new ObjectMapper();
        String jsonStr = null;
        try {
           jsonStr = Obj.writeValueAsString(featureCollectionForGeoJson);

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } //catch (IOException e) {

        return jsonStr;
    }
}

This is the GetMapping that sends the response to Angular

  @GetMapping("/power-plants")
    public ResponseEntity<String> getAllPowerPlants() {
        try {
            FeatureCollectionForGeoJson powerPlantsToFeatureCollectionForGeoJson ;
            //jpa query for the database to return the information
            List<PowerPlant> powerPlantList = powerPlantJpaService.findAll();
            
            if (powerPlantList.isEmpty()) {
                logger.info("The power plant list is empty.");
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
            logger.info("The power plant list is populated and has been returned successfully.");

            powerPlantsToFeatureCollectionForGeoJson = transformPowerPlantsToFeaturesCollection.transformPowerPlantToGeoJsonElements(powerPlantList);

            String objectToGeoJson = jsonObjectBuilderService.transformObjectToGeoJson(powerPlantsToFeatureCollectionForGeoJson);
            logger.info(objectToGeoJson);

            return new ResponseEntity<>(objectToGeoJson, HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

This is how the response looks like in the browser

enter image description here

This is the Angular method that fetches the response.

enter image description here

This is the Angular component where I call the service method that fetches the response and where I want to add the pins to the map with the pop-ups.

enter image description here

How do I take that response from the API (line 27 from Home.component.ts -right above- or the getAll() method from the PowerPlantService) and process it to extract the Point Geometry, to create a pin with it and extract the properties to add to a pop-up to the pin?

enter image description here

Upvotes: 0

Views: 520

Answers (2)

Art
Art

Reputation: 37

If you want to know how the back end formats and sends the response, please check in the body of the question.

Below is the service method that performs a GET request to the back end.

export class PowerPlantService {
  constructor(private http: HttpClient) { }

  getAll() {
    return this.http.get(baseUrl);
  }

Below is the component method that subscribes to the answer and adds the elements to the map.

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  private latitude: number = 45.6427;
  private longitude: number = 25.5887;
   
  private map!: L.Map;
  private centroid: L.LatLngExpression = [this.latitude, this.longitude];

  ngOnInit(): void {
    this.initMap();
  }
  
  constructor(private powerPlantService: PowerPlantService) { 
  }

  private initMap(): void {
    this.map = L.map('map', {
      center: this.centroid,
      zoom: 2.8
    });

    const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', 
    {
      minZoom: 2.8,
      attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
    });

    tiles.addTo(this.map);
    
    this.powerPlantService.getAll().subscribe((data: any)=>{
      console.log(data);
      L.geoJSON(data).addTo(this.map) 
    }) 

Upvotes: 0

Zerotwelve
Zerotwelve

Reputation: 2361

if you use angular you should use Observables and not Promises, also avoid to post images of code, now I can't copy/paste you code.

what you want to do is return an observable in getAll(), something like this:

// in component
  this.powerPlantService.getAll$().subscribe(
      res => this.featureCollection = res,
      err => console.log(err)
    );
// in service
 getAll$(): Observable<any[]> {
    return this.http.get(baseUrl).pipe(
      map(data => {
        // transform your data here, or remove this pipe if you don't need it
        return data;
      })
    );
 }

you can transform your features in a flat object like this:

return this.http.get(baseUrl).pipe(
      map(features => {
          return features.map(f => {
            const pointGeometry: any = {
                ...f.geometry,
                ...f.properties
            };
            return pointGeometry;
        });
      })
    );
      


Upvotes: 1

Related Questions