'prototype'에 해당되는 글 1건

  1. 2009.12.18 Prototype.js 기본예제
2009. 12. 18. 11:01

Prototype.js 기본예제





Prototype.js 기본예제

기본예제 | 레퍼런스 코드 크게 | 소스 보이기 | 예제 숨기기 | 실행 보이기

prototype.js는 무엇인가?

prototype.jsSam Stephenson에 의해 작성된 자바스크립트 라이브러리입니다. 이 라이브러리는 매우 훌륭하게 작성된 표준기반의 코드로, 웹2.0의 특성을 나타내는 풍부한 기능과 상호작용을 필요로 하는 웹페이지를 생성하는데 개발자의 부담을 한층 덜어줄 것입니다. prototype.js는 String, Array, Event 등과 같은 표준 자바스크립트 객체들에 대한 확장과 Ajax, Enumerable, Hash, Form, Element 등 다양한 신규 객체들을 제공하고 있습니다. 또한 자바스크립트 프로그래밍에서 흔하게 사용되어지는 기능들에 대한 유틸리티 함수도 제공합니다.

prototype.js는 현재 웹어플리케이션 프로토타입 개발용으로 많은 관심을 받고있는 프레임워크인 RubyOnRails에 통합되어 있으며, script.aculo.us, Rico 등과 같은 다양한 자바스크립트 프레임워크에서도 라이브러리 형태로 사용되어지고 있습니다. Ruby 프로그래밍 언어에 친숙한 개발자는 Ruby의 내장 클래스와 이 라이브러리에 의해 구현된 구문 사이에 많은 유사성이 있음을 알게 될 것입니다.

유틸리티 함수

prototype.js는 미리 정의된 다양한 객체와 유틸리티 함수를 가지고 있습니다. 아래 유틸리티 함수들은 자바스크립트 프로그래밍에서 반복적인 타이핑과 어구를 줄이는데 유용하게 쓰입니다.

$() 함수

$() 함수는 매우 빈번하게 사용되는 DOM의 document.getElementById() 함수에 대한 편리한 단축함수입니다. DOM 함수처럼, 이것은 인자로 던져진 id를 가진 해당 엘리먼트를 반환합니다. 하지만 DOM함수와는 달리, 이것은 여러개의 id를 사용할수 있는데, 이 경우에 $()는 요청된 엘리먼트들을 가진 Array 객체를 반환하게 됩니다. 이 함수의 다른 장점으로 id 문자열이나 엘리먼트객체 자체를 인자로 가질 수 있는데, 이것은 인자 형태를 가질수 있는 다른 함수를 생성할 때 매우 유용하게 사용되어 질 수 있습니다.

소스: base.js

예제

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Sample</title>
<script src="prototype.js" type="text/javascript"></script>
</head>
<body>

<script>
//<![CDATA[
function test1() {
	var d = $('myDiv1');
	alert(d.innerHTML);
}

function test2() {
	var divs = $('myDiv1','myDiv2');
	for(i = 0; i < divs.length; i++) {
		alert(divs[i].innerHTML);
	}
}
//]]>
</script>

<div id="myDiv1">
	<p>This is a paragraph</p>
</div>
<div id="myDiv2">
	<p>This is another paragraph</p>
</div>

<input type="button" value="Test1" onclick="test1();" />
<input type="button" value="Test2" onclick="test2();" />

</body>
</html>
실행

$F() 함수

$F() 함수는 또다른 유용한 단축함수로, 텍스트박스나 드랍다운 리스트와 같은 입력 컨트롤의 값을 반환합니다. 이 함수는 엘리먼트 id나 엘리먼트객체 자체를 인자로 가질수 있습니다.

소스: form.js

예제

<script>
function test3() {
	alert($F('userName'));
}
</script>

<input type="text" id="userName" value="Joe Doe" />
<input type="button" value="Test3" onclick="test3();" />
실행

$A() 함수

$A() 함수는 전달된 한 개의 인자를 배열로 변환합니다. Array 클래스에 대한 확장으로 이 함수는 열거가능한 목록이라면 그것을 쉽게 배열로 변환할 수 있습니다. 예를 들면, DOM 객체의 NodeLists를 효과적으로 배열로 바꾸는데 유용하게 쓰일 수 있습니다.

소스: array.js

예제

