게시판 본문 ASP, ASP.NET, IIS & Script - Read Only

HTML 입력필드에 값검증 기능을 내장시키자! HTC를 이용한 validator
작성자: 박노철
작성일시: 2005-07-29 10:19,  조회수: 6,344
프로젝트를 하다보면 이런저런 HTML 입력필드들의 값유효성을 검증해야 할 일들
이 많은데요, 그럴 때를 위해서 만들어봤습니다. 다음과 같은 상황을 가정해봅시다.

어떤 input box 에 대해서 YYYYMMDD 형식의 값을 필수적으로 입력해야 하는데, 이런 상황이 여러번 나타납니다. 보통의 경우라면 값검증함수를 .js 파일로 빼놓고 여기다가 input tag object 자체를 파라미터로 던져서 값을 검증하죠. 하지만 좀 더 OOP 적으로 사고를 해본다면, input tag 자체에 값검증 기능이 들어가도록 확장할 수 있으면 더 좋지 않을까요?? 즉, 코드가 다음과 같이 만들어졌으면 좋겠다는 이야기입니다.
<input type="text" id="txtMandatoryYYYYMMDDTest" style="behavior:url(validator.htc)" 
MANDATORY="Y" YYYYMMDD="Y">
아시다시피 공식적인 DHTML 표준에는 input 태그에 MANDATORY 니, YYYYMMDD 니 하는 것들이 없습니다. 하지만 HTC 를 사용하면 input 태그 자체를 확장할 수 있습니다.

의미를 설명해드리자면, MANDATORY="Y" 는 이 필드의 값은 필수적으로 입력해야하고 YYYYMMDD="Y"는 이 필드의 값형식은 YYYYMMDD 형식이어야만 한다는 뜻입니다. 이렇게 HTML 태그 자체를 확장해놓고 Javascript 에서
txtMandatoryYYYYMMDD.validate(); 
만 부르면 HTML 에 선언해놓은데로 값검증이 이루어지는 겁니다.


또다른 시나리오로 이런것도 생각해볼 수 있겠죠. SELECT tag 에 대해서 form submit 하기전에 이 SELECT 는 반드시 선택을 해야합니다. 그것을 검증해야되는데, 위의 접근법을 적용한다면 다음과 같은 방식을 생각해볼 수 있습니다.

"SELECT 태그자체에 '반드시 이 필드는 선택해야한다' 는 속성을 정의해놓고 validate() 함수를 부르면 그 속성에 따라 값을 검증한다."

DHTML 코드로 나타내면 다음과 같겠지요.
<select id="selMustChooseTest" style="behavior:url(validator.htc)" MUSTCHOOSE="Y">
그런담에
selMustChooseTest.validate(); 
를 부르면 되는겁니다.


위의 두가지를 종합하면 다음과 같은 시나리오도 가능합니다. frmTest라는 폼에 위에서 이야기한 두개의 form element와 validator.htc 를 attach 하지 않은 일반적인 폼 요소가 있다고 합시다. 코드는 대충 다음과 같습니다.
<form id="frmTest">
    <input type="text" id="txtMandatoryYYYYMMDDTest" style="behavior:url(validator.htc)"
 MANDATORY="Y" YYYYMMDD="Y">
    <select id="selMustChooseTest" style="behavior:url(validator.htc)" MUSTCHOOSE="Y">
    <input type="text" id="txtNonValidatorTest">
</form>
이제 이 폼을 검증하고 싶습니다. 저는 이렇게 할 것 같습니다.
for(var i = 0; i < frmTest.element.length; i++) {
    try {frmTest.element(i).validate(); } catch(e) {}
}
try ... catch 를 쓴 이유는 txtNonValidatorTest 때문입니다. 여기에는 validator.htc 가
behavior 로 attach 되어 있지 않습니다. 그래서 validate() 함수를 호출하면 스크립트 에
러가 납니다. 그걸 무시하기 위해서 try ... catch 를 쓴 것이죠. 사실 모든 폼에
validator.htc 를 적용할 수는 없을 것이고, 몇개의 폼요소들이 가지는 값들을 한꺼번
에 검증해야 할 필요도 있습니다. 그럴때는 이 validator.htc 를 사용할 수는 없습니다.
그때는 따로 비즈니스적인 의미가 들어가는 검증로직을 만들어야 하겠죠. 하지만 단
순반복되는 필수입력여부체크, 선택여부체크, YYYYMMDD 체크같은 것들, 숫자만 입
력해야하는 것들의 검증로직들은 validator.htc 에 모두 담아놓고 위의 for 루프 한방
에 기본적인 검증은 모두 끝낼 수 있겠지요.

