Ember.js:如何从视图中调用模型中定义的方法?

时间:2013-08-18 01:56:34

标签: ember.js ember-data

我正在开发一个适用于世界各地的应用。我有一个余烬模型:Clock
我想每秒更新一次时钟的time属性。

目前,我已经在时钟中定义了一个start方法,负责更新时钟模型的时间属性。

我有两个问题: 1.如何从我的视图中调用模型的start方法 2.我能采取更好的方法吗?

这是我的模型,视图,控制器,路由器和模板(如果你感兴趣的话):

型号:

App.Clock = DS.Model.extend({
    city: DS.attr('string'),
    country: DS.attr('string'),
    latitude: DS.attr('string'),
    longitude: DS.attr('string'),
    time: DS.attr('date'),
    order: DS.attr('number'),

    start: function() {
        var clock = this;

        var updateTime = function() {
            var timezoneService = Utilities.TimezoneService;

            timezoneService.getTimezone(clock.get('latitude'), clock.get('longitude'), function(timezone) {
                clock.set('time', timezoneService.getDateTime(timezone.offset));
            });
        };

        updateTime();

        window.setInterval(function() {
            updateTime();
        }, 1000);
    }
});

查看:

App.ClocksView = Ember.View.extend({
  templateName : 'world_clock/clocks'
});

App.ClocksNewView = Ember.View.extend({
  templateName : 'world_clock/new'
});

控制器:

App.ClocksController = Ember.ArrayController.extend({
    sortProperties: ['order']
});

App.ClocksNewController = Ember.ObjectController.extend({
    city: null,
    save: function() {
        var cityName = this.get('city');
        if(!cityName.trim()){
            return;
        }

        var locationService = Utilities.LocationService.getInstance();

        locationService.lookupLocation(cityName, function(location) {
            var city = location.city;
            var country = location.country;
            var lat = location.latitude;
            var lon = location.longitude;

            if(city && country && lat && lon) {
                var clks = App.Clock.find({ city: city });
                clks.on('didLoad', function() {
                    if(clks.get('length') === 0) {
                        var clock = App.Clock.createRecord({
                            city: location.city,
                            country: location.country,
                            latitude: location.latitude,
                            longitude: location.longitude,
                            order: 10
                        });

                        clock.save();
                    }
                });
            }
        });

        this.set('city', '');

        this.get('target').transitionTo('clocks');
    }
});

路由器:

App.Router.map(function() {
    this.resource('clocks', { path: '/' }, function() {
        this.route('new');
    });
});

App.ClocksRoute = Ember.Route.extend({
    model: function() {
        var locationService = Utilities.LocationService.getInstance();

        locationService.getLocation(function(location) {
            App.Clock.createRecord({
                city: location.city,
                country: location.country,
                latitude: location.latitude,
                longitude: location.longitude,
                order: -10
            });
        });

        return App.Clock.find();
    }
});

clocks.handlebars:

{{outlet}}
{{#linkTo "clocks.new"}}Add Clock{{/linkTo}}
<ul>
    {{#each controller}}
    <li>{{city}}, {{country}} - {{time}}</li>
    {{else}}
    You have not defined any clock yet.
    {{/each}}
</ul>

new.handlebars:

<form {{action "save" on="submit"}}>
    {{view Ember.TextField valueBinding="city" placeholder="City"}}
    <button>Save</button>
</form>

1 个答案:

答案 0 :(得分:3)

  

如何从我的视图中调用模型的start方法

除极少数情况外,从视图中调用模型方法不是一个好主意。这说有可能。例如,您可以使用类似didInsertElement:

的内容
{{each controller itemViewClass="App.ClockView" emptyViewClass="App.NoClocksView"}}

App.ClockView = Ember.View.extend({
  template: Ember.Handlebars.compile("<li>{{city}}, {{country}} - {{time}}</li>"),
  didInsertElement: function() {
    var clock = this.get('content');
    clock.start();
  }
});

App.NoClocksView = Ember.View.extend({
  template: Ember.Handlebars.compile("You have not defined any clock yet.")
});

这种方法的问题在于它有点破坏封装,这意味着许多微妙的事情可能会出错。例如,如果ember重新使用视图,那么它有一个新的时钟,但不运行didInsertElement。这就是Initializing State in didInsertElement不是一个好主意的原因。或者如果用户导航到此路线或从该路线导航,那么模型时钟将在后台运行,然后当用户返回时他们全部重新开始。这导致我:

  

我能采取更好的方法吗?

可能time不应该是App.Clock的属性。这不像你想在数据库中节省时间,对吗?一种选择是:    - 给App.Clock计算属性以获得时区偏移量    - 将一个currentTime属性添加到clocksController    - 插入ClocksView后,使用setTimeout每秒刷新currentTime    - 制作一个呈现特定时钟的组件(世界时钟)    - 将计算属性time添加到world-clock,它计算给定currentTime和时钟的时区偏移量的时间。

这样的事情:

<script type="text/x-handlebars" id="clocks">
{{outlet}}
{{#linkTo "clocks.new"}}Add Clock{{/linkTo}}
<ul>
{{#each clock in controller}}
<li>
{{world-clock city="clock.city" country="clock.country" offset="clock.offset" currentTime="currentTime"}}
</li>  
{{/each}}
</ul>
</script>

<script type="text/x-handlebars" id="components/world-clock">
  {{city}}, {{country}} - {{time}}
</script>

App.Clock = DS.Model.extend({
  city: DS.attr('string'),
  country: DS.attr('string'),
  latitude: DS.attr('string'),
  longitude: DS.attr('string'),
  order: DS.attr('number'),
  offset: function() {
    var offset;
    var service = Utilities.TimezoneService;
    service.getTimezone(this.get('latitude'), this.get('longitude'), function(zone) {
      offset = timezone.offset
    });
    return offset;
  }.property('latitude', 'longitude')
});

App.WorldClockComponent = Ember.Component.extend({
  tagName: 'li',
  time: function() {
    var service = Utilities.TimezoneService;
    return service.getDateTime(this.get('offset'));
  }.property('offset', 'currentTime');
});