<script>
function showOptions() {
	var someNodeList = $('lstEmployees').getElementsByTagName('option');
	var nodes = $A(someNodeList);

	nodes.each(function(node) {
			alert(node.nodeName + ': ' + node.innerHTML);
		});
}
</script>

<select id="lstEmployees" size="5">
	<option value="5">Buchanan, Steven</option>
	<option value="8">Callahan, Laura</option>
	<option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Show the options" onclick="showOptions();" />
실행

$H() 함수

$H() 함수는 결합된 배열을 열거할수 있는 Hash 객체로 변환합니다.

소스: hash.js

예제

<script>
function testHash()	{
	var a = {
		first: 10,
		second: 20,
		third: 30
		};

	var h = $H(a);
	alert(h.toQueryString());
}
</script>

<input type="button" value="Test Hash" onclick="testHash();" />
실행

$R() 함수

$R() 함수는 new ObjectRange(lowerBound, upperBound, excludeBounds)과 동일한 단축함수입니다. 이 클래스의 완전한 설명을 보기 위해 ObjectRange 클래스 문서를 참고하십시요. each 메소드를 통해 반복(iterators)의 사용법을 보여주는 간단한 예제입니다. 더 많은 메소드는 Enumerable 클래스 문서에서 볼수 있을 것입니다.

소스: range.js

예제

<script>
function demoDollar_R(){
	var range = $R(10, 20, false);
	range.each(function(value, index){
		alert(value);
	});
}
</script>

<input type="button" value="Sample Count" onclick="demoDollar_R();" />
실행

Try.these() 함수

Try.these() 함수는 인자처럼 많은 수의 함수를 가지고 그것들을 순서대로 차례차례 호출하도록 해줍니다. 이것은 지정된 함수들 중 하나가 성공적인 함수호출의 결과를 반환할때까지 순차적으로 함수를 수행하게 됩니다. 예를 들면, 브라우저간에 서로 다른 객체를 검사햐여 사용해야 할 경우 등에 유용하게 사용될 수 있습니다.

소스: base.js

예제

<script>
function getValue(){
	var divA = document.getElementById('divA');
	return Try.these(
		function() { alert('function 1'); throw 'error'; },
		function() { alert('function 2'); return divA.undefined.property; },
		function() { alert('function 3'); return divA.innerHTML;},
		function() { alert('function 4'); return 'not reached';}
	);
}
</script>

<div id="divA">This is some text</div>

<input type="button" value="Test Try.these()" onclick="alert(getValue());" />
실행

Ajax 객체

위에서 언급된 유틸리티 함수들은 좋지만, 그것들은 대부분 고급 형태는 아닙니다. 대부분의 개발자은 자신만의 유사한 함수를 이미 가지고 있을수도 있습니다. 이러한 함수들은 단지 일부분에 해당되는 팁일뿐입니다.

웹2.0의 추세에 맞추어 많은 개발자들이 AJAX 기능에 관심을 가지고 있습니다. prototype.js은 AJAX 로직을 수행할 필요가 있을때 좀더 쉽게 사용하도록 도와주는 라이브러리 제공하고 있습니다. 이 라이브러리가 제공하고 있는 Ajax 객체는 AJAX 함수를 작성할 때 포함되는 트릭성격의 코드를 포장하고 단순화하기 위한 미리 정의된 객체입니다. 이 객체는 캡슐화된 AJAX 로직을 제공하는 많은 수의 클래스를 포함하고 있습니다. 그 클래스 중에 몇 개를 살펴봅니다.

Ajax.Request 클래스 사용하기

만약 개발자가 어떠한 헬퍼(helper) 라이브러리도 사용하지 않는다면, XMLHttpRequest 객체를 생성하기 위한 많은 코드를 작성할 것이고, 비동기적인 요청과 응답 처리를 반복적이고 기교을 요하는 코드를 매번 작성해야 합니다. 또한 다양한 버전의 브라우저를 지원하기 위한 부분도 처리를 해야 합니다.

이러한 AJAX 기능을 지원하기 위해, 라이브러리는 Ajax.Request 클래스를 정의하고 있습니다. 만약 특정 URL을 통해 XML 응답을 반환하는 서버 어플리케이션을 가지고 있다면, XML을 가져오기 위해 서버와 통신하는 것은 Ajax.Request 객체를 통해 쉽게 구현할 수 있습니다.

