포스트를 읽기에 앞서...
- 이 포스트는 영문으로 작성되어 제공되어진 것을 제가 제 나름대로 한글로 번역하였습니다. 모든 저작권에 대해서는 영문 웹 페이지에 명시된 곳에 있습니다.
- 직역보다는 의역에 충실하도록 노력을 하였으며, 충분하게 잘못된 번역이 있을 수 있습니다. 잘못된 번역 부분에 대해서는 덧글로 달아주시면 수정하도록 하겠으며, 잘못된 번역 부분은 원문 영문 웹 페이지를 참조하시기 바랍니다.
- 필요에 의한, 실제적인 코드의 작성 방법은 원문과 달리 제 나름대로 요약할 수 있습니다.
- 원문의 경로는 JavaScript Tips for ASP.NET Developers - Part 1입니다.

Introduction


이 아티클은 ASP.NET 개발자들을 위한 JavaScript 팁을 제공하는 시리즈 중의 첫번째 파트입니다.

Background


ASP.NET 서버 컨트롤이 서버측에서 우리가 작성하는 코드를 더 쉽게 만들 수 있게 해준다는 점은 의심할 필요가 없습니다. Karamasoft UISuite™와 같은 써드파티 컴포넌트들은 서버측과 클라이언트측 둘 다를 더 쉽게 개발할 수 있도록 만들어줍니다. 그러나, 여러분은 아직 여러분의 웹 사이트를 방문하는 방문자에게 강력한 사용자 인터페이스를 제공하기 위한 클라이언트측 프로그래밍에 대한 어느 정도의 지식이 여전히 필요할 것입니다.

JavaScript는 여러분이 서버측 개발 환경에서 개발을 함에도 불구하고 클라이언트측 프로그래밍을 위해 가장 일반적으로 사용되는 언어입니다. 비록 이번 아티클이 다른 언어와 프레임워크에 적용될 수도 있지만, 대부분의 팁이 ASPX와 C#의 샘플 코드로 작성되는 것이기 때문에, ASP.NET 개발자들에게 더 좋을 것이라고 생각합니다.

Using the code


1. Get DOM elements with one simple method
2. Add/Remove event handlers
3. View the current HTML state of your page
4. Disable a button after click to prevent subsequent postbacks to server
5. Use references to deeply nested objects
6. Create your own watermark textbox
7. Center your window on the screen
8. Validate max character length in a text area
9. Display confirmation before the page is closed
10. Format number
11. Swap table rows on the client-side

1. Get DOM elements with one simple method

브라우저에 상관없이 d0cument 객체의 getElementById 메소드는, 특정된 ID 속성값을 가진 객체의 참조를 반환합니다. Prototype JavaScript Framework (http://www.prototypejs.org)은 DOM 요소를 반환하기 위한 짧은 이름의 사용하기 좋은 JavaScript 메소드를 제공합니다.

function $() {
var elements = new Array();
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];
if (typeof element == 'string')
element = d0cument.getElementById(element);
if (arguments.length == 1)
return element;
elements.push(element);
}
return elements;
}

이 메소드의 한가지 좋은 점은 여러분이 하나의 인수 또는 여러 개의 인수를 전달할 수 있다는 것입니다. 만약, 하나의 인수가 전달된다면, 이 메소드는 특정 ID값을 가진 객체의 참조를 반환합니다. 만약 그렇지 않다면, 특정 ID 값들을 가진 객체들의 참조의 배열을 반환합니다. 이 메소드의 다른 좋은 점은 인수로써 string 형식뿐만 아니라 object 형식도 취할 수 있다는 것입니다.

var elem = d0cument.getElementById('TextBox1');

여러분은 다음과 같이 $ 메소드를 호출할 수 있습니다.

var elem = $('TextBox1');

또는, 하나의 간단한 메소드를 호출하여 다중 DOM 요소를 반환시킬 수 있습니다.

var elemArr = $('TextBox1', 'TextBox2');

2. Add/Remove event handlers

여러분은 쉽게 객체의 이벤트가 발생할 때 호출되는 이벤트를 위한 함수를 결합/비결합시킬 수 있습니다.

이벤트 핸들러를 추가/제거하기 위해 Internet Explorer DOM (Document Object Model)은 attachEvent와 detachEvent 메소드를 제공하며, Mozilla DOM은 addEventListener와 removeEventListener 메소드를 제공합니다.

