IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  웹 개발 | XML  >

Ajax로 사이트 전면 개편, Part 4: 기존 사이트를 jQuery와 Ajax forms를 사용하여 개선하기

오픈 소스 도구들을 사용하여 여러 단계의 절차를 단일 화면 인터페이스로 간소화하자

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Brian J. Dillard, VP, Ajax 개발, Pathfinder Development

옮긴이: 장동수 dwkorea@kr.ibm.com

2008 년 9 월 30 일

Ajax 기술이 대규모 상업용 웹 응용 프로그램의 외관을 바꾸고 있습니다. 그러나 대다수의 소규모 웹 사이트는 모든 사용자 인터페이스를 하룻밤 사이에 재구축할 만한 자원이 없습니다. 새로운 기능은 실세계 인터페이스 문제를 해결하고 사용자 경험을 향상시켜야 가치를 증명할 수 있습니다. 이 연재 기사는 오픈 소스 클라이언트측 라이브러리를 사용하여 사용자 인터페이스를 점진적으로 현대화하는 방법을 설명합니다. 이번 회에는 일련의 폼들로 이루어진 여러 단계의 구매 절차를 단일 화면 인터페이스로 바꿔 보겠습니다. 점진적 개선(progressive enhancement)의 원칙을 따르면, 모든 웹 브라우저에서 사이트에 접근할 수 있습니다.

기사 소개

이 기사는 웹 1.0 쇼핑 사이트를 Ajax 기술을 사용하여 단계적으로 개선한다. 개선 전후의 예제 응용 프로그램 소스를 받을 수 있고, 필자의 웹 서버에서 두 버전이 실제로 동작하는 모습을 확인할 수 있다. Ajax 기술과 모범 사례 외에도, Ajax가 점진적 개선의 원칙과 사용성, 사용자 경험 디자인(UxD: user experience design)을 통해 사용자 경험을 향상시키는 방법을 알게 될 것이다.

이 기사는 HTML과 CSS에 익숙하고, 자바스크립트와 Ajax 프로그래밍에 대해 기본적인 지식이 있다는 전제 하에서 썼다. 예제 응용 프로그램은 클라이언트측 코드만 사용하여 구축했지만, 사용된 기술은 어떤 서버측 프레임워크에도 적용할 수 있다. 예제 사이트를 실행하려면, localhost에서 동작하는 기본적인 웹 서버가 필요하지만, 소스 코드를 따라가면서 필자의 웹 서버에서 실행되는 예제 사이트를 통해 결과를 확인해도 된다.




위로


Part 1~3 복습

연재의 Part 1Part 2에서는 Customize Me Now라는 예제 응용 프로그램을 통해 웹 1.0 버전을 Ajax를 사용한 웹 2.0 버전으로 개선하는 작업을 시작하면서, 비즈니스와 사용성 관점에서 그 이유를 설명했다. jQuery 자바스크립트 프레임워크와 몇 가지 플러그인을 포함한 오픈 소스 도구를 설치하는 방법도 알아보았다. 이 라이브러리들을 사용하여 Customize Me Now의 팝업과 사이트를 벗어나는 링크, 내비게이션 상의 샛길을 모달 대화상자, 툴팁, 라이트박스로 대체함으로써 사용자 흐름을 정리했다. Part 3에서도 추가적인 개선을 수행했다. 긴 내용을 Ajax/DHTML 탭으로 바꿨으며, 구닥다리 사진 페이지를 회전식 슬라이드쇼로 바꿨다.

Part 4의 목표

이번 회에는 다중 페이지 폼을 Ajax 탭으로 바꿔 복잡한 절차를 간소화해 보자. 예제 쇼핑 사이트의 구매 절차를 개선할 것이다. 사용자 입장에서 Ajax를 사용하지 않은 다중 페이지 폼은 지루하고, 고통스럽고, 당황스러울 수 있다. Ajax로 전면 개편을 하고 나면, 아무리 복잡한 구매 절차도 사용자 인터페이스를 조직화하는 것만 조심하면 인간적이고 친숙하게 만들 수 있다. 이 기술들은 쇼핑몰 사이트에만 적용할 수 있는 것이 아니다. 사용자가 여러 단계의 절차를 끝마치기 위해 서로 관련있는 일련의 폼들을 채워야 하는 곳이라면 어디라도 똑같은 원리를 적용할 수 있다.

이 기사의 개념을 이해하려면, Ajax 적용 전의 예제 사이트를 조금 고친 Customize Me Now 1.2를 참조하라(다운로드). 1.2를 조금식 고쳐나가면서, Customize Me Now 2.2를 만들어 보자.

쇼핑몰 구매 페이지: 웹 1.0 버전

온라인 쇼핑을 좋아하는 사용자들조차도 종종 구매 절차를 지겨워한다. 문제는 셀 수 없이 많다.

  • 구매에 얼마나 많은 단계를 거쳐야 하는지 명확하지 않다.
  • 각 단계가 얼마나 오래 걸릴지 명확하지 않다.
  • 특정한 질문에 대한 사용자의 응답에 따라, 응용 프로그램의 무관한 부분으로 우회하게 된다. 배송 방법을 선택하거나, 할인 쿠폰을 적용하거나, 심지어 로그인조차도 단순해 보이는 구매 절차를 생각보다 오래 걸리게 만든다.
  • 사이트 개발자가 구매 절차에서 보안이 요구되는 부분을 주의깊게 처리하지 않았다면, 애매한 보안 경고가 사용자들을 화나게 만들 수 있다.
  • 서투르고 일관성 없는 에러 메시지들은 사용자로 하여금 언제 에러가 발생했는지 알기 어렵게 만든다.
  • 서투르게 만들어진 폼 검증 루틴들은 짜증스러운 무한 반복을 유발한다. 원인은 서버로 갔다올 때마다 신용 카드 번호를 지워 버려서 다시 입력하게 만드는 것부터 선택한 체크 박스들을 다시 체크하게 만드는 것까지 다양하다.