예제

<script>
function searchByAjax() {
	var usrkey = $F('usrkey');
	if (usrkey == '') return;
	var url = 'http://yourserver/app/stocks.php';
	var pars = 'usrkey=' + encodeURIComponent(usrkey.toUpperCase());
	
var myAjax = new Ajax.Request( url, { method: 'get', parameters: pars, onComplete: showResponse });
} function showResponse(originalRequest) { $('result').value = originalRequest.responseText; } </script> Search: <br /> <input type="text" id="usrkey" name="usrkey" value="" onkeyup="searchByAjax();" /> <br /> <br /> Result: <br /> <textarea id="result" cols="30" rows="10" ></textarea>
실행

Ajax.Request 객체의 생성자의 두번째 파라미터인 { method: 'get', parameters: pars, onComplete: showResponse }은 문자적 표기법(JSON이라고도 함)으로 나타낸 익명(anonymous) 객체입니다. 이것이 의미하는 것은 'get' 문자열을 갖는 method 프라퍼티와 HTTP 요청 쿼리문자열을 포함하는 parameters 프라퍼티, 그리고 함수 showResponse를 포함하는 onComplete 프라퍼티(메소드)를 가지는 객체를 전달한다는 것입니다. 이 파라미터는 AJAX 호출을 위한 옵션을 정의하고 있습니다. 예제에서 HTTP GET명령을 통해 첫번째 인자에서 URL을 호출하고, 변수 pars내 포함된 쿼리문자열을 전달합니다. Ajax.Request 객체는 서버측으로부터의 응답을 받은 후에 showResponse 함수를 호출할 것입니다. AJAX를 비동기적 또는 동기적으로 서버에 호출하려면, asynchronous 옵션을 true 또는 false로 주면 됩니다(디폴트 값은 true입니다). 이와 같은 이 객체내에서 정의하고 활성화시킬수 있는 다른 프라퍼티를 참조하려면 options 인자 객체를 참조하십시요.

XMLHttpRequest는 HTTP 호출을 하는 동안 진행과정을 알려주는데, Loading, Loaded, Interactive, 또는 Complete 4가지의 단계가 있습니다. Complete는 가장 공통적인 단계인데, 어드 단계에서든 Ajax.Request 객체가 사용자정의 함수를 호출할 수 있게 만들수 있습니다. 함수를 객체에게 알리기 위해, 예제의 onComplete처럼 요청 옵션내 onXXXXX로 명명된 프라퍼티(메소드)를 간단히 지정하면 됩니다. 더블어 결과를 처리하기 위해 사용될 수 있는 두개의 다른 흥미로운 옵션이 있는데, AJAX 호출이 에러없이 수행될 때 호출될 함수를 onSuccess 옵션에 명시하고, 서버에러가 발생할 때 호출될 함수는 onFailure 옵션에 지정할 수 있습니다.

prototype.js 1.4.0 버전에서는 새로운 형태의 이벤트 콜백 핸들링이 도입되었습니다. 만약 AJAX 호출이 발생하는데도 불구하고 특정 이벤트를 위해 수행되어야 하는 코드가 있다면, Ajax.Responders 객체를 사용할 수 있습니다. 에를 들면 AJAX 호출이 진행중이라는 시각적 표시를 보여줘야 하는 경우를 가정해 봅시다. 두개의 전역 이벤트 핸들러를 사용할 수 있는데, 하나는 처음 호출이 시작되었을때 아이콘을 보여주는 것이고, 다른 하나는 끝났을 때 아이콘을 숨기는 것입니다.

예제

<script>
function searchByAjax() {
	var usrkey = $F('usrkey');
	if (usrkey == '') return;
	var url = 'http://yourserver/app/stocks.php';
	var pars = 'sleep=1&usrkey=' + encodeURIComponent(usrkey.toUpperCase());
	
	var myAjax = new Ajax.Request(
		url, 
		{
			method: 'get', 
			parameters: pars, 
			onComplete: showResponse
		});		
}

function showResponse(originalRequest) {
	$('result').innerHTML = '<pre>'+ originalRequest.responseText  + '</pre>';
}