아래는 validator.htc 의 소스입니다~
매우 허접하니까 저작권따윈 주장할 생각이 없고요 ^^
다들 유용하게 고쳐서 쓰세요~ 고친거는 다같이 공유하면 더 좋구요~~
<PUBLIC:COMPONENT>
    <PUBLIC:PROPERTY ID="isMandatory" NAME="MANDATORY" 
            GET="getMandatory" PUT="setMandatory"></PUBLIC:PROPERTY>
    <PUBLIC:PROPERTY ID="mandatoryErrMsg" NAME="MANDATORY_MSG" 
            GET="getMandatoryErrMsg" PUT="setMandatoryErrMsg"></PUBLIC:PROPERTY>
    <PUBLIC:PROPERTY ID="isNumOnly" NAME="NUMONLY" 
            GET="getNumOnly" PUT="setNumOnly"></PUBLIC:PROPERTY>
    <PUBLIC:PROPERTY ID="numonlyErrMsg" NAME="NUMONLY_MSG" 
            GET="getNumOnlyErrMsg" PUT="setNumOnlyErrMsg"></PUBLIC:PROPERTY>
    <PUBLIC:PROPERTY ID="isChosen" NAME="MUSTCHOOSE" 
            GET="getChosen" PUT="setChosen"></PUBLIC:PROPERTY>
    <PUBLIC:PROPERTY ID="chosenErrMsg" NAME="CHOSEN_MSG" 
            GET="getChosenErrMsg" PUT="setChosenErrMsg"></PUBLIC:PROPERTY>
    <PUBLIC:PROPERTY ID="isYYYYMMDD" NAME="YYYYMMDD" 
            GET="getYYYYMMDD" PUT="setYYYYMMDD"></PUBLIC:PROPERTY>

    <PUBLIC:METHOD NAME="validate"></PUBLIC:METHOD>

    <PUBLIC:ATTACH EVENT="onkeyup" ONEVENT="keyup()" />
    <PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="documentready()" />
    
<script language="jscript">
/////////////////////////////////////////////////////////////////////////////////
// HTML 입력필드 종합 validator
// 
// 사용법:
//       <input type="text" style="behavior:url(validator.htc)" MANDATORY="Y" 
//      YYYYMMDD="Y">
//       <select style="behavior:url(validator.htc)" MUSTCHOOSE="Y">
//
// 2005/7/18 박노철
/////////////////////////////////////////////////////////////////////////////////

var isMandatory = null;
var mandatoryErrMsg = "필수적으로 값을 입력해야 합니다";
var isNumOnly = null;
var numonlyErrMsg = "숫자만 입력해야합니다";
var isChosen = null;
var chosenErrMsg = "필수적으로 하나의 항목을 선택해야 합니다";
var isYYYYMMDD = null;

var prevVal = "";        // numonly 가 y 일 때 가장 최근에 입력한 값을 저장함.


///////////////////        mandatory validation    //////////////////////////////////

function getMandatory()    { return isMandatory; }
function setMandatory(val) {
    if(element.type.toLowerCase() != "text")
        throw new Error(0,"<INPUT type=text> 에만 필수입력을 설정할 수 있습니다");
    
    this.isMandatory = (val.toLowerCase() == "true" || 
                        val.toLowerCase() == "yes"  || 
                        val.toLowerCase() == "y") ? true :false;
}

function getMandatoryErrMsg()    { return this.mandatoryErrMsg; }
function setMandatoryErrMsg(val) { 
    this.mandatoryErrMsg = (val) ? val : "필수적으로 값을 입력해야 합니다"; 
}

