2016年5月6日 星期五

html5 的 setCustomValidity(message) 觀念釐清

在這篇文中主要是要釐清在使用setCustomValidity(message)的一些觀念,
setCustomValidity(message)可以跟據送入的message是否是空字串來蓋住input元素的validity狀態,但是要注意的是,並不會蓋掉input元素的validity狀態,input元素的真實validity狀態並不會因此而改變。

為了驗證這個現像,我們可以看一下下面這個例子:
當我們呼叫
setCustomValidity("自訂訊息");
時,input的真正valid訊息會被隱藏起來,而這時去看input的validity.valid的話就得到false的結果,就算我們在input中打字也是一樣,
但其實input在有打字內容時其直正的validity.valid應該是true。
我們可以呼叫setCustomValidity("")來讓input的真正validity.valid不要被蓋往,這時我們可以從isValid(after setCustomValidity("")):來得到之前被隱藏的正確結果。

========================================================================

這裡我再舉出一個比較常用的使用setCustomValidity("")的例子:

可以看到我們再input的oninvalid和oninput都呼叫check(this),這是因為當在input中打字時,就算打的內容不符合設定的pattern,也不會觸發oninvalid,只會觸發oninput。

我們在check(target)中先呼叫setCustomValidity("")得到input的真正valid狀態,如果真正valid為false就呼叫setCustomValidity("自訂訊息"),而因為此呼叫會讓之後valid的真正狀態被隱藏,所以我們之後會再呼叫check時呼叫setCustomValidity("")來讓input的真正valid狀態不要被隱藏起來。

這樣之後再用if()詢問input的狀態時,就不會得到錯的、與實際不符的valid狀態了。
重點就是,在檢查valid的狀態時必須要真正的(沒被隱藏的),再判斷要不要設定自訂訊息後。

========================================================================

接下來我再舉出一個例子,有時候我們會想要對一個Group,即一群name一樣的input元素去做判斷,例如對於input="radio"只會想要同一個Group裡的radio被選取,像下面這樣:


如果想在radio的oninvalid和onclick使用上述的check(target)方法的話,會造成錯誤。
如果有兩個設置rquired的同name的radio且都沒有被點擊時,按下submit後會對每一個radio呼叫check(target)並都被隱藏真正valid狀態。
當點擊第二個radio時,會只對第二個radio呼叫check(target),此時第二個radio的valid會是true,但對一個radio的valid還是false,所以此時按下submit會無法submit,接著又因為submit會讓每一個check(target)都被呼叫,所以此時每一個radio的valid狀態都才會正常,再按一次submit就可以成功submit了。

結果是submit要按兩下才會成功,這很顯然不是我們想要的,所以我們要做一點改良。

以下就是改良的方法,checkValid(target),在其中也對一個input用radio來設置不同的pattern check:

重點就是在checkValid(target)裡面必須對所有group裡面的input都去做檢查並設置正確的valid狀態,如此一來,不管是submit還是onclick就都能對所有的input設置正確的valid狀態了
(當然submit會輪詢一次所有input,而checkValid(target)又會輪詢一次,所以會輪詢兩次造成效能上的浪費,不過這裡就忽略此issue了)。



2016年5月3日 星期二

html5 自訂表單驗證的警示文字 - setCustomValidity(message)

html5 的表單驗證非常方便,能根據設置的type (例如:email, phone等)、requiered屬性的有無設置等在form中有input為invalid時,顯示提示文字,

不過我們通常會想要的不是預設的,而是自訂的提示文字,這時就可以用到setCustomValidity(message)這個javascript方法。

setCustomValidity(message)可以由 input type='xxx' 的元素呼叫,
它接受一個字串作為自訂的提示文字,要注意的是,當此方式呼叫該方法時,input元素的valid狀態會被invalid蓋住(不是蓋掉)。如果我們送入的字串為空字串,則此input元素的valid狀態會回復正常(沒被蓋往)。

所以我們可以在input驗證不通過時呼叫setCustomValidity('XXX'),並在它的內容值有改變或有被key in值時呼叫setCustomValidity('')來得到input的真正valid狀態(否則那個input就永遠是invalid)。

看一下下面的例子:

這裡有兩個 form,並且各自有一個設置required的input type='text',兩個form都設置了
oninvalid="setCustomValidity('XXX')"
所以當沒有填值按下form的submit按鈕時,就會跳出自訂的提示文字並且阻止form的submit動作。

因為第一個form的input設置了onchange="setCustomValidity('');",所以在input中的值改變時會對此input進行invalid error的清除,但此時我們會發現當在此input中打字時,提示文字不會消除且一直出現。
這是因為onchange在此input失去焦點(off focus)且值有改變(change)時才會觸發,當我們點擊Form1的第二個input再點回要reqired的input並打字時,提示文字就不會出現了。
當然,這通常不是我們想要的結果。

第二個Form的input設置了oninput="setCustomValidity('');",使用了oninput而不是onchange來呼叫重設input的invalid狀態,oninput會在使用者對input打字時被觸發,於是當提示文字出現時,只要再input中打字(不用使其焦點),就可以得到input的invalid狀態了,而這個結果也是我們所期望的。

參考資料:

  1. JavaScript Validation API
  2. oninput Event
  3. onchange Event
  4. HTML5應用:setCustomValidity(message)接口


源碼:
<form>
  Form 1
  <input type='text' oninvalid="setCustomValidity('Cusotm Alert 1');" onchange="setCustomValidity('');" placeholder='This input is required' required/>
  <input type='text' />
  <input type='submit' />
</form>
<form>
  Form 2
  <input type='text' oninvalid="setCustomValidity('Cusotm Alert 2');" oninput="setCustomValidity('');" placeholder='This input is required' required/>
  <input type='text' />
  <input type='submit' />
</form>