여러분은 여러분의 이벤트 핸들러를 추가/삭제하기 위한 JavaScript 메소드를 다음과 같이 사용하실 수 있습니다.

function AddEventHandler(obj, eventName, functionNotify) {
if (obj.attachEvent) {
obj.attachEvent('on' + eventName, functionNotify);
}
else if (obj.addEventListener) {
obj.addEventListener(eventName, functionNotify, true);
}
else {
obj['on' + eventName] = functionNotify;
}
}

function RemoveEventHandler(obj, eventName, functionNotify) {
if (obj.detachEvent) {
obj.detachEvent('on' + eventName, functionNotify);
}
else if (obj.removeEventListener) {
obj.removeEventListener(eventName, functionNotify, true);
}
else {
obj['on' + eventName] = null;
}
}

여러분은 다음과 같은 메소드를 통해 위의 메소드를 호출할 수 있습니다.

JavaScript :
function AddKeyDownEventHandler(obj) {
AddEventHandler(obj, 'keydown', KeyDownEventHandler);
}

function KeyDownEventHandler(evnt) {
alert('Event key code: ' + GetEventKeyCode(evnt));
}

function GetEventKeyCode(evnt) {
return evnt.keyCode ? evnt.keyCode : evnt.charCode ?
evnt.charCode : evnt.which ? evnt.which : void 0;
}

function BodyOnloadHandler() {
AddKeyDownEventHandler(d0cument.getElementById('<%=txtKeyDown.ClientID%>'));
}

ASPX :

<body omload="BodyOnloadHandler()">
<asp:TextBox ID="txtKeyDown" runat="server" CssClass="TextBox"></asp:TextBox>

3. View the current HTML state of your page

여러분이 브라우저의 소스 보기를 할 경우, 소스 보기는 페이지가 로드된 페이지의 상태를 표시합니다. 그러나, 페이지에 동적 컨텐츠(특히 AJAX 환경)가 있을 경우에는, 페이지의 현재 소스를 볼 필요가 있을 것입니다.

주소창에 다음을 입력하시기 바랍니다.

Internet Explorer :
javascript:'<xmp>'+window.d0cument.body.outerHTML+'</xmp>'

Firefox :
javascript:'<xmp>'+d0cument.getElementsByTagName('html')[0].innerHTML+'</xmp>'

또는, 브라우저에 상관없는 하나의 JavaScript 구문으로 결합시킬 수도 있습니다.

javascript:'<xmp>'+((d0cument.all) ? window.d0cument.body.outerHTML :
d0cument.getElementsByTagName('html')[0].innerHTML)+'</xmp>'

4. Disable a button after click to prevent subsequent postbacks to server

개발자로써 여러분은 Submit 버튼의 더블 클릭을 절대 하지 않을 것이지만, 웹 사이트의 사용자들은 그렇게 할 것이고, Submit 버튼의 코드가 2번 실행되게 됩니다. 사용자들은 아직 프로세스가 진행중일 경우에도 여러 번 클릭을 할 수도 있습니다. 만약 여러분이 버튼 클릭 이벤트 핸들러에 데이터베이스 연산 또는 메일을 보내는 코드를 작성하였다면, 더블 클릭은 여러분의 시스템에 기대하지 않은 결과를 만들 것입니다. 비록 여러분이 위험한 코드를 작성하지 않았더라도, 서버는 불필요한 호출로 인해 부하가 많이 걸릴 것입니다.

서버로의 불필요한 포스트백을 막기 위해, 사용자가 Submit 버튼을 클릭하는 순간, 여러분은 Submit 버튼을 Disable 시키고, Submit 버튼의 글자를 변경하는 다음과 같은 코드를 이벤트 핸들러에 작성합니다.

JavaScript :
function DisableButton(buttonElem) {
buttonElem.value = 'Please Wait...';
buttonElem.disabled = true;
}

ASPX :
<asp:button id="btnSubmit" runat="server" Text="Submit" />

C# :
protected void Page_Load(object sender, EventArgs e)
{
btnSubmit.Attributes.Add("onclick", "DisableButton(this);" +
Page.ClientScript.GetPostBackEventReference(this,
btnSubmit.ID.ToString()));
}

5. Use references to deeply nested objects

JavaScript 객체는 다음과 같이 dot 연산자를 사용하여 중첩(Nested)되게 사용할 수 있습니다.

tableElem.rows[0].cells[0]

