Kevin Whitaker
Kevin Whitaker

Reputation: 13435

Backbone JS: Validating required nested attributes/models?

If I have a Backbone model who's defaults object looks like this:

defaults {
  "id" : null
  "name" : null,
  "url" : null,
  "admin" : {
    "id" : null,
    "email" : null
  }
}

is there a recommended way to validate the presence of something like admin[id]? We've written a method that makes the attempt, but it keeps puking (especially on new model creation) on null values, or if data is fetched from our DB with null values that are expected to be required (we are laying this app on top of existing data).

Here's our method for validating the presence of required fields:

validatePresence = function(requiredAttrs, submittedAttrs, errorsArr) {
  var regex = new RegExp(/[a-zA-Z0-9_]+|(?=\[\])/g),
  attrStack = null,
  val = null,
  name = null;

  for( var l = requiredAttrs.length; --l >= 0; ) {
      attrStack = requiredAttrs[l].match(regex);
      val = submittedAttrs[attrStack.shift()];
      while(attrStack.length > 0) {
            console.log(requiredAttrs[l]);
          val = val[attrStack.shift()];
      }

      if( val === undefined ) { continue; }

      name = requiredAttrs[l];
      if( val === null || !val.length) {
          if( !errorsArr[name] ) {
              errorsArr[name] = [];
          }
          errorsArr[name].push("Oops, this can't be empty");
      }
  }
  return errorsArr; 
}

And here's the way we call it from within a BB model:

validate: function(attrs) {
  var requiredAttributes = ["name","admin[id]"],
  errors = {};
  errors = validatePresence(requiredAttributes, attrs, errors);
}

That method likes to choke on things like "admin[id]". Any help is apprecaited.

Upvotes: 2

Views: 1245

Answers (1)

nikoshr
nikoshr

Reputation: 33364

If you're not dead set on the bracket notation for your required attributes, you could draw some inspiration from this Q&A to simplify your validation.

Let's add a helper method to _ to extract the value of a given attribute:

_.findprop = function(obj, path) {
    var args = path.split('.'), i, l=args.length;

    for (i=0; i<l; i++) {
        if (!obj.hasOwnProperty(args[i]))
            return;
        obj = obj[args[i]];
    }

    return obj;
}

Your validate method can then be rewritten as:

validate: function(attrs) {
    var requiredAttributes = ["name","admin.id"],
        errors = {}, i, l, v, attr;

    for (i=0, l=requiredAttributes.length; i<l; i++) {
        attr = requiredAttributes[i];
        v = _.findprop(attrs, attr);

        //checks if the value is truthy, to be adapted to your needs
        if (v) continue; 

        errors[attr] = errors[attr] || [];
        errors[attr].push("Oops, this can't be empty");
    }

    return errors;
}

And a demo http://jsfiddle.net/FrtHb/2/

Upvotes: 1

Related Questions