쇼핑몰 구매 페이지: 웹 2.0 버전

시간과 개발 비용을 들여 기존 사이트를 Ajax로 개선하는 가장 큰 목적 중 하나는 사용자 경험을 향상시키는 것이다. Ajax를 사용하더라도 구매 절차에서 사용자가 싫어하는 모든 것을 고칠 수는 없지만, 적어도 세 가지 부분에서 도움은 된다.

  • 구매를 끝내기 위해 몇 단계가 필요한지 명확하다.
  • 각 단계 간 전환이 더 빠르다.
  • 사용자가 로그인하고, 할인 쿠폰을 적용하고, "행복한 경로"를 벗어나 우회해야 할 때도 단순함과 일관성을 유지할 수 있다.

예제 응용 프로그램: Customize Me Now 1.2

웹 브라우저에서 Customize Me Now 1.2를 돌려보면, 대부분의 사이트가 그렇듯이 구매 절차가 혼란스럽다는 것을 알 수 있다. 빵부스러기 내비게이션(breadcrumb navigation, 역주: 동화 헨젤과 그레텔에서 유래한 용어로, 보통 웹 페이지의 헤더 아래에 가로로 나열된 링크들을 말한다)을 통해 구매가 5단계로 이루어진다는 것을 알 수 있다.

  1. 개인 정보
  2. 배송 상세 정보
  3. 지불 상세 정보
  4. 주문 검토
  5. 결과 확인

그러나 실제로는 훨씬 더 복잡하다. 사용자는 1단계에 들어가기 전에 손님으로 구매할 것인지, 로그인하고 구매할 것인지를 결정해야 한다. 전자를 선택했다면, 바로 1단계로 들어가 이름과 연락처를 입력하면 된다. 후자를 선택했다면, 로그인 화면으로 가서 아이디과 비밀번호를 입력하고 1단계로 돌아와 이전에 입력한 연락처 정보를 확인해야 한다.

1단계를 마치고 나면 절차가 꽤 명확하다. 그러나 4단계 주문 검토에 오면 또 다른 잠재적인 우회로 - 이 예에서는 할인 구폰 적용 페이지 - 를 만나게 된다.

우회로를 포함하여, 모든 절차를 거치는 동안, 사용자에게 지금 어떤 단계에 있는지를 알려주는 것은 앞에서 언급했던 빵부스러기 내비게이션 뿐이다. 언제든지 클릭할 수 있는 것은 이전에 끝 마친 빵부스러기 항목들뿐이다. 다음 단계로 건너 뛸 방법은 없고, 오직 뒤로만 갈 수 있다. 그림 1에서 빵부스러기 흔적의 동작을 볼 수 있다.


그림 1. Customize Me Now 1.2 빵부스러기 흔적
그림 1. Customize Me Now 1.2 빵부스러기 흔적

빵부스러기 내비게이션은 어떤 측면에서는 유용하지만, 세로선으로 구분된(pipe-delimited) 목록 스타일 덕분에 사용자 눈에 잘 띄지 않는다. 또한 사용자가 마주치게 될 우회로를 정확하게 반영하지 못한다. 로그인은 1단계의 하위 단계고, 할인 쿠폰 적용은 4단계의 하위 단계지만, 두 우회로 모두 원래 있던 단계로 돌아가는 데 서버와의 통신이 필요하고, 서버와의 통신은 새 페이지를 열기 때문에 전체 절차를 오래 걸리게 만들고 사용자를 혼란에 빠트린다.

Customize Me Now의 모든 이전 버전이 그랬듯이, 헤더와 푸터의 내비게이션은 실제 서비스에서는 존재하지 않는 것이며, 이 기사를 읽으면서 예제의 여러 페이지를 신속하게 이동할 수 있도록 만든 것이다. Customize Me Now 1.2 예제 코드와 실제 서비스되는 쇼핑몰 응용 프로그램 간에는 또 다른 차이점들이 있다. 예제에서는 SSL(Secure Socket Layer)을 사용하지 않는다. HTTP(Hypertext Transfer Protocol) 연결의 양끝 어디에서도 유효성을 검증하지 않는다. 마지막으로, 구매의 각 단계는 정적이다. 예를 들어, 사용자가 배송 주소와 대금 청구 주소가 같다는 체크박스를 선택한다고 해도 대금 청구 주소는 채워지지 않는다. 실제 쇼핑몰 사이트라면 서버측 코드에서 처리해야 할 것이다. 이 글의 목적에 따라, 클라이언트 코드는 실제 사이트에서 발생할 수 있는 추가적인 귀찮은 문제들을 알려줄 뿐이다.

구매 절차 개선하기: 1단계

이제 Customize Me Now 2.2를 만들 준비가 됐다. 구매 경로를 단일 화면 인터페이스로 바꾸면, 서버와 통신하면서 발생하는 지연을 줄이고 단계 사이를 전환할 때 혼란을 줄일 수 있다. 개선을 끝내면, 로그인하고 할인 쿠폰을 적용하는 화면들이 혼란스러운 우회로가 아니라 전체 절차의 직관적인 일부처럼 보일 것이다.

