How to create an ember property dependent on a normal variable, function or logic?
ember.js, javascript, leaflet
Solution
Ok, I think I've did it.
I used a computed property and an auxiliary property.
App.Leaflet = Ember.View.extend({
classNames : ['ember-leaflet'],
//default zoom level
zoomLevelValue : 13,
zoomLevel : function(key, value){
// getter
if (arguments.length === 1) {
var zoomLevel = this.get('zoomLevelValue');
return zoomLevel;
// setter
} else{
var map = this.get('map');
this.set('zoomLevelValue', value);
map.setZoom(value);
return value;
}
}.property('zoomLevelValue'),
didInsertElement : function() {
var self = this;
var zoomLevel = this.get('zoomLevel');
var map = L.map(this.$().get(0)).setView(center, zoomLevel);
// configure map instance...
// Event listeners
map.on('zoomend', function(e) {
console.log('zoomend', 'Setting zoomLevel '+e.target.getZoom());
self.set('zoomLevelValue', e.target.getZoom());
});
// save map instance
this.set('map', map);
}
});
Basically, there are two scenarios:
- zoomLevel was changed programatically -> we update the zoom on the map
- zoomLevel was changed on the map -> we set on the auxiliary property, and the computer property observers will also get notified, and we didn't set the zoom level on the map again
However I have a new problem, but I think it is leaflet related. When I call `setZoom` when another zoom animation on course, this setZoom is ignored. For example, executing:
map.setZoom(1);
map.setZoom(12);
ends up in the `1` zoom level.
Maybe a leaflet related SO question can help.
Problem
The problem I'm working on a leaflet view for emberjs, and I'm having some problems. Leaflet is an external library and somewhat irrelevant to the question, but just know that it is a mapping library. Consider a simple property like zoom level. Leaflet map instances have a zoom level accessible through `map.getZoom()` and assignable through `map.setZoom(zoomLevel)`. Also, users can interact with the map, and change its zoom level. Leaflet allows us to register a callback when the zoom changes. I would like my "Ember-Leaflet" View to have a `zoomLevel` ember property. This way I can benefit from the ember object model (bind `zoomLevel` to a template or to another value, for example), and we're doing it "the ember way". Base solution What I currently have is a subclass of Ember.View, with a zoomLevel property. On `didInsertElement` I create the Leaflet map instance. The code is commented and should be self-explanatory. ``` App.Leaflet = Ember.View.extend({ classNames : ['ember-leaflet'], //default zoom level zoomLevel : 13, didInsertElement : function() { var self = this; var zoomLevel = this.get('zoomLevel'); // create map instance var map = L.map(this.$().get(0)).setView(center, zoomLevel); // configure map instance... // Event listeners map.on('zoomend', function(e) { self.set('zoomLevel', e.target.getZoom()); }); // save map instance this.set('map', map); } }); ``` Checklist To make this question more "answerable", I think that a solution to this problem should fulfill the following requirements: - When the property `zoomLevel` is changed, the map should change its zoom level accordingly (using `map.setZoom(zoomLevel)`) - When the user interactively changes the zoom on the map, the `zoomLevel` property should be changed (probably using leaflet map's `zoomend` event callback) Notice that we have here a kind of "circular dependency", i.e "Do something (setZoom on map) when `zoomLevel` changes" and "when something happens (user changes zoom), change `zoomLevel`". I would like a solution that could avoid this circular observer dependencies. Ember's notifyPropertyChange could be a solution. This seemed like an ideal task for Ember's computed properties, but I didn't know what to put in the dependent properties string. `zoomLevel` is basically a property that is dependent on something that isn't an ember property. Update My first attempt was to use an observer to set the zoom on leaflet and to bind an event on leaflet `zoomend` to set the `zoomLevel` on my view. Problem: When I set zoomLevel on the zoomend leaflet event, I'm automatically triggering again my observer. Did I make myself clear? So, this sequence of events happen: - change `zoomLevel` on interactive map - leaflet fires `zoomend` event - `zoomend` event callback sets ember `zoomLevel` - observer runs - unecessarily calls `setZoom` on leaflet This is not efficient, but I wouldn't mind if it worked. The problem is that when the user changes zoom multiple times very quickly (a simple long scroll on map) the observer is called multiple times, confusing leaflet.