Saturday, 29 November 2008

Demo Code for Union Validate with Lock

我把前面提到的,应用了“锁”机制的联合检查,做了一个简单的演示页面。

由于在BlogSpot上面,没办法将这个页面和对应的JavaScipt包一起放上来,所以只好打包,提供下载了。

Friday, 28 November 2008

MySQL 5.1 GA Released

MySQL 5.1 GA版本,已经正式发布。

MySQL 5.1 List of Changes来看,似乎5.1 GA版本在 14/11/2008 就已经正式发布了。不知为何静悄悄地,没什么动静。

我自己历来对MySQL不太感冒,总觉得在很多方面,不如PostgreSQL。MySQL,简单、快速,但功能不够完整。MySQL 5.1的正式发布,在功能性上有所提高。

其实,MySQL简单、快速,在很多场合下,也够用了。

Thursday, 27 November 2008

Hack on FormCheck : Union Validate with Lock

上一篇中,描述了如何用自定义validate函数,进行多个INPUT元素的联合检查。

在那里,是把myvalidate设置在多个INPUT中的某个元素上。这样的做法,是为了避免出现validate的递归调用,导致无限循环。但在实际应用的过程中,用户的实际使用体验,并不是最好的,因为实际的错误提示,总是出现在那一个INPUT元素上,而不是最近输入元素。

要想获得更好的用户体验,又要避免“死循环”的出现,可以使用“锁”的机制。下面介绍一个实际使用“锁”的例子。

在页面上,有两个INPUT元素,分别是最小值和最大值。正常的逻辑,最小值不能大于最大值,最大值不能小于最小值。这项检查,由自定义validate函数avOrder()来完成。

   1: <label><span>Minimum:</span>
   2: <input type="text" name="minValue" class="validate['required','digit','~avOrder']" /></label>
   3: <label><span>Maximum:</span>
   4: <input type="text" name="maxValue" class="validate['required','digit','~avOrder']" /></label>
   5:  
   6: <input type="submit" class="validate['submit']" value="Validate" />

相应的JavaScript Code:

   1: window.addEvent('domready', pageInitial);
   2:  
   3: var avLockCheck = null;
   4:  
   5: function pageInitial() {
   6:   avLockCheck = new FormCheck('avLockForm');
   7: }
   8:  
   9: var avlock = false;
  10: function avOrder(el) {
  11:   if( avlock )  return true;
  12:   avlock = true;
  13:  
  14:   var elParent = el.getParent('p');
  15:  
  16:   var minEl = elParent.getElement("[name^=min]");
  17:   var maxEl = elParent.getElement("[name^=max]");
  18:  
  19:   if( avLockCheck.validate( minEl ) && avLockCheck.validate( maxEl ) &&
  20:                          Number(minEl.value) > Number(maxEl.value) ) {
  21:       var errorMsg = (el == minEl ?
  22:                      "This value is great than maximum." :
  23:                      "This value is less than minimum." );
  24:       el.errors.push( errorMsg );
  25:  
  26:       avlock = false;
  27:       return false;
  28:   }
  29:  
  30:   avlock = false;
  31:   return true;
  32: }

在这段Code中,设置了一个“锁”变量avlock。进入avOrder(),检查“锁”状态,然后上“锁”。在退出avOrder()的时候,解“锁”。

在20行,实际隐含了一个迭代检查过程。利用“锁”机制,有效地防止了“死循环”的出现。

21行,针对不同的INPUT元素,给出相应的出错提示信息。

avOrder()中的16、17行,没有指定元素的具体tag,实际可以用来处理<INPUT>和<SELECT>标签。

通过minElmaxEl的获取方式,可以知道,<p>在这里被用作了分组标签。如果页面上有多组类似的,需要比较最大值和最小值的INPUT元素,avOrder()能够利用<p>进行分组,自动匹配对应的最大值、最小值元素。

页面上的INPUT元素,都附加了avOrder()检查,也都会给出相应提示。

Tuesday, 4 November 2008

Hack on FormCheck : Self-defining Validation with Multiple Elements

前面定义了FormCheck自定义函数接口,接口本身还是比较简单的。相对的,反而是在书写自定义validate函数的时候,还需要注意一些细节上的问题。

以我目前进行的项目为例,需要对同一行的三个text box,进行“数据和”的检验。把三个text box里的数相加,看它们的“和”,是否等于100。

HTML的Code:

   1: <td><input type="text" name="r2c1" class="validate['required','digit','~sum100']" /></td>
   2: <td><input type="text" name="r2c2" class="validate['required','digit']" /></td>
   3: <td><input type="text" name="r2c3" class="validate['required','digit']" /></td>