자바스크립트 라이브러리 연결하기

이번 회에는 이전 연재에서도 사용했던 유명한 Ajax 라이브러리인 jQuery와 친숙한 두 개의 플러그인을 사용한다.

  • jQuery UI Tabs: Part 3에 사용했는데, 순서없는 목록을 탭 인터페이스로 변형시키고 각 탭을 DOM(Document Object Model)에 정적으로 포함된 내용이나 Ajax로 가져온 동적인 내용로 채운다. 이번에는 분리된 HTML 파일 일곱 개를 단일 화면 인터페이스로 바꾸는 데 사용한다. 지난 연재에서 이 플러그인을 사용하면서 둥근 모서리 모양을 꾸미기 위해 배경 이미지를 고쳤는데, 이번에도 고친 이미지를 그대로 사용한다.
  • jQuery Form: Part 1과 Part 2에 사용했는데, Ajax를 통해 폼을 전송하고 결과를 처리하는 다양한 방법을 제공한다. 이번에는 단일 화면 구매 절차의 각 단계 간의 흐름을 제어하기 위해 사용한다.

이번 전면 개편에 필요한 모든 작업은 checkout.html 페이지에서 이루어진다. jQuery와 플러그인들을 위한 자바스크립트와 CSS들을 다운로드하고, HTML 파일 헤더에 이것들을 참조하도록 연결해야 한다(Listing 1).


Listing 1. 자바스크립트 라이브러리 연결하기
                
<!--jquery assets-->
<script type="text/javascript"
	src="../js/jquery-1.2.3.min.js"></script>
<script type="text/javascript"
	src="../js/jquery.form.js"></script>

<!--jquery.ui.tabs assets-->
<script type="text/javascript"
	src="../ui.tabs/ui.tabs.pack.js"></script>
<link rel="stylesheet"
	href="../ui.tabs/ui.tabs.css" type="text/css"
	media="print, projection, screen">

HTML 조각 만들기

연재의 Part 3에서 했던 것처럼, 기존 HTML 파일로부터 HTML 조각을 만들어야 한다. 일반적으로 Ajax 응답에는 헤더, 푸터, 부가적인 장식 태그들이 생략되므로 이 작업이 필요하다. HTML의 완전한 버전과 조각 버전들은 같은 서버측 템플릿 엔진을 사용하여 만들어낼 수 있지만, 여기서는 원래 파일은 그대로 두고 파일들을 새로운 이름으로 복사하여 효과만 흉내 낸다. 이 작업을 마치고 나면 다음과 같은 파일들이 만들어진다.

  • login-fragment.html
  • checkout1-fragment.html
  • checkout2-fragment.html
  • checkout3-fragment.html
  • checkout4-fragment.html
  • checkout4a-fragment.html

다음으로 각 파일을 열어 주된 폼 태그와 자식 태그들만 남겨두고 모두 삭제하자. 이 작업을 마치면, login-fragment.html의 내용은 Listing 2와 비슷해진다. 다른 파일들도 마찬가지다.


Listing 2. HTML 조각 파일 형식
                
<form method="GET" action="checkout1.html"
	class="checkout" id="lform">
				
	<h2>Step 1: Personal Info</h2>
	
	<h3>Login</h3>
	
	<div>
		<label>
			Email Address
			<input type="text" name="email"
				id="email"/>
		</label>
		<label>
			Password
			<input type="password" name="password"
				id="password"/>
		</label>
	</div>

	<div>
		<input class="button" type="submit"
			name="submit" id="submit"
			value="submit" />
	</div>

</form>

구매 절차 개선하기

이제 필요한 파일을 모두 준비했으니, 실질적인 Ajax로 전면 개편을 시작해보자. 대부분의 코드 변경은 checkout.html에서 이루어진다. 기존 checkout.html이 새로운 탭 인터페이스의 허브 역할도 하고, 자바스크립트를 사용할 수 없는 환경에서 기존 인터페이스의 시작점 역할도 하기 때문에, 조각 파일 형태로 복사하지 않았다.

jQuery UI Tabs를 사용하여 분리된 페이지를 탭으로 바꾸기

checkout.html에서 탭 안으로 들어가야 할 영역을 div 태그로 둘러싸야 한다. 각 div 태그는 class 속성을 "tabContent"로 지정하고, 자바스크립트 코드에서 참조할 수 있는 고유한 id 속성을 가져야 한다. 첫 번째 div 태그는 checkout.html에 원래 있던 내용을 감싸고 있다. 다른 세 개의 빈 div 태그는 Ajax로 가져온 내용을 끼워넣을 자리를 확보하는(placeholder) 역할을 한다. 작업을 마친 HTML 코드가 Listing 3이다.


Listing 3. 탭 형태로 변형될 HTML
                
<div id="personalInfo" class="tabContent">
	
	<h2>Step 1: Personal Info</h2>
	
	<div class="buttons">
		<a class="button" href="checkout1.html"
			id="checkoutAsGuest">
			check out as guest
		</a>
		<a class="button" href="login.html"
			id="login">log in</a>
	</div>

	<div class="fakeForm">
		<p>[long, boring playback of order details]</p>
	</div>

</div>

<div id="shippingDetails" class="tabContent"></div>
<div id="billingDetails" class="tabContent"></div>
<div id="orderReview" class="tabContent"></div>

구매 절차는 모두 5단계인데, 태그가 네 개 밖에 없다는 것이 의아할 수 있겠지만, 걱정할 필요 없다. 5단계인 결과 확인은 특별한 경우다. 5단계를 다른 네 가지 단계와 비슷하게 보여주고 싶겠지만, 5단계는 실질적인 구매가 마무리된 다음에 나온다. 그래서 탭 인터페이스 대신 새 페이지를 열기로 했으며, 따라서 탭이 들어갈 자리도(placeholder) 필요 없다.

방금 추가한 div 태그들에 스타일을 입히자. 탭 아래에서 예쁘게 보이도록 테두리와 패딩을 약간 추가하자. h2 태그가 탭의 레이블과 중복 표시되지 않도록 해야 한다. 연재의 Part 3에서 만들어둔 스타일 규칙들이 있으니, 파일의 아래쪽에 Listing 4의 스타일들이 제대로 추가되어 있는지 확인만 하면 된다.


Listing 4. 탭 내용을 위한 CSS 스타일
                
#CMN .tabContent {
	padding: 14px;
	border: 1px solid #97a5b0;
}
#CMN .tabContent h2{
	display: none;
}

탭의 내용을 위한 div 태그들을 만들었고 스타일도 입혔으니, 이제 탭을 만들 차례다. Part 3에서 배운 내용을 기억하고 있다면, jQuery UI Tabs가 순서없는 목록으로부터 탭을 만든다는 사실을 알고 있을 것이다. 빵부스러기 내비게이션을 표시하기 위해 Listing 5와 같은 ul 태그가 이미 포함되어 있다.


Listing 5. 빵부스러기 내비게이션을 위한 HTML
                
<div class="breadcrumb nav">
	<ul>
		<li class="current">1. Personal Info</li>
		<li>2. Shipping Details</li>
		<li>3. Billing Details</li>
		<li>4. Order Review</li>
		<li class="last">5. Confirmation</li>
	</ul>
</div>

그러나 이 마크업은 jQuery UI Tabs가 요구하는 HTML 구조와 조금 다르므로 탭을 위해 다른 ul 태그를 만들고 CSS와 자바스크립트를 사용하여 두 목록 중 하나만 표시하도록 고쳐야 한다. 기본적으로 빵부스러기 내비게이션을 표시하고 탭은 숨긴다. 이렇게 하면 자바스크립트를 사용할 수 없는 환경에서는 웹 1.0 인터페이스를 볼 수 있다. 자바스크립트를 사용할 수 있는 사용자를 위해 빵부스러기 내비게이션을 위한 목록을 숨기고 탭을 위한 목록을 표시하는 자바스크립트 코드가 필요하다.

탭을 위한 ul 태그는 Listing 6과 같다.


Listing 6. 탭을 위한 HTML
                
<ul class="navTabs">
	<li><a id="tab0" href="#personalInfo">
		<span>1. Personal Info</span></a>
	</li>
	<li><a id="tab1" href="#shippingDetails">
		<span>2. Shipping Details</span></a>
	</li>
	<li><a id="tab2" href="#billingDetails">
		<span>3. Billing Details</span>
	</a></li>
	<li><a id="tab3" href="#orderReview">
		<span>4. Order Review</span>
	</a></li>
	<li class="last"><a id="tab4" href="#">
		<span>5. Confirmation</span>
	</a></li>
</ul>

탭에 대응하는 링크 태그의 URL은 앞에서 만든 div 태그의 이름과 일치해야 한다. 결과 확인(Confirmation) 탭의 경우 연관된 내용이 필요없으므로 해시 기호(#)를 가짜 URL로 지정한다.

ul 태그를 숨기는 CSS는 checkout.html의 noscript 블록에 들어간다. 기억나겠지만, 연재의 Part 3에서도 탭을 만들 때 비슷한 방법을 사용했다. 이번에는 자바스크립트를 사용할 수 없는 사용자를 위해 두 가지 noscript 스타일을 더 추가한다. 기본적으로 Listing 4에서 만들었던 스타일을 뒤집으면 된다. 이렇게 만들어진 noscript 스타일 블록이 Listing 7이다.


Listing 7. 자바스크립트를 사용할 수 없는 환경을 위한 CSS 스타일
                
<noscript>
	<style type="text/css">
		/*don't show tabs when JS disabled*/
		#CMN .navTabs {
			display: none;
		}
		/*without the tab box, disable border+padding*/
		#CMN .tabContent {
			padding: 0;
			border: 0;
		}
		/*without the tab labels, stop hiding h2s*/
		#CMN .tabContent h2 {
			display: block;
		}
	</style>
</noscript>

다음이 재미있는 부분이다. 직접 만든 자바스크립트 코드로 모든 것을 엮어 보자. 모든 코드는 브라우저의 자바스크립트 엔진이 DOM을 사용할 준비가 될 때 발생하는 jQuery의 document.ready 이벤트와 결합시킨다. 이렇게 하면 조작할 DOM 노드들이 준비가 될 때까지 기다린다.

이 복잡한 이벤트 핸들러를 만들려면, checkout.html의 head 태그 아래쪽에 Listing 8에 나오는 스크립트 블록을 추가하면 된다.


Listing 8. 탭을 만들기 위한 자바스크립트 코드
                
<script type="text/javascript">
//when the document is ready
$(document).ready(function() {

	/* hide the breadcrumbs ul and show the tab ul */
	$('div.breadcrumb').hide();
	$('ul.navTabs').show();
	
	/*turn the newly visible ul into tabs*/
	var tabSet = $('ul.navTabs').eq(0).tabs(
		{
			/*apply a nice visual effect to tab activation*/
			fx: { height: 'toggle', opacity: 'toggle' },
			/*disable all but the first tab by default*/
			disabled: [1,2,3,4]
		}
	).bind('select.ui-tabs', function(event, ui) {
			/*
			ensure that each time a new tab is activated
			all subsequent tabs are disabled. This will
			prevent users from jumping around in the process
			*/
			var currentTab = parseInt(ui.tab.id.substring(3));
			var tabSetLength = 5;//a necessary hack
			for (var i = 0; i < tabSetLength; i++) {
				if (i > currentTab) {
					tabSet.tabs("disable", i);
				}
			}
	});

	/*
	bind the checkout and login links to new click
	handlers and cancel their original behavior.
	now, these links will open the fragment versions
	of their original targets inside the first tab.
	*/
	$("#checkoutAsGuest,#login").click(function() {
		$('#personalInfo')
			.load(
				$(this)
				.attr("href")
				.replace(".html", "-fragment.html")
			)
		;
		return false;
	});

});
</script>

Listing 8의 주석에도 있는 것처럼, jQuery를 사용하여 원래 마크업을 새로운 탭 형식으로 변환한다. 더 이상 필요없는 태그들을 숨기고, jQuery UI Tabs가 탭으로 변형시킬 노드를 알려준다. tabs 메서드에는 Part 3에서 사용했던 시각 효과를 위한 옵션을 넘겨주고, 첫 번째 탭을 제외한 나머지 탭을 선택할 수 없도록 한다. 이렇게 하면 사용자의 구매 경로가 단일화되고, 사용자는 각 단계를 차례대로 끝내지 않고 다른 단계로 건너뛸 수 없게 된다. 나중에, 필요에 따라 각 탭을 활성화하거나 비활성화하는 코드를 작성할 것이다.

jQuery UI Tabs는 탭 인터페이스가 동작하는 동안 몇 가지 커스텀 이벤트를 제공한다. onclick이나 onmouseover 같은 내장된 DOM 이벤트와 마찬가지로, 커스텀 이벤트는 콜백 핸들러를 가질 수 있다. 유일한 차이점은 이 이벤트들은 브라우저가 아니라 jQuery와 플러그인이 정의했다는 점이다. 특정 시점에 탭을 활성화하거나 비활성화하기 위해 커스텀 이벤트 핸들러를 사용한다.

새 탭이 활성화되면, select.ui-tabs라는 이벤트가 발생한다(이 이벤트의 이름은 jQuery UI Tabs의 다음 버전에서 바뀔 예정이므로, 문제가 발생하면 문서를 확인하자). jQuery의 bind 메서드를 사용하여 새로 만든 탭과 커스텀 이벤트 핸들러를 연결한다. 이 핸들러는 각 탭을 순회하면서 구매 절차의 다음 단계에 있는 탭들을 비활성화한다. 여기에서 코드에 고정된 탭 배열과 탭의 개수를 참조하고 있다.

다른 탭들의 동작을 정리했으니, 이번에는 첫 번째 탭의 내용을 처리해보자. 먼저 log incheck out as guest 링크의 동작을 바꿔, 원래 링크를 Ajax로 가져와 현재 탭의 내용을 바꾸도록 고치자. 원래의 링크는 완전한 HTML 페이지를 가리키고 있지만, 여기서 필요한 건 앞에서 만들어둔 HTML 조각들이다. jQuery를 사용하여 두 링크에 대한 객체를 찾은 다음, click 이벤트 핸들러로 원래 동작을 재정의한다. 각 링크의 href 속성을 찾아서 HTML 조각 파일을 가리키도록 변경하고, 그 URL을 Ajax로 가져온다. 마지막으로, 가져온 내용을 개인 정보(Personal Info) 탭 안에 표시한다.

자! 구매 경로의 다섯 단계 중 첫 단계를 완성했다. 브라우저로 구매 페이지를 열어보면 그림 2와 같은 페이지를 볼 수 있다.


그림 2. Customize Me Now 2.2 구매 1단계: 로그인 또는 손님으로 구매
그림 2. Customize Me Now 2.2 구매 1단계: 로그인 또는 손님으로 구매

check out as guest 링크를 클릭하면, 그림 3에서 보는 것처럼 개인 정보 탭이 실제 고객 정보 폼으로 바뀐다.


그림 3. Customize Me Now 2.2 구매 1단계: 개인 정보 폼
그림 3. Customize Me Now 2.2 구매 1단계: 개인 정보 폼

log in 링크를 클릭했다면, 그림 4에서 보는 것처럼 개인 정보 탭이 로그인 폼으로 바뀐다.


그림 4. Customize Me Now 2.2 구매 1단계: 로그인 폼
그림 4. Customize Me Now 2.2 구매 1단계: 로그인 폼

아직 전면 개편이 끝나지 않았기 때문에, 지금 로그인이나 개인 정보 폼을 제출하면, 탭 인터페이스가 깨진다. 아직 HTML 조각 파일들을 탭 구조에 맞게 동작하도록 고치지 않았으므로 내용을 탭 안에 계속 불러오는 대신, 전체 페이지를 원래의 완전한 HTML 페이지로 불러온다. 마지막 작업을 끝마치려면 jQuery Form 플러그인을 사용해야 한다.

jQuery Form을 사용하여 단계별 흐름 조절하기

log incheck out as guest 링크를 Ajax 탭 안에서 동작하도록 만드는 일은 간단하다. 구매 페이지들은 HTML 폼을 포함하고 있는데, 이것들의 기본 동작을 재정의하는 일이 조금 까다롭다. Part 1에서 봤던 것처럼, jQuery Form을 사용하여 구닥다리 폼을 멋진 Ajax 위젯으로 변형시키면, Ajax로 전면 개편하는 게 끝난다.

이를 위해, 각 HTML 조각 파일의 아래쪽에 스크립트 블록을 추가하여 폼 제출을 가로채야 한다. 조각들은 Ajax로 읽어오고 checkout.html의 문맥 내에서 실행되므로, 다른 외부 스크립트 파일을 사용할 필요가 없다. 필요한 스크립트들은 checkout.html에 이미 포함되어 있다.

먼저 로그인 폼부터 정리하자. 앞에서 Ajax를 통해 폼을 불러오도록 고쳤다. 이번에는 폼의 submit 이벤트를 핸들러를 설치하여, Ajax를 통해 이 폼을 제출하도록 고쳐야 한다. 같은 HTML 안에 폼 여러 개를 불러오게 되므로 각 폼에 고유한 HTML id 속성을 지정해야 스크립트에서 특정 폼에 접근할 수 있다. HTML 조각 파일들을 보면 이미 처리되어 있다. loing-fragment.html 안에 있는 폼의 idlform, checkout1-fragment.html 안에 있는 폼의 idpform, 나머지도 이런 식으로 되어 있다.

(충돌을 막으려면, 각 폼의 필드들도 유일한 ID를 지정해야 한다. 다시 말하지만, 예제 코드에는 이 작업이 이미 처리되어 있다.)

login-fragment.html의 submit 핸들러가 Listing 9에 나와 있다.


Listing 9. 로그인 페이지를 위한 자바스크립트 submit 핸들러
                
<script type="text/javascript">
// bind the form and provide a callback function
$('#lform').submit(function() { 

	//submit the form via ajax
	$(this).ajaxSubmit({
		target:     '#personalInfo', 
		url:        'checkout1-fragment.html', 
		success:    function() { 
			var tabSet = $('ul.navTabs');
			tabSet.tabs("enable", 0);
			tabSet.tabs("select", 0);
		}
	});

	//don't actually submit the form normally
	return false; 
});
</script>

이 핸들러는 연관된 폼을 찾고, ajaxSubmit 메서드를 사용하여 Ajax를 사용하도록 바꾼다. ajaxSubmit 메서드에 전달되는 인자들의 의미는 다음과 같다.

  • 폼의 값을 submit할 곳(개인 정보 폼을 갖고 있는 checkout1-fragment.html)
  • 응답을 불러올 곳(첫 번째 탭의 div 태그의 id 속성인 personalInfo)
  • Ajax 호출이 성공한 후의 동작(첫 번째 탭을 선택할 수 있게 만든다)

마지막으로, false를 리턴하면 Ajax가 아닌 정상적인 폼 제출을 취소한다.

진척 상황을 확인하려면, 브라우저에서 구매 절차를 새로 시작해보자. log in 링크를 클릭하고, 로그인 폼을 제출하면, 첫 번째 탭에 개인 정보 폼이 표시된다. 이제는 이 폼을 구매 절차가 시작될 때도 볼 수 있고, 로그인 페이지를 거친 후에도 볼 수 있다(실제 서비스라면, 로그인을 거친 후에는 개인 정보 폼이 미리 채워져 있어야 할 것이다).

이제, 첫 번째 탭을 지나 두 번째 탭, 그 다음 탭으로 진행할 수 있도록 만들어보자. 이번에는 개인 정보 폼을 갖고 있는 checkout1-fragment.html에 폼 submit 핸들러를 추가해야 한다. 이 핸들러는 로그인 폼과 비슷하지만, 결과를 첫 번째 탭에 표시하고 활성화하는 대신, 두 번째 탭에 이 동작들을 수행해야 한다. 0부터 시작하는 탭의 인덱스는 1이며, dividshippingDetails로 지정한다. 이렇게 만들어진 핸들러가 Listing 10이다.


Listing 10. 개인 정보 폼을 위한 자바스크립트 submit 핸들러
                
<script type="text/javascript">
// bind the form and provide a callback function
$('#pform').submit(function() { 

	//submit the form via ajax
	$(this).ajaxSubmit({ 
		target:     '#shippingDetails', 
		url:        'checkout2-fragment.html', 
		success:    function() { 
			var tabSet = $('ul.navTabs');
			tabSet.tabs("enable", 1);
			tabSet.tabs("select", 1);
		}
	});

	//don't actually submit the form normally
	return false; 
});
</script>

이런 식으로 나머지 HTML 조각 파일들을 고쳐보자. 단, 4단계인 주문 검토(checkout4-fragment.html)는 Ajax 폼을 사용할 필요가 없다. 앞서 언급한 대로, 5단계는 확인(Confirmation) 페이지이며, 탭 인터페이스가 아니라 새 페이지 전체에 표시되므로, 4단계에서는 일반적인 폼 동작을 사용하면 된다. 그러나 주문 검토에는 할인 쿠폰을 적용하는 우회로가 있으므로, 현재 탭에 checkout4b-fragment.html의 할인 폼과 함께 표시하기 위해 click 핸들러가 필요하다(Listing 11).


Listing 11. 주문 검토를 위한 click 핸들러
                
<script type="text/javascript">
$('#enterDiscount').click(function() {
	/*
	grab the url of the current link and load
	the fragment version it in an existing tab
	*/
	$('#orderReview')
		.load(
			$(this).attr("href")
				.replace(".html", "-fragment.html")
			)
		;
	return false;
});
</script>

개선 내용 검토하기

마무리할 시간이다. Customize Me Now 1.2를 전면 개편하여 2.2를 만들었다.

행복한 길 따라가기

실제로 동작하는 탭을 사용한 구매 경로를 확인하려면, 로그인이나 할인 쿠폰 적용 같은 우회로를 거치지 말고 구매의 각 단계를 밟아보자. 모든 절차는 단일 화면 인터페이스에서 이루어진다. 구매 절차의 각 단계는 해당 탭에서 이루어지고, 단계 사이를 오갈 때는 윈도-셰이드 시각 효과를 볼 수 있다. 끝에서 두 번째 단계에서 purchase를 클릭하면, Customize Me Now 1.2와 동일한 확인 페이지가 표시된다.

더 복잡한 길 따라가기

이번에는 로그인과 할인 쿠폰 적용 같은 우회로를 거쳐 구매의 각 단계를 밟아보자. 여러 개의 하위 단계로 이루어진 복합적인 몇몇 단계(1단계와 4단계)를 제외하면 탭을 통한 선형적인 절차는 그대로다. 개별적인 하위 단계들은 시각 효과없이 표시된다. 다음 탭으로 진행할 때는 친숙한 윈도-셰이드 효과를 볼 수 있다.

이제, 좀 더 창의적인 시도를 해보자. 사용자가 이전 단계를 다시 수행하는 상황을 흉내내기 위해 4단계까지 끝마친 다음, 2단계의 탭을 클릭하자. 두 번째 탭이 다시 활성화되지만(폼 필드에 이전에 입력했던 값들이 그대로 유지하고) 세 번째와 네 번째 탭은 비활성화된다. 구매 절차를 되돌리고 나서, 절차를 다시 밟으려면 폼을 다시 제출해야 한다. Listing 8에서 추가한 활성화와 비활성화 코드가 완벽하게 동작함을 확인할 수 있다.

이 제약이 예제 응용 프로그램을 위해 임의로 정한 것처럼 보일 수 있겠지만, 실제 서비스에서도 중요하다. 2단계의 사용자 답변이 4단계의 질문에 영향을 미칠 수 있고, 이전 단계의 답변이 바뀌면, 이후 단계들을 다시 밟아야 한다. 이러한 실제 서비스 시나리오에서는, 각 탭을 다시 방문할 때 해당 내용을 Ajax로 다시 받아오도록 탭 인터페이스에 코드를 추가로 작성해야 한다.

점진적 개선 시험하기

마지막으로, 자바스크립트를 사용할 수 없는 환경에서 구매 페이지를 다시 열어, Ajax를 적용하기 전의 인터페이스를 통해 구매에 문제가 없는지 확인하자. 자바스크립트를 사용해 구닥다리 인터페이스 전체를 재작성하는 대신 점진적으로 개선하면 여러분이 만든 응용 프로그램을 더 다양한 브라우저에서 사용할 수 있다.

무엇을 개선했나요?

일련의 폼들을 탭을 이용하여 한 페이지로 만든다는 단순한 목표를 위해 꽤 많은 작업이 했다. 이 작업을 통해 얻은 것은 무엇인가? 늘 그렇듯이 대답은 사용자 경험의 문제다.

Customize Me Now 1.1의 다중 페이지 인터페이스도 그렇게 나쁘진 않았지만, 일련의 폼들을 불러오는 과정은 사용자를 기다리게 만들고, 각 단계를 오갈 때 혼란스러웠다. 구닥다리 빵부스러기 내비게이션을 제공했지만, 시각적으로 볼 때 빵부스러기 흔적은 구매 과정을 통일성 있게 만드는 데 그다지 도움이 되지 못했다. 전역 내비게이션이나 테스트 위주의 내용과 비슷하기 때문에, 빵부스러기 링크들은 시각적으로 구별되는 탭 인터페이스보다 눈에 잘 띄지 않았다. 탭 인터페이스는 구매 절차에 시각적인 결합을 제공하고, 연결되지 않은 일련의 페이지들을 단일한 인터페이스로 바꿨다. 각 단계 사이에서 볼 수 있는 윈도-셰이드 효과는 사용자가 구매 절차를 진행하고 있음을 상기시켜 결합을 강화했다.

로그인이나 할인 쿠폰 적용 등의 부가적인 단계들을 거치는 사용자 경험도 개선했다. 개선 전 인터페이스에서는, 사용자들이 구매 절차 중에서 어떤 단계에 있는지 혼란스러웠지만, 새로운 구매 경로에서는 개별 단계의 복합적인 동작들이 페이지에서 사라지지 않고 단일 탭에서 이루어지므로 사용자들이 헤매지 않게 됐다. 단일 탭 내에서 각 하위 단계에는 윈도-셰이드 효과를 보여주지 않기 때문에, 사용자는 현재 단계가 끝나지 않았음을 인지할 수 있다.

다음에는 무엇을 개선해야 하나요?

