Dojo中的ValidationTextBox使用Ajax vor验证

时间:2012-08-06 11:12:51

标签: dojo validation

这是另一个我不能相信尚未解决的问题...... 我正在创建一个注册表。现在......我需要做一些ajax异步验证。 这就是我现在正在做的事情(参见底部的代码)。

很好,它缓存已经检查过的值,它是异步等等但是:

  1. 您绝不会10000%确定在提交前已经过验证。这个 这是一个很大的交易,因为我也检查服务器端的东西。但 仍然......使这段代码在提交时“强制”验证 把它变成一个真正的怪物!

  2. 对于应有的事情,似乎需要做很多工作 准备好了

  3. (可能与2有关)我想不出一种方法可以使它实际上是通用的。我有另外10个字段需要类似的验证,但所有验证都有所不同,除了Ajax调用...而且我没有剪切和粘贴此代码10次!

  4. 我错过了一些非常明显的东西吗?有什么想法吗?

    define([
    'dojo/_base/declare',
    'dijit/form/ValidationTextBox',
    'dojo/_base/lang',
    'app/globals',
    ], function(
     declare
    , ValidationTextBox
    , lang
    , g
    ){
    return declare('app.ValidationWorkspace', [ ValidationTextBox ], {
    
     ajaxSaidNo: {},
     ajaxSaidYes: {},
     ajaxRequested: {},
    
     onChange: function(value){
       this.validate();
     },
    
     validator: function(value){
    
       // console.log("Started validation for " + value);
       // Ajax has already said no -- returning false straight away
       if(this.ajaxSaidNo[value] ){
         this.invalidMessage = 'Workspace taken';
         return false;
       }
    
       // Run the normal field validators -- if they fail,
       // return false
       var validation =  Validators.workspace(value);
       if( ! validation.result){
         this.invalidMessage = validation.message;
         return false;
    
       // At this point, regexp validators passed and Ajax hasn't said "no".
       } else {
         // console.log("OK, ajasSaidYes for " + value + " is " +  this.ajaxSaidYes[value]); 
         if(! this.ajaxSaidYes[value] ){
           g.stores.workspacesAnon.query({name: value}).then(
             lang.hitch(this, function(res){
               if(res && res.length ){
                 this.ajaxSaidNo[value] = true;
                 //console.log("Added to Ajaxfailed: " + value);
                 this.validate();
               } else {
                 //console.log("Added to Ajaxsuccess: " + value);
                 this.ajaxSaidYes[value] = true;
                 this.validate();
               }
             })
           );    
         }  
    
         return true;
       }
    
     },
    
      invalidMessage: "Workspace name not valid",
      missingMessage: "Workspace name cannot be empty",
    
    });
    
    }
     );
    

2 个答案:

答案 0 :(得分:1)

从TextBox本身提取自己并自定义onSubmit形式。在formDom.submit()之前使用的一般回调只是调用formDijit.validate()并将该布尔值传递给form.submit(如果它的错误,当然没有提交)。

换句话说,它期望验证器在每个验证器函数解析返回值之前运行阻塞/原子并且不返回。

在您的情况下,dojo.Deferred会派上用场。发现自己在form.onSubmit期间从ajax请求中获取响应 - 并且一旦所有具有“正在进行中”的ajax调用已经解决,那么如果真的提交了火灾。

<div tada-dojo-type="dijit.form.Form" id="form">
   <div data-dojo-type="app.ValidationWorkspace" name="inputfield" id="inputfield1"></div>
</div>

作为填写我在代码库中看不到的缺失内容的示例,下面是这个简化

<script>
    declare('app.ValidationWorkspace', [ ValidationTextBox ], {
         invalidMessageLocal : 'JS renders your entry invalid',
         invalidMessageServer: 'Server expects something different then you entered',
         invalidMessage: '',

         regExp: 'Foo*', // validates false if does not start with "Foo"

         dfdValidator: undefined,

         validator: function() {
              var curVal = this.get("value");
              if(new RegExp(this.regExp).test(curVal)) {
                    // client-side passes, run serverside
                    this.dfdValidator = dojo.xhrGet({
                         url: 'validate.sapi'+
                            '?field=' + this.inputNode.name +
                            '&value='+ value
                    });
                    // we cannot truly base anything form-wise here, but we might want
                    // to set a message (and show it, left out)
                    this.dfdValidator.then(dojo.hitch(this, function(response) {
                          this.invalidMessage = this.invalidMessageServer + " : " + response;
                    }));
              }
         }
    });