만약 여러분이 위와 같이 여러 개의 연산자를 사용한다면, 각 dot 연산자는 속성을 검색하기 위한 연산을 유발시키기 때문에 참조하기 위한 변수를 정의하는 데에 더 편리합니다. 예를 들어, 만약 여러분이 루프를 돌며 table cell들을 처리할 필요가 있다면, cell들의 컬렉션을 참조하기 위한 지역 변수를 선언하여 사용합니다.

var cellsColl = tableElem.rows[0].cells;
for (var i = 0; i < cellsColl.length; i++) {
cellsColl[i].style.backgroundColor = '#FF0000';
}

비록 위의 코드가 지역 변수를 통하여 cell의 컬렉션을 참조하기는 하지만, 여전히 루프를 돌면서 각 단계마다 cell 컬렉션의 length 속성을 체크하게 됩니다. 그러므로, 다음과 같이 지역 변수에 cellsColl.length 속성을 저장하는 것이 더 좋습니다.

for (var i = 0, loopCnt = cellsColl.length; i < loopCnt; i++)

6. Create your own watermark textbox

워터마크의 주 목적은 페이지의 혼란(cluttering up) 없이 텍스트박스를 통해 사용자에게 정보를 제공하는 것입니다. 여러분은 아마도 웹 사이트의 검색 상자에서 이러한 예제를 많이 보았을 것입니다. 워터마크된 텍스트박스에 어떠한 글자도 입력하지 않았을 때에는 사용자에게 어떠한 정보나 메세지를 표시합니다. 사용자가 텍스트박스에 글자를 입력할 경우, 워터마크된 텍스트박스는 사라지게 됩니다. 만약, 다시 텍스트박스의 컨텐츠에 입력된 글자가 사라졌을 경우에는 다시 워터마크된 텍스트가 나타나게 됩니다.

여러분은 쉽게 onfocus와 onblur 이벤트 핸들러를 사용하여 워터마크 행동을 제공하는 텍스트박스를 만들수 있습니다. focus 이벤트에서, 워터마크의 글자와 입력된 글자가 일치하게 되면, 텍스트박스는 클리어됩니다. blur 이벤트에서, 만약 텍스트박스에 글자가 입력되지 않았다면 워터마크 텍스트가 다시 나타되게 됩니다.

JavaScript :
function WatermarkFocus(txtElem, strWatermark) {
if (txtElem.value == strWatermark) txtElem.value = '';
}

function WatermarkBlur(txtElem, strWatermark) {
if (txtElem.value == '') txtElem.value = strWatermark;
}

ASPX :
<asp:TextBox ID="txtWatermark" runat="server" />

C# :
protected void Page_Load(object sender, EventArgs e)
{
string strWatermark = "Search Karamasoft.com";
txtWatermark.Text = strWatermark;
txtWatermark.Attributes.Add("onfocus", "WatermarkFocus(this, '" + strWatermark + "');");
txtWatermark.Attributes.Add("onblur", "WatermarkBlur(this, '" + strWatermark + "');");
}

7. Center your window on the screen

여러분은 화면에서 window.open 메소드로 여는 윈도우를 중앙으로 위치시킬 수 있습니다. Internet Explorer와 Mozilla DOM 둘 다 시스템 화면의 작업 영역의 넓이와 높이를 검색하기 위한 availWidth와 availHeight 속성들을 가지는 윈도우 스크린 객체(window screen object)를 제공합니다. 화면의 넓이(또는 높이)와 윈도우의 넓이(또는 높이)와 이것들을 2로 나눈 값들에 대한 차이를 얻기 위해서 이것들을 사용할 필요가 있습니다.

이 메소드들의 기능적 재사용을 만들기 위해, 여러분은 넓이, 그리고 높이와 같은 속성들을 포함하는 특정(feature) 인수를 교체함으로써 window.open 메소드를 호출하기 위한 래퍼 메소드를 만들 수 있습니다. 여러분은 특정 인수값에서 넓이와 높이 속성을 분석(parse)할 수 있고, 윈도우의 중앙에 대한 좌측(left)과 상단(top)값을 찾을 수 있으며, 특정 인수 값으로 좌측과 상단 속성을 추가할 수 있습니다.

특정 인수는 보통 다음과 같이 보이게 됩니다.

'width=400,height=300,location=no,menubar=no,resizable=no,scrollbars=no,status=yes,toolbars=no'

