Establishing the placement of map markers in Angular

Currently, I am in the process of developing a simple web application. The main functionality involves retrieving latitude and longitude data from my MongoDB database and displaying markers on a map, which is functioning correctly. However, the issue I'm facing is related to setting the colors of these markers. While I can achieve this by storing the URL of the marker PNG in the database, I am exploring options to dynamically change the marker color based on specific data from MongoDB. Presently, I have included a field named 'marker' in each MongoDB document containing a number ranging from 1 to 4, which determines the color of the corresponding marker.

This snippet showcases the component.ts setup:

import { Component, OnInit } from '@angular/core';
import { SchoolService } from '../school.service';
import { School } from '../School';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.css']
 })

export class MapComponent implements OnInit {

  startLat = 35.782169;
  startLng = -80.793457;
  zoom = 7;
  greenMarker = 'http://www.google.com/intl/en_us/mapfiles/ms/micons/green-dot.png';
  yellowMarker = 'http://www.google.com/intl/en_us/mapfiles/ms/micons/yellow-dot.png';
  schools: School[] = [];

  constructor(private schoolService: SchoolService) { }

  ngOnInit() {
    this.getSchools();
    this.getIcon();
  }

  getSchools(): void {
    this.schoolService.getSchools()
      .subscribe((schoolList: School[]) => {
        this.schools = schoolList;
        console.log(this.schools);
      });
  }

  getIcon() {
    for (let i = 0; i <= this.schools.length; i++) {
      if (this.schools[i].marker === 1) {
        return this.greenMarker;
      } else {
        return this.yellowMarker;
      }
    }
  }
}

Below is the HTML markup:

 <div class="container">

  <ul class="legend">
    <li><span class="faster"></span>IPv6 Load Time ≤ IPv4</li>
    <li><span class="all-elements"></span>Fully IPv6 Accessible</li>
    <li><span class="reachable"></span>DNS AAA Record</li>
    <li><span class="DNS-AAAA"></span>Not IPv6 Accessible</li>
  </ul>

  <agm-map id="map" [latitude]="startLat" [zoom]="zoom" 
[longitude]="startLng">
    <agm-marker *ngFor="let school of schools; let i = index"
      [latitude]="school.lat" [longitude]="school.long" 
[iconUrl]="getIcon()">
      <agm-info-window>
        <h4>{{ school.name }}</h4>
        <p>lat: {{ school.lat }}</p>
        <p>long: {{ school.long }}</p>
      </agm-info-window>
    </agm-marker>
  </agm-map>
</div>

School.ts Schema:

export class School {
    name: string;
    lat: number;
    long: number;
    marker: number;
}

School Service Implementation:

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

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


  constructor(private http: HttpClient) { }

  getSchools() {
    return this.http.get('http://localhost:3000/get');
  }
}

Error log generated:

MapComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: Cannot read property 'marker' of undefined
    at MapComponent.push../src/app/map/map.component.ts.MapComponent.getIcon (map.component.ts:38)
    at MapComponent.push../src/app/map/map.component.ts.MapComponent.ngOnInit (map.component.ts:25)
    at checkAndUpdateDirectiveInline (core.js:22099)
    at checkAndUpdateNodeInline (core.js:23363)
    ...

Answer №1

It seems like the issue lies within the template when attempting to call the "getIcon()" method. This function could be triggered before the subscription is completed.

To resolve this, you should modify your template and component code as shown below -

<agm-map id="map" [latitude]="startLat" [zoom]="zoom" 
[longitude]="startLng">
    <agm-marker *ngFor="let school of schools; let i = index"
      [latitude]="school.lat" [longitude]="school.long" 
[iconUrl]="getIcon(school)">
      <agm-info-window>
        <h4>{{ school.name }}</h4>
        <p>lat: {{ school.lat }}</p>
        <p>long: {{ school.long }}</p>
      </agm-info-window>
    </agm-marker>
  </agm-map>

