0

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

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

  1. 您永远无法 10000% 确定它在提交之前已得到验证。这是一笔大买卖,因为我还在服务器端检查了一些东西。但仍然......让这个代码在提交时“强制”验证会将它变成一个真正的怪物!

  2. 对于一切都应该准备就绪的事情,这似乎需要做很多工作

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

我错过了一些非常明显的东西吗?有任何想法吗?

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",

});

}
 );
4

2 回答 2

1

将自己从 TextBox 本身中抽象出来,然后自定义表单 onSubmit。在 formDom.submit() 之前使用的一般回调只是调用 formDijit.validate() 并将该布尔值传递给 form.submit (如果它为假,当然不会发生提交)。

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

在你的情况下,dojo.Deferred派上用场了。发现自己在 form.onSubmit 期间从 ajax-requests 中获取响应 - 一旦所有“进行中”的 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>
于 2012-08-06T17:07:09.993 回答
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',
    });

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

默克。

于 2012-08-07T04:27:27.050 回答