첫번째로, 우리는 특정 스트링에서 넓이와 높이 값을 분석하는 메소드를 만들 필요가 있습니다. 쿼리스트링 값들을 찾기 위해 쿼리 스트링을 분석하는 것처럼 이름/값 쌍을 자르기 위한 다른 목적을 위해서도 이 메소드를 사용하기를 원할 수도 있습니다.

function GetAttributeValue(attribList, attribName, firstDelim, secondDelim) {
var attribNameLowerCase = attribName.toLowerCase();
if (attribList) {
var attribArr = attribList.split(firstDelim);
for (var i = 0, loopCnt = attribArr.length; i < loopCnt; i++) {
var nameValueArr = attribArr[i].split(secondDelim);
for (var j = 0, loopCnt2 = nameValueArr.length; j < loopCnt2; j++) {
if (nameValueArr[0].toLowerCase().replace(/\s/g, '') ==
attribNameLowerCase && loopCnt2 > 1) {
return nameValueArr[1];
}
}
}
}
}

이 메소드는 인수로 이름/값 쌍의 목록과 그 값을 검색하기 위한 속성명, 첫번째 구분자와 두번째 구분자인 인수를 취합니다. 첫번째 구분자는 컴마(,)일 것이고, 두번째 구분자는 이 경우에 이퀄(=) 기호일 것입니다. 쿼리스트링 값을 분석하기 위해서 첫번째 구분자는 앰퍼샌드(&)가 될 것이고, 두번째 구분자는 이퀄(=) 기호가 될 것입니다.

이제 화면의 넓이와 높이값을 검색하기 위한 메소드를 정의합니다.

function GetScreenWidth() {
return window.screen.availWidth;
}

function GetScreenHeight() {
return window.screen.availHeight;
}

이들 메소드를 사용하여 window.open 래퍼 메소드를 만들 수 있습니다.

function WindowOpenHelper(sURL, sName, sFeatures, centerWindow) {
var windowLeft = '';
var windowTop = '';
if (centerWindow) {
var windowWidth = GetAttributeValue(sFeatures, 'width', ',', '=');
windowLeft = (typeof(windowWidth) != 'undefined') ? ',left=' +
((GetScreenWidth() - windowWidth) / 2) : '';
var windowHeight = GetAttributeValue(sFeatures, 'height', ',', '=');
windowTop = (typeof(windowHeight) != 'undefined') ? ',top=' +
((GetScreenHeight() - windowHeight) / 2) : '';
}
window.open(sURL, sName, sFeatures + windowLeft + windowTop);
}

이 메소드는 표시하기 위한 문서의 URL, 윈도우명, 특정 아이템들의 목록, 윈도우가 중앙에 위치할것인지를 가리키는 불린값과 같은 4개의 인수를 취합니다.

여러분은 이제 페이지에서 WindowOpenHelper 메소드를 호출할 수 있습니다.