var myGlobalHandlers = { onCreate: function(){ Element.show('loading'); }, onComplete: function() { if(Ajax.activeRequestCount == 0){ Element.hide('loading'); } } };
Ajax.Responders.register(myGlobalHandlers); </script> Search: <br /> <input type="text" id="usrkey" name="usrkey" value="" onkeyup="searchByAjax();" /> <span id='loading'><img src='spinner.gif'> Loading...</span> <br /> <br /> Result: <div id="result"></div>
실행

Ajax.Updater 클래스 사용하기

만약 이미 작성된 HTML을 문서를 서버측으로부터 얻을 수 있고, 그 HTML을 가지고 페이지내의 특정 부분을 바꾸고 싶다면, Ajax.Updater 클래스를 사용하여 작업을 쉽게 할 수 있습니다. 이 클래스를 이용하여 어느 엘리먼트가 AJAX 호출로부터 반환된 HTML을 채우는지만 알려주면 됩니다. 예제를 보면 코드는 onComplete 함수와 생성자에 전달된 엘리먼트 id를 제외하고 이전 예제에 비해서 매우 간단합니다.

예제

<script>
function getHTML() {
	var url = 'http://yourserver/app/sample_html.php';
	var pars = 'someParameter=ABC';
	
var myAjax = new Ajax.Updater( 'placeholder', url, { method: 'get', parameters: pars });
} </script> <input type="button" value="Get Html" onclick="getHTML()" /> <p><div id="placeholder"></div></p>
실행

클라이언트에서 서버 에러들을 다루는 것이 어떻게 가능한지 보기 위해 코드를 조금 변경해 봅시다. 에러 보고를 위한 함수를 명시하고, onFailure 옵션을 추가합니다. 참고적으로 성공할 때와 에러가 발생할 경우 각각 업데이트될 엘리먼트(예제의 placeholder)를 구분하기 위해서, 첫번째 파라미터를 단순 엘리먼트 id에서 2개의 프로퍼티(success-모든것이 정상적일때 사용, failure-어떤것이 실패일때 사용)를 가지는 익명 객체로 변경할 수 있습니다. 이 경우에는 성공시와 오류시 각각 지정된 영역에 업데이트 될 것입니다. 다음 예제에서 failure 프라퍼티를 사용하지 않고, onFailure 옵션에서 reportError 함수를 사용하고 있습니다.

예제

<script>
function getHTML() {
	var url = 'http://yourserver/app/sample_html.php';
	var pars = 'someParameter=ABC';
	
	var myAjax = new Ajax.Updater(
		{ success: 'placeholder' },
		url, 
		{
			method: 'get', 
			parameters: pars,
			onFailure: reportError,
			evalScripts: true
		});
}

function reportError(request) { alert('Sorry. There was an error.'); }
</script> <input type="button" value="Get Html" onclick="getHTML()" /> <p><div id="placeholder"></div></p>
실행

만약 서버 로직이 HTML 마크업과 함께 자바스크립트 코드도 반환한다면, Ajax.Updater 객체는 이 자바스크립트 코드를 evaluation 할 수 있습니다. 자바스크립트 응답을 처리하기 위해서는 객체 생성자의 마지막 인자로 프라퍼티들의 목록에 evalScripts: true;를 간단히 추가하면 됩니다. 하지만 여기에 주의해야 할 점이 있습니다. 이러한 스크립트 블럭은 본 페이지의 스크립트에 추가되지는 않을 것입니다. 아래 예제는 서버로부터 얻어온 스크립트를 포함한 HTML 인데, 스크립트 블럭에서 sayHello1 이라는 함수를 생성하지 않을 것입니다. 함수를 정상적으로 생성시키기 위해서는 sayHello2 처럼 함수생성 코드를 변경할 필요가 있습니다. 추가적으로 함수 선언을 위해 var 키워드를 사용하면 스크립트 블럭에 지역화될 함수 객체를 생성하게 되므로, 함수 객체가 window 범위에서 작동하도록 var 키워드를 사용하지 않습니다.

예제

/* HTML from AJAX call */

<script>
	// sayHello1() won't work in AJAX call.
	function sayHello1() {
		alert('Hello 1');
	}

	// sayHello2() will work in AJAX call.
sayHello2 = function() { alert('Hello 2'); }
</script> <a href="#" onclick="sayHello1()">Function 1</a> <a href="#" onclick="sayHello2()">Function 2</a>
실행

Ajax.PeriodicalUpdater 클래스 사용하기

