2012-06-08 78 views
10

我需要驗證一個表單,其中有一堆輸入。而且,如果輸入無效,則以特定屬性無效的形式直觀地指示。爲此我需要驗證每個表單元素個別主幹:逐一驗證屬性

我有一個模型&代表整個表單的一個視圖。現在當我更新屬性時:

this.model.set('name', this.$name.val()) 

模型上的驗證方法將被調用。

但是,這種方法我驗證所有屬性,所以設置上面的屬性時,所有其他人也證實,如果任一個是無效的,則返回一個錯誤。這意味着即使我的'名稱'屬性有效,我也會爲其他人出錯。

那麼,如何驗證一個屬性呢?

我認爲不可能通過validate()方法驗證一個屬性。一種解決方案是不使用validate方法,而是驗證'change'事件的每個屬性。但是,這會造成很多變更處理程序。這是正確的方法嗎?我還可以做些什麼?

我也認爲這指向一個更大的問題在骨幹:

每當你使用model.set()設置在模型上的屬性,您的驗證方法運行和所有屬性被驗證。這似乎違反直覺,因爲你只是想要驗證這個單一的屬性。

+1

我同意,如果這是由設計,這的確是一個問題。如果您要爲表單創建模型,則許多字段將爲空,因此處於無效狀態。在調用save()之前,字段更改是否應該只保存在模型中?目前有活動代表進行現場更改。 – SAGExSDX

回答

9

Validate用於保持您的模型處於有效狀態,除非您通過silent:true選項,否則不會讓您設置無效值。

你既可以將您的所有屬性一氣呵成:

var M=Backbone.Model.extend({ 
    defaults:{ 
     name:"", 
     count:0 
    }, 

    validate: function(attrs) { 
     var invalid=[]; 
     if (attrs.name==="") invalid.push("name"); 
     if (attrs.count===0) invalid.push("count"); 

     if (invalid.length>0) return invalid; 
    } 
}); 

var obj=new M(); 
obj.on("error",function(model,err) { 
    console.log(err); 
}); 
obj.set({ 
    name:"name", 
    count:1 
}); 

或將它們設置

var M=Backbone.Model.extend({ 
    defaults:{ 
     name:"", 
     count:0 
    }, 

    validate: function(attrs) { 
     var invalid=[]; 
     if ((_.has(attrs,"name"))&&(attrs.name==="")) 
      invalid.push("name"); 
     if ((_.has(attrs,"count"))&&(attrs.count===0)) 
      invalid.push("count"); 

     if (invalid.length>0) return invalid; 
    } 
}); 

var obj=new M(); 
obj.on("error",function(model,err) { 
    console.log(err); 
}); 

if (!obj.validate({name:"name"})) 
    obj.set({name:"name"},{silent:true}); 
+1

返回一個對象映射屬性到他們的問題('{username:['too long','invalid chars'],...}')是另一種選擇。這可能更適合good_computer的問題。 –

+0

@ mu爲了可讀性,我儘量保持驗證邏輯儘可能短,您的確可以更好地匹配。 – nikoshr

+0

我不是在批評,只是提供一個可能的變體。這是一個很好的答案。 –

1

這不是Backbone的問題,它不會強制您以某種方式編寫驗證。驗證模型中保存的所有屬性沒有意義,因爲通常情況下,您的模型不包含無效屬性,因爲如果驗證失敗,導致set()不會更改模型,除非您傳遞無聲選項,但那是另一回事。但是,如果您選擇這種方式,由於上面提到的點,驗證總是會傳遞未更改的屬性。

您可以自由選擇另一種方式:僅驗證要設置的屬性(作爲參數傳遞給validate())。

+0

http://backbonejs.org/#Model-validate – Yaroslav

0

您還可以使用自己的自定義功能,通過無聲超載模型的設定功能。

set: function (key, value, options) { 
    options || (options = {}); 
    options = _.extend(options, { silent: true }); 
    return Backbone.Model.prototype.set.call(this, key, value, options); 
} 

這基本上在選項中傳遞{silent:true}並使用{silent:true}調用Backbone.Model集合函數。 這樣,你就不必通過{沉默:真正}作爲選項隨處可見,在這裏你調用 this.model.set(「propertyName的」,纈氨酸,{沉默:真})

爲了驗證你也可以使用Backbone.Validation插件 https://github.com/thedersen/backbone.validation

0

我必須對backbone.validation.js文件進行修改,但是它使得我的任務更加容易。我將下面的代碼片段添加到validate函數中。

validate: function(attrs, setOptions){ 
      var model = this, 
       opt = _.extend({}, options, setOptions); 
      if(!attrs){ 
       return model.validate.call(model, _.extend(getValidatedAttrs(model), model.toJSON())); 
      } 

      ///////////BEGIN NEW CODE SNIPPET///////////// 
      if (typeof attrs === 'string') { 
       var attrHolder = attrs; 
       attrs = []; 
       attrs[attrHolder] = model.get(attrHolder); 
      } 
      ///////////END NEW CODE SNIPPET/////////////// 

      var result = validateObject(view, model, model.validation, attrs, opt); 
      model._isValid = result.isValid; 

      _.defer(function() { 
       model.trigger('validated', model._isValid, model, result.invalidAttrs); 
       model.trigger('validated:' + (model._isValid ? 'valid' : 'invalid'), model, result.invalidAttrs); 
      }); 

      if (!opt.forceUpdate && result.errorMessages.length > 0) { 
       return result.errorMessages; 
      } 
     } 

我可以再調用驗證的單一屬性,像這樣

this.model.set(attributeName, attributeValue, { silent: true }); 
this.model.validate(attributeName);