Programming(Web)/JAVASCRIPT
[JS] 2009년 12월 17일자 <로미오의 푸른하늘 삽질 일보>
novasera
2009. 12. 17. 19:18
오늘도 슬픕니다.
"아~~~~ 삽질은 이제 그만~" 이라는 옛 노래의 가사 (잉..가사가 달랐던거 같은걸! 퍽) 처럼
삽질은 그만 하고 싶었는데. 오늘도 열심히! 했습니다.
오늘은 무슨 일에 삽을 펐느냐. 자바스크립트 입니다.
1.발단은 식상함....
발단은 이렇습니다.
이런식으로 대리점 리스트를 뿌려주는 작업이 있습니다.
그럼 그 담에는 수정/삭제도 되도록 해야겠지요???
네. 그래서 수정/삭제를 구현하려고 했습니다.
그런데 왼쪽 끝에 체크박스 만들고 밑에 [수정][삭제] 버튼을 배치하는 매번 똑같은 인터페이스가
그 날따라 유난히도 실증났었습니다.
그래서 뭐 좋은거 없을까...하고 생각하다가 네이버 메일에서 본 오른쪽 버튼 누르면 튀어나오는
메뉴가 생각났습니다.
'아! 그래. 나도 저 왼쪽에 각 대리점 이름을 누르면 옆에 메뉴가 나오게 해서 [수정][삭제]를 선택 할 수
있게 해야지!' 하고 생각했습니다.
그래서 구현 작업을 시작했습니다.
2. 이왕 만드는거...
그런데 한가지 생각이 더 떠올랐습니다.
매번 제가 웹페이지를 짜면서든 생각은, 내가 만든 자바스크립트는 너무나도 html과 유착관계가 깊어서
어디 다른데다 재사용 하기가 힘들다는 것이였습니다.
그래서 '나도 멋지게 다른 프로그래머들처럼 패키지 식으로 하나 만들어서 다른데도 사용 할 수 있는
스크립트를 만들겠어!' 하고 생각했습니다. 없는 실력이지만 그래도 발전가능성이 있는 아름다운
생각입니다.
그래서 우선 html단에 팝업메뉴를 튀어나오게 할 이벤트발생점부터 거꾸로 짜보았습니다.
나중에 함수를 다 만들고 나서 딱 이렇게만 html에 코딩하면 메뉴팝업 뿅~하고 튀어나오도록 하는 코드!
그런 코드가 이랬으면 좋겠다. 하고 생각했습니다.
-----------------------------------------------------------------
<td style="text-align:center;">
<span onclick="objUtils.popupMenu(this, ['수정','editAgency','<?=$idx?>'], ['삭제','delAgency']);" onmouseover="this.style.textDecoration='underline';" onmouseout="this.style.textDecoration='none';" style="cursor:pointer;"><?= $agency_name ?></span>
</td>
-----------------------------------------------------------------
위 내용은 좀 더 위에 올린 그림에서 대리점 명을 출력하는 부분입니다.
보시는 바와 같이 onclick 이벤트에 저렇게 함수만 호출하면 뿅~하고 팝업메뉴가 만들어져서 나오는
방식입니다.
최종적으로 덕지덕지 뭐가 많이 붙어있긴 하지만 다 띄고 보면
objUtils.popupMenu(this, ['메뉴이름1','클릭실행함수명','함수인자'], ['메뉴이름2','클릭실행함수명2']);
대충 이러한 사용법입니다.
클릭했을 때 실행할 함수가 인자를 줘야하는 때도 있고, 아닌 때도 있어서 함수인자부분은 옵션으로
했습니다.
그담엔 실제 함수 구현을 1차로 여차 저차 했습니다.
팝업메뉴 내부에 디자인은 테이블로 하는데, DOM을 이용해서 생성, 붙이기 하였습니다.
DOM을 이용했기에, 해당 메뉴를 클릭 했을 때 실행될 onclick 이벤트 역시 DOM방식으로 처리 했습니다.
----------------------------------------------------------------------
newCell.addEventListener("click", eval(arguments[i][1]), false);
----------------------------------------------------------------------
이런식으로 넣었습니다.
여기까지 구현했을 당시에는 실행될 함수에 인자도 넣어야 된다는 생각은 못했습니다.
그냥 앗 된다! 하면서 좋아하고, '좋아, 이제 수정 메뉴를 눌렀을 때 처리를 코딩하자!' 하면서
해당 함수에 커서를 옮겨놓고 보니.
..... 램프의 알리바바가 말합니다. '무엇을 수정할꼬?'
웁쓰.... 대상이 없군요. 인자가 필요했습니다.
DOM을 이용해서 팝업메뉴 DIV를 대리점명 TD 밑에 차일드로 붙이고 parentNode로
쭉쭉쭉(정말 몇번을 써야했는지...)올라가 id를 보고 '아~ 이 분이 날 불렀구나!' 하고 알아내려고도
했지만, 너무 지저분해지는거 같아 그만뒀습니다.
그래서 인자를 넘기는 방향으로 가닥을 잡았습니다.
3. 문제는 이벤트리스너...
이제 위에서 말한 addEventListener() 함수로 다시 커서를 옮겼습니다.
그전에 브라우저간 호환성을 위해
newCell.attachEvent , newCell["onclick"] 도 if로 구분하여 만들었습니다.
이제, 호출부분에서 인자를 이렇게 주면 어떨까 하고 써보았습니다.
----------------------------------------------------------------------
objUtils.popupMenu(this, ['수정','editAgency(<?=$idx?>)'], ['삭제','delAgency']);
----------------------------------------------------------------------
당연히 안됬습니다.
이유는
newCell.addEventListener("click", eval(arguments[i][1]), false);
부분에서 두번째 인자는 함수명만 쓰고 ()는 안붙입니다.
()를 붙이면 자바스크립트는 인터프리터 방식이기 때문에 그자리에서 바로 실행해버립니다.
그래서 각종 사이트에 검색을 하며 찾아봤습니다.
addEventListener()를 쓰면서 함수에 인자값도 같이 주는거엔 이런 방법이 있다는걸 알게됐습니다.
--------------------------------------------------------------------
newCell.addEventListener("click", function() { editAgency(10) }, false);
--------------------------------------------------------------------
해보니 잘 됩니다.
하지만 제가 하고 있는 방식은 한가지가 더 필요합니다.
바로 함수명마저 인자로 받아오고 있다는 것이지요.
즉, 함수명이 가변적이라는 겁니다.
--------------------------------------------------------------------
1. newCell.addEventListener("click", function() { arguments[i][1]) }, false);
2. newCell.addEventListener("click", function() { eval(arguments[i][1] }, false);
--------------------------------------------------------------------
이렇게 해봤더니 안됩니다. 자바스크립트 문법을 정확히 이해하지 못한것이 여기서 여지없이
터지고 맙니다.
어떻게 저떻게 해도 결국 두번째 인자 함수에는 ()이 붙으면 안되기에 결국 저는 여기서 멈추었습니다.
그리고는 처음부터 이번에는 많이 자제하면서 하자 하는 방법을 썼습니다.
바로. DOM을 사용안하고 HTML 태그를 string으로 생성해서 붙이기.
이방법을 여러번 쓰다보니 코드도 지저분해지고 해서 잘 쓰지 않으려고 했는데, 모든 방법은 다 쓸대가
있는거 같습니다.
위의 코드를 아래와 같이 바꿨습니다.
---------------------------------------------------------------------------------------
for (i=1; i < arguments.length; i++)
{
...길어서 생략...
temp_html += "<td id=\"util_menuTd_"+i+"\"";
temp_html += " onclick=\""+arguments[i][1]+"("+((arguments[i][2]!=null)?arguments[i][2]:"")+")\"";
temp_html += " style=\"cursor:pointer;text-align:center\">";
temp_html += arguments[i][0]+"</td></tr>";
}
objTbl.innerHTML = temp_html;
---------------------------------------------------------------------------------------
아아....해보니 이젠 잘 됩니다.
역시 인터프리터의 '그 자리에서 실행' 특성때문에 막힐 때는 이게 최고인거 같습니다.
눈물이 흐르면서 이 삽질기를 블로그에 남겨 나중에 또 같은 자리에 삽뜨는 일이 생기지 않도록
해야겠다는 생각이 불끈 불끈 들었습니다.
그래서 썼습니다.
그리고 위에 방식을 하면서 하나 더 알게 된거는
obj.innerHTML = 변수
방식으로 대입을 할 때는 여러번 대입하지 말고 딱 마지막에 한번만 대입해야 된다. 하는 것입니다.
처음에는 temp_html 자리에 innerHTML을 써서 매번 넣었는데 그랬더니 넣을 때 마다
<tbody></tbody>가 붙는 것 같았습니다. 같았다...라고 쓰는 이유는 검증하지는 않았기 때문입니다.
그래서 위와 같이 다시 작성하였습니다.
오늘의 결론은
addEventListener()를 사용 할 때엔 (함수이름 가변 & 인자도 넘기기) 가 안되고
(함수이름 가변 | 인자도 넘기기) 이렇게 된다...저는 우선 이렇게 결론 지었습니다.
하지만 또 모릅니다. 함수 호출부에서의 방식을 달리 하고, 내부 구현부에서도
다른 방식을 쓰면 가능 할 수도 있을지 말입니다.
저는 앞서 말했듯이 문법적인 실력 한계가 있어서 (+시간압박) 이렇게 하기로 했습니다.
뭔가 좋은 방법이 있으신 분은 가르침 부탁드리며... 이만 오늘의 삽질 일보를 마치겠습니다.
다음호는 언제 또 나올지 미정이나....제 실력으로 미루어보아 곧 또 발행 될 듯 합니다...(슬픕니다.)