3

我希望有一个带有浮点属性的 Backbone 模型,但不必过多担心变量类型。

我想将值解析封装在模型中,因此我正在考虑覆盖该set函数:

var Place = Backbone.Model.extend({
  set: function(attributes, options) {
    if (!_.isEmpty(attributes.latitude)){
      attributes.latitude == parseFloat(attributes.latitude);
    }
    if (!_.isEmpty(attributes.longitude)){
      attributes.longitude == parseFloat(attributes.longitude);
    }
    Backbone.Model.prototype.set.call(this, attributes, options);
  }
});

然而,这似乎很麻烦,因为我在 validate 方法中会有类似的逻辑,并且可能会在多个模型中重复。我认为 View 不应该处理这些转换。

那么最好的方法是什么?

4

2 回答 2

2

为您的模型使用验证插件,以便您可以以通用方式验证输入。

那里有几个,包括我写的一个:

然后您不必担心在其他任何地方执行数据验证 - 您的模型会执行此操作并发送error您可以收听的消息并提供适当的反馈。

此外,在极少数情况下,lat/lng 对可以是整数,例如格林威治英格兰:0,0 或北极:90,180。并且由于 JavaScript 只有“数字”,所以 parseFloat 的任何有效输入对于 parseInt 也是有效的。

但是 parseFloat 总是会返回一个浮点数。

于 2012-04-07T00:20:47.500 回答
0

我的解决方案是Backbone.Model.prototype.set用预处理器代理替换:

/**
 * Intercept calls to Backbone.Model.set and preprocess attribute values.
 * 
 * If the model has a <code>preprocess</code> property, that property will be
 * used for mapping attribute names to preprocessor functions. This is useful
 * for automatically converting strings to numbers, for instance.
 * 
 * @param Backbone
 *            the global Backbone object.
 */
(function(Backbone) {
    var originalSet = Backbone.Model.prototype.set;
    _.extend(Backbone.Model.prototype, {
        set: function(key, val, options) {
            if(!this.preprocess) {
                return originalSet.apply(this, arguments);
            }

            // If-else copied from Backbone source
            if (typeof key === 'object') {
                attrs = key;
                options = val;
            } else {
                (attrs = {})[key] = val;
            }

            for(attr in this.preprocess) {
                if(_.has(attrs, attr)) {
                    attrs[attr] = this.preprocess[attr](attrs[attr]);
                }
            }
            return originalSet.call(this, attrs, options);
        },
    });
})(Backbone);

在此之后,具有preprocess属性的模型将使用它来将属性名称映射到预处理器函数。例如,preprocess: { age: parseInt }意味着无论何时设置属性,都会在实际设置之前age传递该值。parseInt没有对应preprocess条目的属性不会受到影响。

示例用法:

var Thing = Backbone.Model.extend({
    preprocess: {
        mass: parseInt,
        created: function(s) { return new Date(s); },
    },
});
var t = new Thing({
    label: '42',
    mass: '42',
    created: '1971-02-03T12:13:14+02:00',
});
console.log(t.get('label')+3); // 423
console.log(t.get('mass')+3); // 45
console.log(t.get('created').toLocaleString('ja-JP', { weekday: 'short' })); // 水

优点

  • 该功能适用​​于所有型号,无需重复代码
  • 无需{ validate: true }每次调用​​都发送到set
  • 无需在 中重复预处理validate,因为这发生在validate调用之前(这也可能是一个骗局,见下文)

缺点

  • 骨干代码的一些重复
  • 可能会破坏验证,因为预处理发生在validate调用之前。JavaScript 解析方法通常会返回无效值而不是抛出异常(即parseInt('foo')返回NaN),因此您应该能够检测到它。
于 2014-07-09T12:19:07.823 回答