</script>

并使用与此类似的内容改变onSubmit上的表单:

<script>
     dojo.addOnLoad(function() {
       dijit.byId('form').onSubmit = function() {
        var immediate = true;
        var deferreds = [];
        dojo.some(dijit.byId('form')._getDescendantFormWidgets(), function(w) {
            if(w.validate) {
                var tmp = w.validate();
                if(!tmp) immediate = false;
                else { // check if it has servervalidation in flight
                     if(w.dfdValidator) {
                         // it does, store it so we can keep a count and 
                         // not submit before all has passed
                         deferreds.push(w.dfdValidator);
                     }
                }
            }
            return tmp; /* if false - one field failed - foreach(some) stops loop */
        }); // end dojo.some
        var form = this.domNode
        var submit = function() { 
               // logic to submit your values here
               store.put(dojo.formToJson(form));
        }
        // simply stop here if local validators fail
        if(immediate == false) {

             return false;

        } else if(deferreds.length > 0) {

             // do not act before all is done    
             var dfdCounter = new dojo.Deferred();
             dfdCounter.then(submit);
             var dfdCount = deferreds.length;
             var incrCount = 0;
             var delayed = true; // delayed validation
             dojo.forEach(deferred, function(serverValidatedComplete) {
                 serverValidatedComplete.then(function(serverresponse) {
                     incrCount++;
                     if(/REGEXPTOTESTRESPONSEFALSE/.test(serverresponse))
                          delayed = false;
                     if(dfdCount == incrCount && delayed == true) 
                     {    /* YES, all is done, any errors? */
                          dfdCounter.resolve(/* optional arguments here */); 
                     }
                 });
             });
        } else {
             // no server validators are running, local validation succeeds
             submit();
        }
        // never return true - or <form> will submit as HTML should be doing
        return false;
       } // end mutation
     });
</script>

答案 1 :(得分:0)

接受的答案可能是正确的解决方案。 但是,对于非阻塞的ajax检查,我最终编写了一个简单的mixin:

define([
  'dojo/_base/declare',
  'dojo/_base/lang',
  'app/globals',
  ], function(
    declare
  ,lang
  , g
  ){
    return declare(null, {

  ajaxSaidNo: {},
  ajaxSaidYes: {},
  ajaxRequested: {},

  constructor: function(){

    // Declaring object variable in constructor to make sure that
    // they are not class-wide (since they will be in the prototype)
    this.ajaxSaidNo = {};
    this.ajaxSaidYes = {};
    this.ajaxRequested = {};
  },

  // Overloads the validator, adding extra stuff
  ajaxValidate: function(value, options){

    // Set some defaults
    options.ajaxInvalidMessage = options.ajaxInvalidMessage || "Value not allowed";
    options.ajaxStore = options.ajaxStore || null;
    options.ajaxFilterField = options.ajaxFilterField  || 'name';

    // No ajaxStore query available, return true
    if( ! options.ajaxStore ){
      return true;
    }

    // console.log("Started validation for " + value);
    // Ajax has already said no -- returning false straight away
    if(this.ajaxSaidNo[value] ){
      this.invalidMessage = options.ajaxInvalidMessage;
      return false;
    }

    // console.log("OK, ajasSaidYes for " + value + " is " +  this.ajaxSaidYes[value]); 
    if(! this.ajaxSaidYes[value] ){
      var filterObject = {};
      filterObject[options.ajaxFilterField] = value;
      options.ajaxStore.query( filterObject ).then(
        lang.hitch(this, function(res){
          if(res && res.length ){
            this.ajaxSaidNo[value] = true;
            //console.log("Added to Ajaxfailed: " + value);
            this.validate();
          } else {
            //console.log("Added to Ajaxsuccess: " + value);
            this.ajaxSaidYes[value] = true;
            this.validate();
          }
        })
      );    
    }  

    return true;
  }

});
  }
);

然后在文本框的验证功能(或任何字段,真的)中,只需添加最小值以使其工作:

    return this.ajaxValidate(value, {
       ajaxInvalidMessage: "Workspace taken",
       ajaxStore: g.stores.workspacesAnon,
       ajaxFilterField: 'name',
    });

就是这样......好看又清晰,你可以把它应用到你喜欢的任何领域。 (如果我对我的方法收到足够令人鼓舞的评论,我会把这个作为“接受的”答案......)

Merc的。