JavaScript :
function OpenWindowCentered(windowWidth, windowHeight) {
WindowOpenHelper('http://www.karamasoft.com', 'WindowCentered',
'width=400,height=300,location=no,menubar=no,
resizable=no,scrollbars=no,status=yes,toolbars=no', true);
}

ASPX :
<asp:LinkButton ID="lbOpenWindowCentered" runat="server"
omClientClick="OpenWindowCentered(); return false;">Open window
centered</asp:LinkButton>

8. Validate max character length in a text area

HTML input 형태의 텍스트 요소는 사용자가 입력하는 최대 글자수를 설정할 수 있는 내장된 MaxLength 속성을 제공합니다. 그러나, TextArea 요소는 입력 가능한 글자수를 제한하기 위한 그러한 속성을 가지지 않습니다. 여러분이 웹 페이지에서 TextMode = "MultiLine" 속성을 가진 ASP.NET 텍스트박스를 사용했을 경우, HTML TextArea 요소로 렌더링될 때, 여러분은 최대 글자수를 설정하기 위한 MaxLength 속성을 사용할 수 없습니다.

여러분은 TextArea의 글자수를 체크하고, 만약 최대 글자수에 도달했을 때 이벤트를 취소하기 위한 TextBox 컨트롤의 keypress 이벤트 핸들러를 정의할 수 있습니다.

JavaScript :
function ValidateMaxLength(evnt, str, maxLength) {
var evntKeyCode = GetEventKeyCode(evnt);
// Ignore keys such as Delete, Backspace, Shift, Ctrl,
// Alt, Insert, Delete, Home, End,
// Page Up, Page Down and arrow keys
var escChars = ",8,17,18,19,33,34,35,36,37,38,39,40,45,46,";
if (escChars.indexOf(',' + evntKeyCode + ',') == -1) {
if (str.length >= maxLength) {
alert("You cannot enter more than " + maxLength + "characters.");
return false;
}
}
return true;
}

ASPX :
<asp:TextBox ID="txtValidateMaxLength" runat="server" TextMode="MultiLine" />

C# :
protected void Page_Load(object sender, EventArgs e)
{
txtValidateMaxLength.Attributes.Add("onkeypress", "return
ValidateMaxLength((window.event) ? window.event : arguments[0],
this.value, 5)");
}

9. Display confirmation before the page is closed

만약, 여러분이 사용자가 윈도우를 닫기 전에 확인(confirmation)을 보여줄 필요가 있다면, 여러분은 확인 메세지를 표시하기 위한 윈도우 객체의 beforeunload 이벤트를 사용할 수 있습니다.

JavaScript :
function AddUnloadHandler() {
AddEventHandler(window, 'beforeunload', HandleUnload);
}

function HandleUnload() {
var strConfirm = 'Please make sure you saved your changes before closing the page.';
if (d0cument.all) {
window.event.returnValue = strConfirm;
}
else {
alert(strConfirm);
var evnt = arguments[0];
evnt.stopPropagation();
evnt.preventDefault();
}
}

ASPX :
<body omload="AddUnloadHandler()">

10. Format number

여러분은 숫자 또는 통화값의 포맷을 지정하는 다음과 같은 메소드를 사용할 수 있습니다. 이 메소드는 포맷을 지정할 숫자, 십진법(decimal) 위치의 숫자, 0값이 추가되어야하는지를 가리키는 불린값, 그리고 천단위를 구분할 때 컴마가 추가되어야하는지를 가리키는 블린값의 4개의 인수를 취합니다.

function FormatNumber(num, decimalPlaces, appendZeros, insertCommas) {
var powerOfTen = Math.pow(10, decimalPlaces);
var num = Math.round(num * powerOfTen) / powerOfTen;
if (!appendZeros && !insertCommas) {
return num;
}
else {
var strNum = num.toString();
var posDecimal = strNum.indexOf(".");
if (appendZeros) {
var zeroToAppendCnt = 0;
if (posDecimal < 0) {
strNum += ".";
zeroToAppendCnt = decimalPlaces;
}
else {
zeroToAppendCnt = decimalPlaces - (strNum.length - posDecimal - 1);
}
for (var i = 0; i < zeroToAppendCnt; i++) {
strNum += "0";
}
}
if (insertCommas && (Math.abs(num) >= 1000)) {
var i = strNum.indexOf(".");
if (i < 0) {
i = strNum.length;
}
i -= 3;
while (i >= 1) {
strNum = strNum.substring(0, i) + ',' + strNum.substring(i, strNum.length);
i -= 3;
}
}
return strNum;
}
}

11. Swap table rows on the client-side

여러분은 클라이언트측에서 현재의 행과 교환할 행의 열 컨텐츠를 교환함으로써, 테이블 행을 교환(swap)할 수 있습니다. 다음의 메소드는 현재 테이블 행의 요소, 행을 위로 올릴지를 가리키는 불린값, 첫번째 행은 무시할 것인가를 가리키는 불린값의 세 개의 인자를 가집니다.

function SwapRows(rowElem, dirUp, ignoreFirstRow) {
var rowElemToSwap = (dirUp) ? rowElem.previousSibling : rowElem.nextSibling;
// Firefox returns a blank text node for the sibling
while (rowElemToSwap && rowElemToSwap.nodeType != 1) {
rowElemToSwap = (dirUp) ? rowElemToSwap.previousSibling :
rowElemToSwap.nextSibling;
}
if (rowElemToSwap && !(ignoreFirstRow && rowElemToSwap.rowIndex == 0))
{
var rowCells = rowElem.cells;
var colInner;
for (var i = 0, loopCnt = rowCells.length; i < loopCnt; i++) {
colInner = rowCells[i].innerHTML;
rowCells[i].innerHTML = rowElemToSwap.cells[i].innerHTML;
rowElemToSwap.cells[i].innerHTML = colInner;
}
}
}

## 출처 : http://www.neostyx.net/GrayRound/NXBlogPostView.aspx?postid=071119115819172&categoryname=ASP.NET

Posted by 퓨전마법사
,