또 다른 유용한 클래스로, AJAX 호출을 일정한 주기로 반복해서 호출을 해야 할 경우에 유용하게 사용될 수 있는 Ajax.PeriodicalUpdater 클래스를 제공하고 있습니다.

예제

<script>
	function getNumber() {
		var url = 'http://yourserver/app/sample_number.php';
		var pars = 'someParameter=ABC';
		
		var myAjax = new Ajax.PeriodicalUpdater(
			'placeholder', 
			url, 
			{
				method: 'get', 
				parameters: pars,
				frequency: 2
			});
	}
</script>

<input type="button" value="Get Number" onclick="getNumber()" />

<p><div id="placeholder"></div></p>
실행

Enumerating

프로그래머에게 루프(loop)에 친숙합니다. 잘 알다시피, 배열을 생성하고, 같은 종류의 엘리먼트로 채우고, for, foreach, while, repeat 등과 같은 루프 제어문을 생성하고, 숫자로 된 인덱스를 통해 순차적으로 각각의 엘리먼트에 접근하고, 그 엘리먼트로 작업을 수행합니다. 언제나 코드에 배열을 가지고 루프내 배열을 사용할 것이라는 것을 의미합니다. 이러한 반복을 다루기 위해 좀더 많은 기능을 가진 배열 객체가 있다면 좋지 않겠습니까? 사실, 많은 프로그래밍 언어는 배열이나 유사한 구조(collection과 list와 같은)에서 이러한 기능을 제공하고 있습니다.

prototype.js는 반복 가능한 데이터를 다룰때 사용하도록 구현된 Enumerable 객체를 제공합니다. 이 라이브러리는 더 나아가 Enumerable의 모든 메소드로 Array 클래스를 확장합니다.

루프, 루비-스타일

표준 자바스크립트에서 배열의 엘리먼트를 순차적으로 표시할 경우, 예제의 showList1처럼 작성할 수 있습니다. prototype.js를 사용하면, 루비 언어와 유사한 구문을 사용하여 showList2와 같이 작성할 수 있습니다. each 메소드에 대한 인자처럼 전달되는 이 함수는 보았습니까? 이것을 반복자(iterator) 함수라 합니다.

예제

<script>
var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Meg'];

// using standard javascript
function showList1(){
for(i=0;i<simpsons.length;i++){ alert(simpsons[i]); }
} // using prototype.js function showList2(){
simpsons.each( function(familyMember){ alert(familyMember); });
} </script> <input type="button" value="List 1" onclick="showList1();" /> <input type="button" value="List 2" onclick="showList2();" />
실행

강력해진 배열

일반적으로 한 배열내의 모든 엘리먼트들은 같은 프라퍼티와 메소드를 가진 동일 종류입니다. 예제의 새로운 배열을 가지고 iterator 함수의 장점을 살펴봅시다.

예제

<script>
function findEmployeeById(emp_id){
	var listBox = $('lstEmployees')
	var options = listBox.getElementsByTagName('option');
	options = $A(options);
var opt = options.find( function(employee) { return (employee.value == emp_id); });
alert(opt.innerHTML); //displays the employee name } </script> <select id="lstEmployees" size="10" > <option value="5">Buchanan, Steven</option> <option value="8">Callahan, Laura</option> <option value="1">Davolio, Nancy</option> </select> <input type="button" value="Find Laura" onclick="findEmployeeById(8);" />
실행

다음 예제는 배열의 각 항목을 필터링하여 원하는 멤버만 가져오는 것입니다.

예제

<script>
function showHttpLinks(paragraph) {
	paragraph = $(paragraph);
	var links = $A(paragraph.getElementsByTagName('a'));
	//find links that start with 'http'
	var localLinks = links.findAll( function(link) {
		var start = link.href.substring(0,4);
		return start == 'http';
	});
	//now the link texts
	var texts = localLinks.pluck('innerHTML');
	//get them in a single string
	var result = texts.inspect();
	alert(result);
}
</script>

<p id="someText">
	This <a href="http://somesite.com">text</a> has 
	a <a href="ftp://someftp.com">lot</a> of 
	<a href="http://othersite.com">links</a>. Some are 
	<a href="http://wherever.com/page.html">http links</a>
	and others are <a href="ftp://otherftp.com">ftp links</a>.
</p>

<input type="button" value="Find Http Links" onclick="showHttpLinks('someText')" />
실행