title: Openlayers and Angular 2 Typescript
body: <p>I'm trying to use Openlayers to dynamically load features from my API into a Layer after my Map is loaded from within app.component.ts. My error is <em><strong>&quot;ERROR TypeError: Cannot read property 'addFeature' of undefined&quot;</strong></em> if I call my function from my app.component.ts on ngOnInit,</p>
  <p>The source of my project was the following link although I've tried other examples without success. I cannot figure why my vectorSource object is NULL.</p>
  <p><a href="https://stackoverflow.com/questions/40852037/angular2-openlayers3-test-fails-when-map-renders-writing-tests-impossible">Angular2 + Openlayers3: Test fails when map renders. Writing tests impossible?</a></p>
  <p>Below is the source code, I'm open to different designs or approaches to solve the issue. Thanks.</p>
  <p><strong>ol.service.ts</strong></p>
  <blockquote>
  <pre><code>import {Injectable} from '@angular/core';
  import * as ol from 'openlayers';
  
  
  @Injectable()
  export class OlService {
  
      get(): any {
          return ol;
      }
  }
  </code></pre>
  </blockquote>
  <p><strong>ol.component.ts</strong></p>
  <blockquote>
  <pre><code>import { Component, OnInit, Input } from '@angular/core'; 
  import { OlService } from './ol.service';
  
  @Component({
      selector: 'app-map',
      providers: [OlService],
      templateUrl: './ol.component.html',
      styleUrls: ['./ol.component.css'],
  
  }) export class OlComponent implements OnInit {
  
      @Input() lnglat: [number, number];
      @Input() zoom: number;
  
      private map;
      public layers = [];
      private vectorSource;
  
      constructor(private olService: OlService) {
  
          this.lnglat = [-93.49401, 45.08203];
          this.zoom = 7;
  
      }
  
      createMap = () =&gt; {
          let ol = this.olService.get();
          this.vectorSource = new ol.source.Vector({});
          // define layers
  
          let OSM = new ol.layer.Tile({
              source: new ol.source.OSM()
          });
          OSM.set('name', 'Openstreetmap');
  
  
          let geography = new ol.layer.Tile({
              source: new ol.source.TileJSON({
                  url: '',
                  crossOrigin: '',
              }),
              visible: false
          });
          geography.set('name', 'Geography');
  
          let boundaries = new ol.layer.Tile({
              opacity: 0.5,
  
              source: new ol.source.TileWMS({
                  url: '',
                  params: {
                      'LAYERS': 'fwsys:fwsys_region',
                      'TILED': true,
                      'transparent': 'true',
                      'format': 'image/png'
                  },
                  serverType: 'geoserver',
                  projection: ol.proj.get('EPSG:3857')
              })
          });
          boundaries.set('name', 'Boundaries');
          let vector = new ol.layer.Vector({
              source: this.vectorSource
          });
  
          this.map = new ol.Map({
              target: 'map',
              layers: [OSM, geography, vector, boundaries],
  
              view: new ol.View({
                  center: ol.proj.fromLonLat(this.lnglat),
                  zoom: this.zoom,
                  projection: ol.proj.get('EPSG:3857')
              })
          });
  
          let select_interaction = new ol.interaction.Select();
  
          this.map.addInteraction(select_interaction);
  
          // add popup for all features
          let container = document.getElementById('ol-popup');
          let content = document.getElementById('ol-popup-content');
          let closer = document.getElementById('ol-popup-closer');
  
  
          let popup = new ol.Overlay({
              element: container,
              autoPan: true,
              positioning: 'bottom-center',
              stopEvent: false,
              offset: [0, -5]
          });
  
          closer.onclick = function () {
              popup.setPosition(undefined);
              closer.blur();
              return false;
          };
          this.map.addOverlay(popup);
  
          this.map.on('click', (evt) =&gt; {
              let feature = this.map.forEachFeatureAtPixel(evt.pixel, (feat) =&gt; {
                  return feat;
              });
              if (feature) {
                  let coordinate = evt.coordinate;
                  content.innerHTML = feature.get('name');
                  popup.setPosition(coordinate);
              }
  
  
          });
          this.addLayerSwitcher([OSM, geography, boundaries]);
          // This works during ngOnInit, but not after
          this.addMarker([174.76, -37.10], 'Close to Auckland', 'akl1'); 
          this.addMarker([173.76, -37.10], 'Out in in waters', 'pacific1');
          // this.addMarker([38.909635, -77.043386], 'Dupont Circle', 'myid');
  
          this.addPolygon([[174.76, -37.18], [176.76, -37.18], [176.76, -38.18], [174.76, -38.18]], 'Hamilton', 'id_hamilton');
      };
  
      addPolygon = (polygon: [[number, number]], name: string, id: string) =&gt; {
          let ol = this.olService.get();
          let projectedPolygon = [];
  
          for (let poly of polygon) {
              projectedPolygon.push(ol.proj.transform(poly, 'EPSG:4326', 'EPSG:3857'));
          }
  
          let p = new ol.geom.Polygon([projectedPolygon]);
  
          let featurething = new ol.Feature({
              name: name,
              id: id,
              geometry: p
          });
  
          this.vectorSource.addFeature(featurething);
  
      };
  
  
      setMarker(coords: [number, number], name: string, id: string) {
  
          this.addMarker(coords, name, id);
      }
  
      addMarker = (coords: [number, number], name: string, id: string) =&gt; {
          
          let ol = this.olService.get();
          let iconFeature = new ol.Feature({
              geometry: new ol.geom.Point(ol.proj.transform(coords, 'EPSG:4326', 'EPSG:3857')),
              name: name,
              id: id,
          });
  
          let iconStyle = new ol.style.Style({
              image: new ol.style.Icon(/** @type {olx.style.IconOptions} */({
                  opacity: 0.75,
                  anchor: [0.5, 1],
                  src: '//cdn4.iconfinder.com/data/icons/pictype-free-vector-icons/16/location-alt-32.png'
              }))
          });
  
          iconFeature.setStyle(iconStyle);
          //
          // THIS CODE FAILS BECAUSE &quot;this.vectorSource.&quot; is null when
          // addMarker() is called after ngOnInit() from app.component.ts
          //
          this.vectorSource.addFeature(iconFeature);
  
      }
  
      addLayerSwitcher = (layers: [any]) =&gt; {
  
          this.layers = layers;
  
      }
      toggleLayer = (layer, evt) =&gt; {
          evt.target.blur();
          if (layer.getVisible()) {
              layer.setVisible(false);
  
          } else {
              layer.setVisible(true);
          }
  
      }
  
      ngOnInit() {
          this.createMap();
      }
  
  }
  </code></pre>
  </blockquote>
  <p><strong>app.component.ts</strong></p>
  <blockquote>
  <pre><code>import { Component, OnInit, ViewChild } from '@angular/core';
  
  import { OlComponent } from './_component/ol.component';
  import {OlService} from './_component/ol.service';
  
  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: [OlComponent, OlService]
  })
  export class AppComponent implements OnInit {
    title = 'app works!';
  
  
    constructor(private olcomponent: OlComponent) {
      // constructor
    }
  
    ngOnInit() {
    // I WANT TO ADD MARKERS after the ol.component.ngOnInit() from an
    // outside API service - THIS CODE FAILS due to a null vectorSource 
    // object. 
    this.olcomponent.setMarker([38.909635, -77.043386], 'Dupont Circle', 'myid');  
  
    }
  }
  </code></pre>
  </blockquote>