탭을 이용해 구매 절차를 개선했으니, 사용자 인터페이스에서 문제가 있는 부분들에 대한 전면 개편을 계속할 수 있게 됐다. 다음은 추가 개선이 필요한 작업 목록이다.

  • Ajax 실패 처리하기: 새로 만든 submit 핸들러는 Ajax 호출이 성공했을 때만 동작한다. 실제로 서비스를 하는 사이트라면 서버 오류나 네트워크 지연 등으로 인해 Ajax 호출이 실패할 때를 대비하고 복구해야 한다.
  • 폼 검증하기: 입력 검증은 개발자와 사용자 모두에게 가장 큰 골칫거리 중 하나다. 이 글에서는 이런 곤란한 문제를 깡그리 무시했지만, 제대로만 하면 Ajax 폼 검증은 사용자 경험을 엄청나게 향상시킬 수 있고 코드를 더욱 효과적이고 유지보수하기 쉽게 만든다.
  • 장바구니 항상 보여주기: 새로 만든 Ajax 인터페이스는 사용자에게 장바구니를 구매 절차의 시작과 끝에만 보여준다. 요약된 장바구니를 탭 바로 옆에 사이드바로 표시하고, 구매의 각 단계가 끝날 때마다 갱신할 수 있을 것이다. 이러한 주문 내용에 대한 지속적인 피드백은 사용자에게 엄청난 가치가 있다.
  • 뒤로가기(Back) 버튼 관리 통합하기: 개선도 많이 했지만, 새로운 문제도 만들었다. 구매 절차 중에는 뒤로가기 버튼이 무용지물이다. 이 문제를 해결하는 것은 간단하다. Ajax 방문기록 관리 라이브러리를 사용하면 탭에 새로운 폼을 표시할 때마다 브라우저의 방문기록에 새로운 항목을 추가할 수 있다. 이렇게 하면, 사용자가 뒤로가기 버튼을 클릭할 때, 구매 절차를 완전히 벗어나 이전 페이지로 돌아가는 대신, 이전 탭으로 돌아가게 만들 수 있다. 이를 위해 Really Simple History 같은 별도의 라이브러리를 사용할 수 있는데 jQuery, Prorotype, 기타 많은 Ajax 프레임워크와 함께 사용할 수 있다(미리 밝혀 두자면, 이 기사의 필자는 Really Simple History의 핵심 개발자다).

보는 바와 같이, 가능성은 끝이 없다. 그러나 이 글에서 소개한 개선 작업들이 구매 과정를 계속 개선하기 위한 굳건한 Ajax 뼈대를 제공할 것이다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
개선 전 예제 소스 코드wa-aj-overhaul4OnePointTwo.zip832KBHTTP
개선 후 예제 소스 코드wa-aj-overhaul4TwoPointTwo.zip928KBHTTP
다운로드 방식에 대한 정보

더 많은 다운로드

Notes

  1. 필자의 회사 웹 서버에서 개선 전 예제 응용 프로그램을 돌려 볼 수 있다.
  2. 필자의 회사 웹 서버에서 개선 후 예제 응용 프로그램을 돌려 볼 수 있다.
  3. 필자의 회사 웹 서버에서 연재 기사에서 소개된 모든 버전의 예제 응용 프로그램을 돌려 볼 수 있다.


참고자료

교육
  • jQuery 문서 웹 사이트에서 jQuery 응용 프로그램 인터페이스(API)를 배워보자.

  • Learning jQuery 웹 사이트를 통해 jQuery 커뮤니티에 참여하고 튜토리얼과 포럼을 확인하자.

  • "jQuery로 Ajax 개발을 단순화하기"(Jesse Skinner, 한국 developerWorks, 2007년 9월) 기사를 통해 Ajax를 더 심도있게 익힐 수 있다.

  • jQuery in Action(Manning Publication Co., 2008년 2월)을 통해 jQuery에 대한 추가적인 도움을 받을 수 있다.

  • Brian Dillard의 블로그 Agile Ajax를 통해 jQuery와 기타 UI 관련 주제들을 확인하자.

  • Billy Hoffman과 Bryan Sullivan의 책 Ajax Security(Addison Wesley Professional, 2007년 12월)에서 Ajax 응용 프로그램의 보안에 대한 모범 사례들을 볼 수 있다.

  • 유명한 웹 개발자 Luke Wroblewski의 블로그 Functioning Form에서 웹 폼 설계의 모범 사례에 대한 다양한 의견을 볼 수 있다.

  • 기술 서점에서 이 주제 또는 기타 기술 주제에 대한 책들을 찾아보자.


제품 및 기술 얻기
  • jQuery 웹 사이트에서 jQuery의 설계 철학을 배우고, 추가적인 플러그인들을 찾아보자. 글을 쓰는 시점에서 현재 버전은 1.2.3이다.

  • jQuery UI Tabs라는 jQuery 플러그인을 사용하면 내장되어 있거나 Ajax로 가져온 내용을 탭 인터페이스로 만들 수 있다. 이 플러그인은 입맛대로 조절할 수 있는 위젯과 사용자 인터페이스 컴포넌트의 모음인 jQuery UI의 일부다.

  • jQuery Form: 이 플러그인을 사용하면 HTML 폼을 강력한 Ajax 컴포넌트로 변형시킬 수 있는 직관적이고 편리한 방법을 다양하게 제공한다.

  • Ajax 방문기록 라이브러리인 Really Simple History를 사용하면 사용자가 웹 응용 프로그램에서 기대하는 뒤로가기(Back) 버튼과 북마크 동작을 복원할 수 있다.


토론


필자소개

Brian Dillard

Brian J. Dillard는 12년 동안 웹 개발자로 일하면서 Orbitz Worldwide, Reflect True Custom Beauty, Archipelago LLC, United Airlines 같은 다양한 회사를 위해 풍부한 사용자 인터페이스를 구축했다. 현재 시카코에 위치한 Pathfinder Development에서 RIA 전도사로 일하면서, 다양한 고객을 위한 리치 인터넷 애플리케이션을 구축하고, 오픈 소스 프로젝트에 참여하고, Agile Ajax 블로그에 기여하고 있다. 수천 개 웹 사이트에서 실무에 사용되는 Ajax 방문기록 및 북마크 라이브러리인 Really Simple History 프로젝트를 이끌고 있다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의