How can I apply attribute types in the Backbone model?

I want to have a Backbone model with float attributes, but not worry too much about variable types.

I would like to encapsulate the parsing right in the model, so I am thinking about overriding the function 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);
  }
});

      

However, this seems cumbersome as I would have similar logic in the validator method and possibly repeated for multiple models. I don't think View should care about these conversions.

So what's the best way to do it?

+3


source to share


2 answers


Use an authentication plugin for your model so you can validate input in general.

There are several of them, including the one I wrote:



Then you don't have to worry about doing data validation elsewhere - your model does it and sends a message and a error

message that you can listen to and provide appropriate feedback.

In addition, the lat / lng pair can on rare occasions be an integer such as Greenwich England: 0,0 or North Pole: 90 180. And since JavaScript only has a "number", any valid input for parseFloat is also valid for parseInt.

But parseFloat will always return float.

+1


source


My solution was to replace Backbone.Model.prototype.set

with a preprocessor proxy:

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

      

The models with the property preprocess

will then use it to map attribute names to preprocessor functions. For example, preprocess: { age: parseInt }

means that whenever an attribute is set age

, the value will be passed through parseInt

before setting it. Attributes without a matching entry preprocess

will not be affected.

Usage example:

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' })); // ζ°΄

      



Pros

  • Functionality is available in all models without code duplication
  • Don't need to send { validate: true }

    in every callset

  • No need to duplicate preprocessing in validate

    , as this happens before it gets called validate

    (it could also be con, se below)

Against

  • Some duplication of baseline code
  • Powerful validation because preprocessing occurs before the call validate

    . JavaScript analysis methods typically return invalid values, instead of exceptions exceptions, though (ie parseInt('foo')

    returns NaN

    ), so you have to find it.
0


source







All Articles