这里的自定义validate函数为 sum100,相应的JavaScript Code:

  1:   var infoCheck = null;
  2:   ...
  3:   infoCheck = new FormCheck('infoForm');
  4:   ...
  5:   function sum100(el) {
  6:     var asscItems = $$('input[name^=r2]');
  7:     var elStatus = true;
  8:     var elValue = Number(el.value);
  9: 
 10:     asscItems.each( function(ael) {
 11:       if( ael != el) {
 12:         var aelStatus = infoCheck.validate(oel);
 13:         elStatus &= aelStatus;
 14:         if( aelStatus ) {
 15:           elValue += Number(ael.value);
 16:         }
 17:       }
 18:     } );
 19: 
 20:     if( !elStatus || (elStatus && elValue == 100) ) {
 21:       return true;
 22:     }
 23:     else {
 24:       el.errors.push("Sum of inputs is not 100.");
 25:       return false;
 26:     }
 27:   }

需要注意的地方:

  • 涉及到的多个INPUT元素,都应该纳入FormCheck的validation范围中;
  • 需要实例化FormCheck给一个全局变量;
  • 在自定义validate函数中,可以使用FormCheck变量,对相关的其它元素进行验证;
  • 使用其它INPUT元素数据的时候,应首先对其进行验证,确保数据有效;
  • 特别注意,不要在自定义validate函数中,对本元素自身再次validate,避免出现validate的递归调用;
  • 多个INPUT元素的联合验证,自定义validate函数只设定在一个元素上面。不能在多个元素上设立相同的联合验证。原因同上。

使用~myvalidate这种形式的自定义validate函数,Form Validation感觉显得比较有层次,使得针对输入的普通验证,同涉及到多元素的逻辑性验证,相对分离开来。这是最初Hack FormCheck的主要原因之一。

Hack on FormCheck : Self-defining Validation

尽管FormCheck提供了很多的validation模式,但在实际应用中,总会遇到不够的时候,比如Fine Validation,多元素联合验证等等。这些validation的功能,往往需要自己去定义。

FormCheck目前的版本,还没有开放自定义validate函数的接口。只能先自己定义自定义函数接口,然后再把自定义validate函数adapt上去。

310:   validate : function(el) {
   :     ...
316:     el.validation.each(function(rule) {
317:       if(this.isChildType(el)) {
   :         ...
321:       } else {
   :         ...
344:         if (el.get('tag') == "select" || (el.type == "checkbox" && ruleMethod == 'required')) {
345:           if (this.simpleValidate(el) == false) {
346:              el.isOk = false;
347:           }
348:         }
349: 
350:         if(rule.match(/%[a-z0-9_]+$/) || (el.isOk && rule.match(/~[a-z0-9_]+$/))) {
351:           if( eval(rule.slice(1)+'(el)') == false ) {
352:             el.isOk = false;
353:           }
354:         }
355:       }
356:     }, this);
357:
358:     if (el.isOk) return true;
359:     else return false;
360:   },

* 以上改动,基于FormCheck v.1.4RC6。

350~354为增加的自定义validate函数接口。这里,定义了两种形式的接口,分别是:

  %myvalidate   '%'+自定义函数名,该validate将和其它validate一起工作;

  ~myvalidate   '~'+自定义函数名,该validate只有在其它validate都通过了之后,才会进行。属于额外的validate。应该是validate列表的最后一项。

自定义validate函数,要求能够接受element作为参数,并以true/false的形式,返回验证的结果。如果验证的结果为false,还需要手工设置出错信息。其基本结构,如下:

  1:   function myvalidate(el) {
  2:     var elValue = el.value;
  3:     var elStatus;
  4: 
  5:     elStatus = ... (elValue);
  6: 
  7:     if( elStatus ) {
  8:       return true;
  9:     }
 10:     else {
 11:       el.errors.push("It's really bad.");
 12:       return false;
 13:     }
 14:   }

在表单的INPUT中,使用自定义函数进行validation:validate['required','%myvalidate'],或者validate['required','~myvalidate']。

Hack on FormCheck : Disabled Input Element

最近结合MooTools 1.2使用FormCheck,进行Form数据的验证。显示效果,自然是很漂亮。不过,还是有地方不够完善,需要自己动动手。

其中一点,如果一个INPUT设置了required,但它被disabled之后,仍然会进行validation。增加313行,对disabled的元素,禁止(直接忽略)validation。一但该元素恢复enabled之后,validation也会自动恢复。

309:   ...
310:   validate : function(el) {
311:       el.errors = [];
312:       el.isOk = true;
313:       if( el.get('disabled') )    return true;    // skip the validation on the disabled element
314:       if (this.options.trimValue) el.value = el.value.trim();
315:   ...

* 以上改动,基于FormCheck v.1.4RC6。

在具体使用上,会遇到一个小问题。在INPUT是enabled的时候,validation没有通过,有出错提示出现,并会停留在页面上。这时,disable该INPUT元素,忽略validation,出错提示应该消失。这可以通过触发一个onBlur事件来实现。

  1:   var elStatus = ...;
  2:   var targetEl = $$('input[name=abc]');
  3: 
  4:   targetEl.set('disabled', elStatus);
  5: 
  6:   if(elStatus == '0') {
  7:       targetEl.fireEvent('blur');
  8:   }

这里,对name=abc的INPUT元素,进行enable/disable处理。一旦disable,就会关闭出错提示;而enable的时候,并不马上进行validation。这样比较符合正常的是用习惯。