getIcon(school) {

if(school) {
  if(school.marker === 1) {
  return this.greenMarker;
      } else {
        return this.yellowMarker;
      }
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A custom Typescript type for immutable values within an object

I am struggling with finding the right data type for my function, where I need to work with static types. I have experimented with Type, interface, class, Record, and others, but none seem to fit perfectly. GEOLOCATIONS is a constant record that maps cou ...

Keep an eye out for any instances of new files being created in nodemon js or npm

Is there a way to monitor only for new file creation events using nodemon js, npm, or any other packages? For instance, in a project, whenever a new file is created, a specific script needs to be executed to carry out additional tasks for a one-time setup. ...

Increase the current version number by adding the release candidate label and making it a prerelease using npm version command

Our team is in the process of streamlining our versioning and build processes for our Angular 2 applications through automation. We are interested in leveraging npm version However, we have encountered difficulty when attempting to add an 'rc' ...

The Material UI button shifts to a different row

I need help adjusting the spacing between text and a button on my webpage. Currently, they are too close to each other with no space in between. How can I add some space without causing the button to move to the next line? const useStyles = makeStyles((the ...

Angular 2 Cordova application experiencing challenges with updating member variables that are not reflecting changes in the associated template

In my Cordova app with Angular 2, I am facing an issue where the @Component decorated AppComponent class member variable is not updating in the view template as expected. I have noticed that the first update to the member variable gets rendered in the vie ...

Tips for improving the slow compilation of the Next.js 14 development environment

Currently, I am tackling an issue with my Typescript - Next.js 14 Application where the compilation process in the development environment is taking excessive time, sometimes up to 60 seconds. What steps can be taken to resolve this problem and optimize t ...

Inheriting Angular components: How can the life cycle hooks of a parent component be triggered?

So I'm working with BaseComponent and a number of child components that extend it: export class Child1Component extends BaseComponent implements OnInit, AfterViewInit In the case of Child1Component, there is no explicit call to super.ngAfterViewInit ...

I am facing difficulty in retrieving data from Firestore using Angular

I've been utilizing the AngularFireList provided by @angular/fire/database to retrieve data from firestore. However, despite having data in the firestore, I am unable to fetch any information from it. import { Injectable } from '@angular/core&apo ...

Utilize only the necessary components from firebase-admin in Cloud Functions with Typescript

When I looked at my transpiled code from cloud functions, I noticed the following TypeScript import: import { auth, firestore } from 'firebase-admin'; It gets transpiled to: const firebase_admin_1 = require("firebase-admin"); Upon further exa ...

Display a pop-up directly below the specific row in the table

I am working on creating a table where clicking on a row will trigger a popup window to appear right below that specific row. Currently, the popup is displaying under the entire table instead of beneath the clicked row. How can I adjust my Angular and Bo ...

The template is displaying the string as "[object Object]"

I've implemented code in my ngOnInit function to fetch the translation for a specific text. The following function is being called: async getEmailTranslation() { const email$ = this.translate.get('SUPPORT_TRANSLATE.EMAIL'); this.emai ...

Preventing the (click) function from being activated during dragging in Angular 10

My div contains an openlayers map setup as shown below: <div id="map" (click)="getInfo($event)" class="map"></div> Whenever I drag my mouse to move around the map, the getInfo function is triggered. Is there a way to make it trigger only when ...

Angular Universal: Missing Title and Meta tags in Page Source

I need help with updating title and meta tags in my Angular Universal Application after a successful api call. app.component.ts import {Component, Inject, OnInit, PLATFORM_ID} from '@angular/core'; import {Meta, Title} from '@angular/platfo ...

Types of Axios responses vary depending on their status codes

I am looking to create a specific type for axios responses based on the status code: types: type SuccessfulResponseData = { users: .... }; interface SuccessfulResponse extends AxiosResponse<SuccessfulResponseData, any> { status: 200; } ty ...

What is the best way to assign a value to an ngrx reducer/action in order to update the state?

As a newcomer to Angular ngrx, I am in the process of integrating it into my 'standard beginner-project' by replacing all @Input()s and @Output()s. While incrementing and decrementing the state is straightforward, I am faced with the challenge of ...

The navigation function in Angular, this.router.navigate, is causing issues and

I've encountered a peculiar issue. There's a logout function that is activated whenever I receive a 401 response from any API I interact with. The function looks like this: constructor( private router: Router, ) {} logout(router1: Router ...

Can you explain the reference to "ng2" in relation to Angular 2?

In countless blog posts discussing Angular 2, I often come across references to ng2. Can someone clarify what ng2 stands for? Is it the CLI for Angular 2? ...

The function within filereader.onload is not running properly in JavaScript

When working with FileReader to read a file and convert it to base64 for further actions, I encountered an issue. Although I was able to successfully read the file and obtain its base64 representation, I faced difficulties in utilizing this data to trigger ...

What is the best way to utilize a single component for validating two other components?

I am encountering an issue with my components setup. I have three components in total: GalleryAddComponent, which is used to add a new element, GalleryItemComponent, used to edit an element, and FieldsComponent, the form component utilized by both GalleryA ...

When the JSON array is converted into a string, it appears as undefined

Below is a snippet of my service.spec.ts file: service.spec.ts it('should mock the http requests', inject([Service, MockBackend], (service, mockBackend) => { let result:any; mockBackend.connections.subscribe((connection) => { ...