Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refreshing map data #140

Open
jamesdixon opened this issue Nov 7, 2015 · 6 comments
Open

refreshing map data #140

jamesdixon opened this issue Nov 7, 2015 · 6 comments

Comments

@jamesdixon
Copy link

Hi, I'm using ember-leaflet to display a map for an appointment's location. The user selects an appointment from a list and the corresponding appointment details (including the map) are then displayed.

When an appointment is selected, the details are passed to the component, which contains the map. Unfortunately, after the user selects an appointment and then another is selected, the coordinates on the map do not change. However, outputting the coordinates using Handlebars, I can in fact see that the different coordinates are being passed to the component. That leads me to believe that the map needs to be "refreshed" somehow in order for the new coordinates to be displayed on the map.

I use the component like so: {{ember-leaflet geoJSON=geoJSON}} where geoJSON is a string containing the location data.

My component is as follows:

// components/leaflet-map.js

import Ember from 'ember';
import ENV from '../config/environment';

import EmberLeafletComponent from 'ember-leaflet/components/leaflet-map';
import MarkerCollectionLayer from 'ember-leaflet/layers/marker-collection';
import TileLayer from 'ember-leaflet/layers/tile';

L.Icon.Default.imagePath = '/images/leaflet';

export default EmberLeafletComponent.extend({

  center: Ember.computed(function() {
    return this.get('coordinates');
  }),

  /////////////////////////////////////
  // PROPERTIES
  /////////////////////////////////////

  geoJSON: null,

  /////////////////////////////////////
  // COMPUTED PROPERTIES
  /////////////////////////////////////

  childLayers: Ember.computed('coordinates', function() {

    return [
      TileLayer.extend({
        tileUrl: 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}',
        options: {
          id: 'XXXXX',
          accessToken: ENV.APP.MAPBOX_KEY
        }
      }),
      MarkerCollectionLayer.extend({
        content: [{ location: this.get('coordinates') }]
      })
    ];
  }),

  coordinates: Ember.computed('geoJSON', function() {

    if (this.get('geoJSON')) {

      const coordinates = JSON.parse(this.get('geoJSON')).coordinates;

      if (coordinates) {
        return L.latLng(coordinates[1], coordinates[0]);
      }
    }

    return null;
  }),
});

When setting a breakpoint, it appears that childLayers and coordinates are only being called once regardless of which appointment is selected by the user. I've considered setting up an observer to observe the geoJSON property, but it seems overkill.

Any help would be greatly appreciated!

@jamesdixon
Copy link
Author

I've refactored my code based on some of the other threads as such:

import Ember from 'ember';
import ENV from '../config/environment';

import EmberLeafletComponent from 'ember-leaflet/components/leaflet-map';
import MarkerLayer from 'ember-leaflet/layers/marker';
import TileLayer from 'ember-leaflet/layers/tile';

L.Icon.Default.imagePath = '/images/leaflet';

export default EmberLeafletComponent.extend({

  center: Ember.computed(function() {
    return this.get('coordinates');
  }),

  /////////////////////////////////////
  // PROPERTIES
  /////////////////////////////////////

  geoJSON: null,

  /////////////////////////////////////
  // COMPUTED PROPERTIES
  /////////////////////////////////////

  childLayers: Ember.computed(function() {

    return [
      TileLayer.extend({
        tileUrl: 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}',
        options: {
          id: 'scoutforpets.o2ml3nm1',
          accessToken: ENV.APP.MAPBOX_KEY
        }
      }),
      MarkerLayer.extend({
        component: this,
        contentBinding: Ember.computed.reads('component.coordinates')
      })
    ];
  }),

  coordinates: Ember.computed('geoJSON', function() {

    if (this.get('geoJSON')) {

      const coordinates = JSON.parse(this.get('geoJSON')).coordinates;

      if (coordinates) {
        return { location: L.latLng(coordinates[1], coordinates[0]) };
      }
    }

    return null;
  })
});

Unfortunately, I'm still not having any luck. All I mentioned above, I'm simply trying to change the marker on the map when new data is passed in, but it's been seemingly difficult to get working. I'm sure it's something trivial, but am really pulling my hair out at this point!

@gabesmed @miguelcobain would you be able to lend 5 minutes to offer some advice? Thank you!

@miguelcobain
Copy link
Collaborator

@jamesdixon As a hint, remember that each child layer has controller set to the components instance.

Try to:

  • Extend the layers separately (you can even put them in separate files afterwards in app/layers and then import them) and then in the EmberLeafletComponent use just childLayers: [MapBoxTileLayer, AppointmentMarkerLayer].
    This will lead to a more maintainable, readable and testable code.
  • More importantly, remember that each child layer instance has controller set to the EmberLeafletComponent's instance. This is extremely useful to compose layers this way.
    Your example should become something like:
{{ember-leaflet appointmentLatlng=appointmentLatlng center=center ...}}
//TODO move to separate file
let AppointmentMarkerLayer = MarkerLayer.extend({
  location: Ember.computed.alias('controller.appointmentLatlng')
});

//TODO move to separate file
let MapBoxTileLayer = TileLayer.extend({
  //...
});

export default EmberLeafletComponent.extend({
  childLayers: [MapBoxTileLayer, AppointmentMarkerLayer]
});

This way, whenever appointmentLatlng changes, the marker's position will also change.
I would handle the geoJSON stuff outside of the component.
Well, not entirely mandatory, but just my preference.
I see geoJSON format as a data concern, which a map component should not care about.

@jamesdixon
Copy link
Author

@miguelcobain I appreciate the advice. Going to take a break from this for a bit and will give it a shot. Thank you for your response!

@localyost
Copy link

awesome thank you for the response and thanks to @jamesdixon for the question! I externalized all childLayers into app/layers/ and was able to bind location to the coords passed through the component interface! This changes everything for me! Thanks again guys!

@miguelcobain
Copy link
Collaborator

@localyost consider using ember-leaflet 2.0 - www.ember-leaflet.com

@localyost
Copy link

Just stumbled across it after that last post! Great work man, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants