jQuery : 폼 필터 및 조작 메서드(each 등)

필자의 잡담~

강좌가 좀 늦어졌네요.
실은 재미삼아 시작한 게시판 만들기에 뜻밖에 심취하는 바람에 그랬어요.
http://taeyo.net/jQueryBoard ^^;

강좌가 좀 늦어졌네요. 그냥 데모 수준으로 가볍게 만들어 보려 한 게시판에 의외로 몰입하게 되는 바람에 한 10일 정도 jQueryBoard를 만들게 되어서 그리 되었습니다. http://taeyo.net/jQueryBoard 가 그것인데요. 아직 손을 봐야 할 것들이 남아있긴 합니다만, 그런대로 기본 기능들은 다 갖춘 것 같습니다. 습작이니 너무 예리한 눈으로 보진 마시고요. 그냥 이렇게 jQuery를 적용할 수도 있다는 수준으로 봐주시면 감사하겠습니다. 그러면, 이제 강좌로 들어가 볼까요?

이번 강좌는 셀렉터의 마지막 강좌로 폼과 관련된 셀렉터에 대해서 알아볼까 합니다. 사실상, 웹 페이지에서 서버로 데이터를 전송하려면 입력 UI로 다양한 폼 컨트롤들을 사용할 수 밖에 없는데요. 이는 Ajax 기반의 웹 페이지라 해도 다를 것이 없습니다. 해서, 폼 관련 요소들은 다양한 HTML 요소들 중 상당히 중요한 요소라 할 수 있고, 그렇기에, 이와 직접적으로 연관된 폼 필터들도 마찬가지로 매우 중요하다고 우겨볼 수 있을 것 같습니다. 하하. 하지만, 정말로 그럴까요?

이미 이전 강좌를 통해서 필터의 역할이나 사용방법은 알고 계실 테니까요. 폼 필터들에는 어떤 것들이 있는지 일단 정리한 것을 먼저 보고 이야기를 계속해 나가보겠습니다.

:input 모든 input, textarea, select, button요소들과 일치됩니다
:text text 타입의 모든 input 요소들과 일치됩니다.
:password password타입의 모든 input 요소들과 일치됩니다.
:radio radio 타입의 모든 input 요소들과 일치됩니다.
:checkbox checkbox 타입의 모든 input 요소들과 일치됩니다.
:submit submit 타입의 모든 input 요소들과 일치됩니다.
:image image 타입의 모든 input 요소들과 일치됩니다.
:reset reset 타입의 모든 input 요소들과 일치됩니다.
:button 모든 button 요소들 및 button 타입의 input 요소들과 일치됩니다.
:file file 타입의 모든 input 요소들과 일치됩니다.
:hidden hidden 상태인 모든 요소들과 일치됩니다.

이미 필터에 익숙한 여러분이기에 보면서 이해가 되실텐데요. 보이는 것처럼 모든 입력 컨트롤을 선택하고 싶다면 $(":input") 라고 작성하면 되고, 체크박스만 선택하고 싶다면 $(":checkbox")라고 jQuery를 작성하면 됩니다. 히든 필드는 $(":hidden") 이라고 작성해서 선택할 수 있고요. 호오~ 깔끔하네요.

하지만, 생각 외로 이 폼 필터들을 자주 사용할 일은 없는 편인데요(물론, 사용하기 나름이겠지만 저의 경우는 그다지 사용할 일이 많지 않았습니다). 이는 일반적으로 $("input#UserID")이나 $("input.required") 와 같이 특정 목적을 위한 입력 컨트롤들을 콕 찝어서 접근하는 방식을 더 선호하기 때문이 아닐까 합니다. 사실, 모든 입력 컨트롤을 선택한다거나, 모든 라디오 버튼을 선택한다거나 할 일은 그리 많지 않죠.

반면, 체크박스 중 체크된 것들을 모두 알아온다던가, 셀렉트 컨트롤들 중에서 선택된 것들을 알아낸다던가 하는 작업은 상대적으로 자주 요구되는 일 중에 하나입니다. 예를 들어, 사용자가 체크한 값들이나 선택한 값들을 화면에 출력해주는 일을 생각해 볼 수 있습니다. 다음의 코드를 한번 볼까요?

var sports $("input:checkbox");
for 
(var 0i < sports.lengthi++) {
  
if (sports[i].checked == true) {
    
//두 썸띵!
  
}
}

이는 체크박스 필터를 사용해서, 우선 현재 페이지에 있는 모든 체크박스들을 얻어온 뒤, 전체 요소들만큼 for 루프문을 반복하면서 해당 체크박스가 checked 상태인지를 검사하고, 만일, 체크가 된 상태라면 "두 썸띵"을 하는 코드입니다. ^^;

앞서서 설명을 드렸었는지 기억이 가물해서 언급하자면 var sports = $("input:checkbox"); 와 같은 셀렉터 혹은 셀렉터 필터에 의해 반환하는 개체는 Html 요소들의 배열입니다. 즉, sports 라는 변수는 Html 요소들의 배열이지, jQuery 개체의 배열이 아니라는 것이죠.

상기 코드는 현재 페이지에 존재하는 모든 체크박스들을 일일히 확인해가면서 선택된 것을 찾아내는 코드입니다만, jQuery의 필터 중에는 이와 같은 작업을 보다 쉽게 해주는 필터들도 있습니다. 바로 다음과 같은 것들이죠.

:enabled 현재 enable 상태인 모든 요소와 일치됩니다.
:disabled 현재 disable 상태인 모든 요소와 일치됩니다.
:checked 체크된 모든 요소들과 일치됩니다.
:selected 선택된 모든 요소들과 일치됩니다.

예를 들면, :checked 와 같은 필터는 폼에서 체크된 모든 요소들을 선택하게 됩니다. 즉, 이 필터를 사용하면 모든 체크박스를 일일히 확인할 필요없이, 체크가 된 체크박스들만을 얻어올 수 있다는 것이죠. 해서, 이 필터를 사용하면 이전의 체크박스 확인 코드가 다음과 같이 좀 더 간단해 질 수 있습니다.

var sports $("input:checked");
var 
result "";
for 
(var 0i < sports.lengthi++) {
  
//두 썸띵!
}

전과 비교했을 때, if (sports[i].checked == true){ .. } 와 같은 코드를 사용할 필요가 없게 된 것이죠. 이미 필터를 통해서 체크된 요소들만 가져와진 상태니까요 ^^.

자. 그럼 간단한 예제를 통해서 확인을 해볼까요?

<html>
<head>
    
<title></title>
<script src="js/jquery-1.3.2.min.js" type="text/javascript"></script>
    
<script type="text/javascript">
        $(
document).ready(function() {

            $(
"#DoIt").click(function() {
                
var sports $("input:checked");
                var 
result "";
                for 
(var 0i < sports.lengthi++) {
                        result +
$(sports[i]).next().text() + ",";
                
}
                $(
"#result").text(result);
            
});
});
    </
script>
</head>
<body>
    
<p>
        스포츠 :
<input id="c1" type="checkbox" /><label for="c1">농구</label>
        
<input id="c2" type="checkbox" /><label for="c2">배구</label>
        
<input id="c3" type="checkbox" /><label for="c3">축구</label>
        
<input id="c4" type="checkbox" /><label for="c4">야구</label>
    
</p>
<p>
        
<input id="DoIt" type="button" value="선택" />
</
p>
    
<p>
        당신이 선택하신 스포츠는 
<span id="result"></span> 입니다.
    
</p>
</body>
</html>

우선, HTML 코드들부터 살펴보도록 하세요. 화면에는 4개의 체크박스가 존재하고 있고, 1개의 버튼과 1개의 출력용 span 구역이 정의되어 있습니다. 그리고, 구현하려는 기능은 사용자가 몇몇 체크박스에 체크를 하고, "선택" 버튼을 클릭하면, span 영역에 그 선택된 값들을 출력하려는 것입니다. 매우 간단한 예제이긴 하죠?

하지만, 스크립트 구역의 소스는 생각보다 설명을 드릴 것이 조금 많네요. 하지만, 재미있는 내용이니 기쁘게 설명해 보도록 할게요. 우선 이벤트에 관한 것부터 설명 드리겠습니다. 사실, 이벤트에 관한 부분은 추후에 설명드릴 예정인 부분이지만, 예제에서 등장을 했으니 조금쯤은 설명을 드리고 가야 할 듯 합니다.

우선, $(document).ready()라는 이벤트 메서드를 보세요. 이것! 기억하시죠? 그렇습니다. 이는 jQuery가 제공하는 페이지 로드 이벤트 함수(마치, window.load와 유사한)라고 제가 2번째 강좌에서 간략하게 설명을 드렸었습니다. 그리고, 그 메서드 인자로는 함수를 작성한다고 말씀을 드렸었죠. 즉, 다음과 같이 말입니다.

$(document).ready(pageLoad);
function 
pageLoad()
{
   
//.. 페이지 로드시에 할 일
}

하지만, 일반적으로는 저렇게 굳이 함수를 분리해서 작성할 이유가 없어서, pageLoad라는 함수를 별도로 작성하지 않고, 그냥 다음과 같이 익명 함수로 작성하는 편입니다.

$(document).ready(
   
function()
   {
      
//.. 페이지 로드시에 할 일
   
}
)
;

그리고, 대부분은 가독성을 위해서 다음과 같이 붙여서 쓰곤 하는 편이죠.

$(document).ready(function(){
    
//.. 페이지 로드시에 할 일
});

이렇게 말이죠. 해서, 예제에서의 코드도 이러한 코드 내부에 작성된 것을 보실 수 있습니다. 혹시라도, 이전에 이 코드가 왜 이렇게 작성된 것인지 잘 이해가 안되셨던 분들은 이제는 좀 감을 잡으셨을 것이라 생각합니다(그리고, 이와 같은 류의 코드가 jQuery에서는 대단히 자주 등장합니다. 진짜로 100초 안에 다시 등장할 겁니다).

그 이후 등장하는 소스를 계속해서 보시면, 페이지가 준비가 되는대로(즉, ready() 함수 안에서) 다음과 같은 코드를 사용해서 버튼에 click 이벤트를 걸어주는 것을 볼 수 있습니다.

$("#DoIt").click( someFunction );

이는 #DoIt이라는 개체에게 동적으로 클릭 이벤트를 걸어주는 jQuery 코드입니다. 사실, 이는 document.getElementById("DoIt").click = someFunction; 이라는 자바스크립트 함수와 같은 것이라 볼 수 있죠. 하지만, 코드가 간결하고, 메서드 체인을 통해서 여러 작업을 이어서 지정할 수 있다는 장점이 있습니다. 예를 들면, 다음과 같이 말입니다.

$("#DoIt").click( someFunction ).mouseover( otherFunction ).css("color""red");

즉, 이와 같은 식으로 작성해서, 클릭 이벤트와 마우스 오버 이벤트를 걸어줌과 동시에 color 스타일 값도 red로 변경하는 작업을 한번에 할 수 있다는 것이죠.

사실, 오리지날 jQuery에서의 이벤트 설정 작업은 상기와 같은 코드를 사용하는 것이 아니라 다음과 같이 bind 라는 메서드를 통해서 설정해야 합니다.

$("#DoIt").bind("click"someFunction );

하지만, jQuery는 자주 사용하는 몇몇 이벤트(몇몇이라고 하기엔 꽤 많지만)에 대해서는 click과 같이 단축 메서드를 작성해 놓았기에, bind 대신 click과 같이 직관적인 메서드를 사용해서도 이벤트 핸들러를 걸 수가 있는 것입니다. 이러한 부분에 대한 구체적인 이야기는 추후에 다시 하도록 하고요(엉? 근데, 거의 다 이야기했는데..). 다시 예제에 집중하도록 하죠.

해서, 소스를 보시면, DoIt이라는 아이디를 갖는 버튼에게 click 이벤트를 지정하고 있는데요. click() 이라는 메서드도 인자로는 함수(클릭 시에 해야할 작업을 작성하는 함수)를 지정할 수 있게 되어 있습니다. 해서, ready() 메서드에서 했던 것처럼 이도 별도의 함수로 작성하기 보다는 그냥 익명함수로 작성하곤 합니다. 다음과 같이 말이죠(제가 100초 안에 다시 등장할 거라고 말했죠!).

$("#DoIt2").click(function() {
  
//.. 클릭 시 해야할 작업
});

click 메서드의 인자로 지정된 익명함수 내에서는 원래의 개체에 대한 컨텍스트가 유지되기 때문에, 함수 내에서 this라는 키워드를 사용할 수 있으며, 이 this는 Doit이라는 html 요소를 의미합니다. 만일, jQuery 개체로 다시 감싸고 싶다면, 함수 내부에서 $(this)와 같이 작성하시면 되지요.

자. 그럼 이제 클릭 이벤트 핸들러 안에다 어떤 코드를 작성했는지 한번 살펴보도록 하겠습니다. 단, 그 전에 이제부터 작성하는 코드들은 "버튼이 클릭되는 경우"에만 수행된다는 것을 기억하세요. 전체적인 코드 작성이 $(document).ready() 메서드 안에서 작성되고 있기에, 마치 모든 코드가 페이지 로드 시에 동작할 것이라고 오해하실 수 있어서 강조드리는데요. 페이지가 로드될 경우 수행되는 것은 이러한 함수가 click 이벤트에 연결되는 것까지이고요. 실제 click 메서드 안에 작성된 익명 함수(아래의 코드)는 사용자가 실제로 버튼을 클릭하는 경우에만 호출되고, 수행됩니다.

var sports $("input:checked");
var 
result "";
for 
(var 0i < sports.lengthi++) {
   result +
$(sports[i]).next().text() + ",";
}
$(
"#result").text(result);

자. 이 코드는 앞서 설명한 :checked 필터를 사용하여 체크가 된 체크박스들을 얻어오고 있고요. 그를 sports라는 변수에 담고 있습니다. 결국, sports라는 변수는 셀렉터에 의해 필터링된 html 요소들의 배열이라고 볼 수 있죠. 그들을 루프를 돌면서, 각 체크박스의 다음에 있는 html 요소로 접근한 뒤(next() 메서드), 그 요소의 텍스트값을 얻어와서 문자열로 구성하고 있습니다.

여기서 우리가 추가로 배우게 되는 2개의 jQuery 메서드가 있는데요. 하나는 next() 이고, 다른 하나는 text() 입니다.

next()란 메서드는 현재의 개체 요소와 형제 수준인 요소 중 바로 다음에 나오는 개체를 얻어오는 메서드입니다. 이름에서 느껴지듯이 딱 그런 역할을 하는 메서드이죠. 예제를 기준으로 설명드리면, 현재 예제는 각각의 체크박스 바로 옆에 <label> 개체들이 놓여있는 것을 보실 수 있을 겁니다. 고로, $(sports[i]).next() 라는 표현은 현재의 체크박스 바로 옆에 있는 label 개체를 찾아가게 되는 것이죠. 단, 루프 안에서 sports[i].next() 라고 코드를 작성한 것이 아니라, $(sports[i]).next()라고 작성한 것에 주목하셔야 하는데요. sports라는 배열에 들어있는 개체들은 jQuery 개체가 아닌 html 요소일 수 있기 때문입니다. 해서, 이를 $()를 사용하여 확실하게 jQuery 개체로 포장해야만 합니다. jQuery 개체가 아니면 next() 메서드를 사용할 수 없으니까요.

text() 메서드는 해당 개체가 가지고 있는 컨텐트를 텍스트로 반환하는 메서드입니다. 이와 유사한 메서드로는 html()이 있는데요. 이는 개체가 포함하고 있는 html 컨텐트를 반환하는 메서드입니다. 이 메서드들은 인자를 사용하지 않으면 값을 가져오는 역할을 하지만, 인자로 값을 지정하면 그 값으로 원래의 값을 바꾸는 역할을 합니다. text() 메서드의 재미있는 점은 개체의 컨텐트가 html 요소들을 포함하고 있다고 해도, 다 무시하고 텍스트만을 반환한다는 점입니다. 즉, <span><b>taeyo</b></span> 와 같은 span 개체가 있을 때, 이 span 개체에 대해서 text()를 수행하면, 반환값은 내부 html을 제외한 "taeyo"가 되고요. html() 메서드를 사용하면 <b>taeyo</b>를 반환한다는 것이죠.

그리하여, 예제에서의 result += $(sports[i]).next().text() + ","; 라는 구문은 현재 루프 안에서, 체크박스 개체의 바로 옆에 있는 개체(label)의 텍스트를 읽어와서 그 텍스트에 ","라는 문자를 더한 다음, 이를 result 라는 변수에 덧붙이는 역할을 하게 됩니다. 즉, 사용자가 체크한 체크박스의 명칭을 차곡차곡 문자열에 더하는 것이죠.

그 후, 예제는 그렇게 만들어진 문자열 result를 span 요소에 출력하는 것을 볼 수 있습니다. 텍스트 설정을 위해서 text() 메서드를 사용하고 있는 것도 잊지말고 째려봐 주세요. 해서, 결과 화면은 다음과 같죠.

이야기를 진행하다 보니, 원래의 폼 관련 셀렉터에 대한 설명보다는 jQuery 개체가 제공하는 트래버싱(traversing, 탐색) 메서드나 조작(Manipulation) 메서드에 대해 설명을 하게 되었네요. 하긴, 이 이야기가 다음 강좌의 주제이니 지금 이야기하는 것이 부드럽긴 하지만요(그리고, 사실 폼 관련 셀렉터에 대해서는 이번 강좌 초반에 표로 설명한 정도면 충분하다고 봅니다요).

그렇다면, 이야기를 꺼낸 김에 루프를 좀 더 편하게 작성할 수 있는 jQuery의 기본 제공 메서드인 each() 메서드에 대해서도 설명을 좀 드리고 넘어갈까 합니다.

each() 메서드는 jQuery 개체가 제공하는 메서드로서, 모든 일치된 개체들에 대해서 순차적으로 특정 함수를 수행할 수 있게 해주는 메서드입니다. 문법은 다음과 같아요.

jQuery(selector).each( function );

each() 메서드 안에 인자로 사용하는 것은 역시나 또 함수입니다(jQuery는 거의 인자로 함수를 사용합니다). 그리고, 역시나 주로 익명 함수를 사용하게 되죠. 해서, 일반적으로 다음과 같은 구문을 가지게 됩니다.

jQuery(selector).each( function(i) {
    //.. 루프 안에서 할 일을 작성
});

익명 함수의 i 라는 인자는 0부터 시작하는 인덱스 값이 넘어옵니다. 마치 for 문에서의 i와 동일하다고 보시면 됩니다만, 필요치 않다면, 인자를 지정하지 않으셔도 됩니다.

each() 메서드는 상당히 자주 사용하게 되는 메서드입니다. 제가 샘플로 만들어 놓은 jQueryBoard에서도 이는 예외가 아닙니다. 이는 셀렉터에 의해 추출된 개체들에 대해서 각각 지정한 함수를 수행하게 합니다. 해서, 루프를 사용할 때와 마찬가지로 각 요소에 대해 어떤 작업을 하고 싶다면 바로 그 함수 안에다가 수행할 내용을 작성하면 됩니다. 이는 for 루프문을 대체할 수 있을 뿐만 아니라, 상당히 효과적이어서 한번 사용하기 시작하면 다시는 for 문을 거들떠 보지도 않게 만드는 마력이 있더군요. 그러면, 이번 예제의 for 루프문을 each() 메서드를 사용해서 바꾸어 볼까요?

var result "";
$("input:checked").each(function(i) {
   result +
$(this).next().text() + ",";
});
$("#result").text(result);

만일, 2개의 체크박스가 체크되었다면, each() 안의 함수는 그 2개의 체크박스에 대해 각각 호출될 것이고, 구문 내 this는 각각의 호출 시에 그에 해당하는 체크박스가 될 것입니다.

어떻습니까? 기존의 for 문으로 작성한 것보다 훨씬 간단하고 명료합니다. 그리고, 결과는 기존과 아주 확실히 동일하죠. 게다가, each() 메서드를 사용하게 되면, 여전히 jQuery의 장점 중 하나인 메서드 체인도 사용이 가능합니다. 예를 들어, 다음 구문을 보시죠.

$("#DoIt").click(function() {
   
var result "";
   
$("input:checked")
      .each(
function(i) {
         result +
$(this).next().text() + ",";
       
})
      .css(
"background""yellow");

   $(
"#result").text(result);
});

each() 메서드에 이어서 css() 메서드를 체인으로 연결해서 작성하고 있습니다. 이렇게 작성하면, 체크된 모든 체크박스에 대해서 each() 메서드를 사용한 기존 작업을 수행할 뿐 아니라, 배경색을 노란색으로 지정하는 것까지 수행하게 됩니다. 해서, 이렇게 바꿔 작성된 예제는 다음과 같은 결과를 보이게 됩니다.

호~ 쓸만하죠?

어찌하다보니, 이번 강좌에는 다음 번에 다루어야 할 내용까지 들어가 버리게 된 결과가 되었지만, 그래도 독자들은 단순히 셀렉터만을 다루는 것보다는 재미있지 않았을까 생각해 봅니다. 어찌됐건, 이로서 셀렉터에 대한 내용은 거의 모두 다룬 것 같네요.

다음 강좌부터는 UI를 조작하는 메서드들 즉, Manipulation 관련 메서드들을 다룰 예정에 있습니다. 그리고, 그를 통해서 여러분은 동적으로 UI를 보다 쉽게 조정할 수 있게 될 것이라 생각합니다.

그럼 다음 강좌에서 뵈어연~~~ jQueryBoard도 많은 테스트와 조언을 부탁드립니다.


authored by Taeyo

Posted by 바람이불면
,