如何根据正常变量,函数或逻辑创建一个ember属性?

时间:2013-03-27 11:19:45

标签: javascript ember.js leaflet

问题

我正在为emberjs制作传单视图,我遇到了一些问题。 Leaflet是一个外部库,与问题有些无关,但只知道它是一个映射库。

考虑像缩放级别这样的简单属性。传单地图实例的缩放级别可通过map.getZoom()访问,并可通过map.setZoom(zoomLevel)分配。此外,用户可以与地图交互,并更改其缩放级别。当缩放发生变化时,Leaflet允许我们register a callback

我希望我的“Ember-Leaflet”视图拥有zoomLevel余烬属性。通过这种方式,我可以从ember对象模型中受益(例如,将zoomLevel绑定到模板或另一个值),我们就是“使用ember方式”。

基础溶液

我目前拥有的是Ember.View的子类,具有zoomLevel属性。在didInsertElement我创建Leaflet地图实例。代码已注释,应该是不言自明的。

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

清单

为了使这个问题更“可回答”,我认为这个问题的解决方案应该满足以下要求:

  1. 更改属性zoomLevel后,地图应相应更改其缩放级别(使用map.setZoom(zoomLevel)
  2. 当用户以交互方式更改地图上的缩放时,应更改zoomLevel属性(可能使用传单地图的zoomend事件回调)
  3. 请注意,我们在这里有一种“循环依赖”,即“当事情发生时zoomLevel更改”“时执行某些操作(setZoom在地图上)更改缩放),更改zoomLevel。我想要一个可以避免这种循环观察者依赖的解决方案。 Ember的notifyPropertyChange可能是一个解决方案。

    这似乎是Ember's computed properties的理想任务,但我不知道在依赖属性字符串中放入什么。 zoomLevel基本上是一个依赖于不是余烬属性的属性。


    更新

    我的第一次尝试是使用观察者在传单上设置缩放并在活页zoomend上绑定事件以在我的视图上设置zoomLevel

    问题:当我在zoomend leaflet事件上设置zoomLevel时,我会再次自动触发我的观察者。我清楚了吗?

    所以,这一系列事件发生了:

    1. 在互动地图上更改zoomLevel
    2. 宣传单点火zoomend事件
    3. zoomend事件回调设置了ember zoomLevel
    4. 观察员运行
    5. 在传单上不必要地调用setZoom
    6. 这效率不高,但我不介意它是否有效。 问题是,当用户非常快速地多次更改缩放时(地图上的一个简单的长滚动),观察者被多次调用confusing leaflet

3 个答案:

答案 0 :(得分:2)

好的,我想我已经做到了。

我使用了计算属性和辅助属性。

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

    }
});

基本上,有两种情况:

  1. 以编程方式更改了zoomLevel - >我们在地图上更新缩放
  2. 在地图上更改了zoomLevel - >我们设置了辅助属性,计算机属性观察者也会得到通知,我们没有再次在地图上设置缩放级别
  3. 但是我有一个新问题,但我认为它与传单有关。当我在另一个缩放动画播放时调用setZoom时,将忽略此setZoom。 例如,执行:

    map.setZoom(1);
    map.setZoom(12);
    

    1缩放级别结束。

    也许与传单相关的SO问题可以提供帮助。

答案 1 :(得分:1)

要从ember中的zoomLevel到setZoom,您可以使用观察者。

另一方面,你可能需要将一个事件绑定到传单上的zoomChange

答案 2 :(得分:1)

使用几乎不同的策略,我将zoomLevel设置为属性并从函数中观察它,并且如果属性的实际值与实际缩放不同,则仅在地图上设置缩放。 看到这个小提琴http://jsfiddle.net/5As2z/30/ 我将逻辑传递给控制器​​,视图在插入文档时设置了地图

App.ApplicationController = Ember.Controller.extend({
//default zoom level
zoomLevel: 13,
map: null,
zoomLevelChanged: function () {
    var zoomLevel = this.get('zoomLevel');
    var map = this.get('map');
    //Control not changing the zoom of the map if it is yet at the value
    if (zoomLevel != map.getZoom()) {
        map.setZoom(zoomLevel);
    }
}.observes('zoomLevel')});

App.ApplicationView = Ember.View.extend({
templateName: 'application',
didInsertElement: function () {
    var center = [41.3823000, 2.1825000];
    var controller = this.get('controller');
    var zoomLevel = controller.get('zoomLevel');
    var map = L.map('map').setView(center, zoomLevel);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    // configure map instance...

    // Event listeners
    map.on('zoomend', function (e) {
        console.log('zoomend', 'Setting zoomLevel ' + e.target.getZoom());
        controller.set('zoomLevel', e.target.getZoom());
    });

    // save map instance
    this.controller.set('map', map);
}});

HTML

<script type="text/x-handlebars" data-template-name="application">
    <h1> Leaflet map ember example </h1>
    {{view Ember.TextField valueBinding="zoomLevel"}}
    <div id="map"></div >
</script>