function validateMandatory() {
    if(!this.isMandatory) return true;
    
    if(element.value ==  "" || element.value == null) {
        alert(this.mandatoryErrMsg);
        element.focus();
        element.select();
        return false;
    }
    return true;
}

///////////////////        numonly validation        /////////////////////////////////

function keyup() {
    if(this.isNumOnly) {         // 숫자만 입력받는 조건 체크
        var key = window.event.keyCode;
        // END          HOME         LEFT         RIGHT        BACKSPACE
        if(key == 35 || key == 36 || key == 37 || key == 39 || key == 8) {
            this.prevVal = element.value;
            return;
        }
        
        if(key < 48 || key > 57) 
            element.value = this.prevVal;
        else {
            if(window.event.shiftKey) 
                element.value = this.prevVal;
            else
                this.prevVal = element.value;
        }    
    }
}

function documentready() {
    // 이 element 에 포커스가 왔을 때 한글입력기를 아예 disable 시킨다. 
    // 한글입력을 안받기 위해서
    if(this.isNumOnly) element.style.imeMode = "disabled";
}

function getNumOnly()    { return this.isNumOnly; }
function setNumOnly(val) {
    if(element.type.toLowerCase() != "text")
        throw new Error(0,"<INPUT type=text> 에만 숫자만 입력가능을 설정할 수 있습니다");

    this.isNumOnly = (val.toLowerCase() == "true" || 
                      val.toLowerCase() == "yes"  || 
                      val.toLowerCase() == "y") ? true :false;
}

function getNumOnlyErrMsg()    { return this.numonlyErrMsg; }
function setNumOnlyErrMsg(val) { 
    this.numonlyErrMsg = (val) ? val : "숫자만 입력해야합니다"; 
}

function validateNumOnly() {
    if(!this.isNumOnly) return true;
    
    if(isNaN(element.value)) {        // 숫자가 아니면
        alert(this.numonlyErrMSg);
        element.focus();
        element.select();
        return false;
    }
    return true;
}

//////////////////        select box chosen validation    //////////////////////////

function getChosen()    { return this.isChosen; }
function setChosen(val) { 
    if(element.tagName.toLowerCase() != "select")     
        throw new Error(0,"<SELECT> 요소에만 MUSTCHOOSE 를 설정할 수 있습니다");

    this.isChosen = (val.toLowerCase() == "true" || 
                     val.toLowerCase() == "yes"  || 
                     val.toLowerCase() == "y") ? true :false;
}

function getChosenErrMsg()    { return this.chosenErrMsg; }
function setChosenErrMsg(val) { 
    this.chosenErrMsg = (val) ? val : "필수적으로 하나의 항목을 선택해야 합니다"; 
}

// select 박스에서 하나를 반드시 선택해야 함
function validateChosen() {
    if(!this.isChosen) return true;
    
    if(element.selectedIndex <= 0) {
        alert(this.chosenErrMsg);
        element.select();
        element.focus();
        return false;
    }
    return true;
}

//////////////////        YYYYMMDD 포맷 validation        ////////////////////////

function getYYYYMMDD()    { return isYYYYMMDD;    }
function setYYYYMMDD(val) {
    if(element.tagName.toLowerCase() != "input") 
        throw new Error(0,"<INPUT> 요소에만 YYYYMMDD 를 설정할 수 있습니다");
    
    if(element.type.toLowerCase() != "text") 
        throw new Error(0,"<INPUT type=text> 에만 YYYYMMDD 를 설정할 수 있습니다");

    this.isYYYYMMDD = (val.toLowerCase() == "true" || 
                       val.toLowerCase() == "yes"  || 
                       val.toLowerCase() == "y") ? true :false;
    
    // yyyymmdd 입력가능하다는 이야기는 numonly 라는 것
    // yyyymmdd 가 false 이더라도 numonly 일 수 있으므로 
    // false 처리는 안해줌                    
    if(this.isYYYYMMDD) this.setNumOnly("Y"); 
}

