0

I am creating a pretty basic web app as of right now. Basically, I just get the lat and long from my mongodb and put markers on the map, which is working fine. The problem I am having is setting the marker colors. I can make it work if I put the url to the marker png in the mongodb, but I was wondering if there is a way to change the marker color based on certain data from mongodb. Right now, I am just using a field called 'marker' in my mongodb document with a number 1 - 4, based on that number, will determine what color the marker is.

Here is the component.ts

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;
      }
    }
  }
}

Here is the html

 <div class="container">

  <ul class="legend">
    <li><span class="faster"></span>IPv6 Load Time &le; 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

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

schoolService.ts

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');
  }
}

Here is the current log... 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) at checkAndUpdateNode (core.js:23325) at debugCheckAndUpdateNode (core.js:23959) at debugCheckDirectivesFn (core.js:23919) at Object.eval [as updateDirectives] (MapComponent_Host.ngfactory.js? [sm]:1)

1 Answer 1

1

The problem is in the template where you are trying to call "getIcon()". This method may be called even before subscribe is completed.

Please change your template and component code like this -

<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;
      }
  }
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you so much for your response! I actually literally just figured this out like 5 minutes ago!! haha. But I had been working on it for hours, I felt stupid when I realized what I was doing. I have another problem now though. It works now, yes, but I get this error... ERROR TypeError: Cannot read property 'marker' of undefined at MapComponent.push../src/app/map/map.component.ts.MapComponent.getIcon (map.component.ts:39) at MapComponent.push../src/app/map/map.component.ts.MapComponent.ngOnInit (map.component.ts:27)
Oh, nevermind I see what you did there... you added the if(school) before the if(schoolmarker === 1). It works with no errors now! Thank you again so much!!
Your code could have been written a better way even without doing if(school). I thought of to change your code instead of providing a better code to implement the same. Anyway, good to know that it worked for you. If the solution worked, please mark it as answered so that it can help someone.
I have no doubt there is a better way to do what I have done. I am still fairly new programming. My main focus has been Java for the past almost year, but have only just recently dived into javascript and its frameworks. If you wouldn't mind, pointing me in a general direction of where I could start to look to change things to make it better, that would be great. By no means asking for a full solution, just a hint. Thank you.
In the template, you are using [iconUrl]="getIcon(school)". If you add "console.log('getIcon called');" at the start of the getIcon() method then you would notice that log will be shown more times than expected. It is happening because the function call in the template is called on every change detection [until it is on the user's action like button click]. Here, you want to transform your marker to the url. For this purpose, angular has pipe [angular.io/guide/pipes]. The pipe is memoized which means it will evaluate only if the input to the pipe is changed. Hope it helps [directs] you
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.