function validateYYYYMMDD() {
    if(!this.isYYYYMMDD) return true;
    
    var val = element.value;
    var y = parseInt(val.substring(0,4),10);
    var m = parseInt(val.substring(4,6),10);
    var d = parseInt(val.substring(6,8), 10);
    
    if(val.length != 8) {
        alert("YYYYMMDD 포맷이 아닙니다. 다시 입력해주십시오.");
        element.focus();
        element.select();
        return false;
    }
    
    if(y < 1900) {
        alert("연도가 잘못 입력되었습니다. 다시 입력해주십시오.");
        element.focus();
        element.select();
        return false;
    }
    
    if(m > 12 || m < 1) {
        alert("잘못된 달입니다. 다시 입력해주십시오.");
        element.focus();
        element.select();
        return false;
    }
    
    if(d > 31 || d < 1) {
        alert("잘못된 날짜입니다. 다시 입력해주십시오.");
        element.focus();
        element.select();
        return false;
    }
    return true;
}

///////////////////        종합 validate 함수        ////////////////////////////

function validate() {
    if(!validateMandatory()) return false;
    if(!validateChosen()) return false;
    if(!validateNumOnly()) return false;
    if(!validateYYYYMMDD()) return false;
    return true;
}

</script>
</PUBLIC:COMPONENT>
IP 주소: 165.141.120.133
전체 1 건의 댓글이 존재합니다.

송원석

대단히 감사합니다. 이런식으로 많은 분들이 자작 HTCs 를 공개해주시면 나중엔 어지간한 수준의 라이브러리도 될 수 있을것 같네요. 유용하게 참고하도록 하겠습니다. 감사합니다. ^_^
2005-07-29 10:49
전체 2,095 건의 게시물, 84 페이지로 구성된 ASP, ASP.NET, IIS & Script 게시판의 36 페이지입니다.
게시물
1,257

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

영이

2005-08-04 1,089
1,256

re: EgoCube IE Analysis의 MSHTML 참조에 관하여... [1]

송원석

2005-08-04 3,091
1,255

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

영이

2005-08-04 1,086
1,254

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

송원석

2005-08-04 3,115
1,253

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

영이

2005-08-04 1,033
1,252

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

송원석

2005-08-04 3,122
1,251

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

영이

2005-08-08 1,148
1,250

re: EgoCube IE Analysis의 MSHTML 참조에 관하여...

송원석

2005-08-09 3,054
1,249

RSS 부탁 드립니다.

궁금이

2005-08-03 1,027
1,248

re: RSS 부탁 드립니다.

송원석

2005-08-03 2,914

HTML 입력필드에 값검증 기능을 내장시키자! HTC를 이용한 validator [1]

박노철

2005-07-29 6,344
1,246

DHTML behavior 와 HTC 를 이용한 SELECT 의 확장 [2]

박노철

2005-07-29 3,367
1,245

HTCs 에 대한 질문입니다. :)

감성우

2005-07-28 3,212
1,244

re: HTCs 에 대한 질문입니다. :)

송원석

2005-07-28 2,944
1,243

javascript 의 this 에 해당하는 것은 vbscript 에서 무엇인가요?

구나구나

2005-07-27 3,057
1,242

re: javascript 의 this 에 해당하는 것은 vbscript 에서 무엇인가요? [1]

송원석

2005-07-27 3,308
1,241

asp에서 오라클 프로시저 사용법 알고 싶습니다.

궁금이

2005-07-25 3,427
1,240

re: asp에서 오라클 프로시저 사용법 알고 싶습니다.

송원석

2005-07-26 3,390
1,239

쿠키에 대한 질문입니다. [2]

omar

2005-07-21 1,015
1,238

iE 아날라이즈에서요... [1]

정보문

2005-07-21 3,180
1,237

이미지태그의 src 부분만 추출하는 정규식 좀 알려주세요 [1]

강문성

2005-07-20 1,194
1,236

re: 이미지태그의 src 부분만 추출하는 정규식 좀 알려주세요

송원석

2005-07-21 3,889
1,235

정규식에서 And 형태의 연결은 어떻게 하는지요?

리피

2005-07-27 3,202
1,234

re: 정규식에서 And 형태의 연결은 어떻게 하는지요?

송원석

2005-07-27 3,260
1,233

iE 아날라이즈 소스의 일부분입니다.

정보문

2005-07-20 3,289