נתקלתי היום בבעייה מעצבנת ב java script.
האמת זה לא פייר להגיד שהבעייה הזאת מעצבנת, כי כל הבעיות ב java script מעצבנות. (אבל זאת במיוחד).
הפוסט הזה ודוגמאות הקוד נכתבו בעזרתו של אחי, יוסי גולדברג.
הייתי צריך להוסיף ב RunTime שורות לטבלה. ולהוסיף onclick על ה td,
נשמע פשוט, לא ?
נראה בהתחלה את הקוד של הוספת השורות. (יש כמה דרכים, אני בחרתי באחת מהם)
1 function createAtRunTime() {
2 var table = document.getElementById('tbl').
3 getElementsByTagName("TBODY")[0];
4
5 for (var i = 0; i < 5; i++) {
6 var row = document.createElement("TR")
7 var cell = document.createElement("TD")
8
9 cell.appendChild(document.createTextNode('shlomo goldberg'));
10
11 row.appendChild(cell);
12 table.appendChild(row);
13 }
14 }
אני מוצא את הטבלה שלי.
רץ בלולאה חמש פעמים.
יוצר שורה.
יוצר עמודה.
מוסיף טקסט לעמודה.
מוסיף את העמודה לשורה.
ומוסיף את השורה לטבלה.
עד כאן הכל פשוט וברור.
עכשיו אני רוצה להוסיף שבזמן לחיצה על העמודה יקרה משהו.
שלב ראשון, אנחנו נפעיל פונקצייה שמציגה הודעה.
אז, נוכל להשתמש ב attachEvent (עבור IE), בצורה הבאה:
1 cell.attachEvent("onclick", ShowMsg);
2 function ShowMsg() {
3 alert("Msg");
4 }
או להשתמש עם setAttribute (תואם לכל הדפדפנים), בצורה הבאה:
5 cell.setAttribute("onclick", function() { ShowMsg() });
וכאן יש לי בעייה, נניח שאני רוצה להפעיל מתודה שמקבלת פרמטרים.
אין לי דרך לעשות את זה.
כי ב attachEvent, הוא מוכן לקבל רק שם של מתודה (כמו delegate)
וב setAttribute, במידה ואני שולח פרמטרים, רק האחרון יתפוס,
לדוגמא, אם הקוד שלי נראה כך:
1 cell.setAttribute("onclick", function() { ShowMsg(i) });
2 function ShowMsg(msg) {
3 alert(msg);
4 }
כל חמש העמודות כשילחצו עליהם יציגו את המספר 5.
והסיבה היא פשוטה.
שורה מספר אחד, מייצרת מתודה אנונימית, בכל פעם שאני משנה את הערך של i בתוך הקריאה אני למעשה משנה את אותו עותק של המתודה האנונימית,
כשלבסוף נשאר לי מתודה שמתיגה את המספר 5.
למעשה אפשר לתרגם את שורה מס' 1, ל
1 var newFunc = function myFunc() { ShowMsg(i); };
2 cell.setAttribute("onclick", newFunc);
למעשה בכל פעם אנחנו משנים את התוכן של הפונקצייה שנקראת myFunc
מה שלכאורה היינו צריכים לעשות זה לייצר רנדומלית שם של פונקצייה, מה שכנראה לא אפשרי.
ולכן הפיתרון שמצאתי הוא כזה.
1 cell.setAttribute("msg", i);
2 cell.setAttribute("onclick", ShowMsg);
3 function ShowMsg() {
4 alert(event.srcElement.msg);
5 }
הרי אני יכול להוסיף כל attribute שעולה על דעתי ולתת איזה ערך שאני רוצה.
אז אני מוסיף attribute שנקרא msg, ונותן לו את ההודעה שאני רוצה להציג למשתמש בזמן לחיצה, (בדוגמא את הערך של i)
והפונקצייה תיקח ממי שקרא לה את הערך מתוך ה attribute.
הנה הקוד המלא:
1 function createAtRunTime() {
2 var table = document.getElementById('tbl').
3 getElementsByTagName("TBODY")[0];
4
5 for (var i = 0; i < 5; i++) {
6 var row = document.createElement("TR")
7 var cell = document.createElement("TD")
8
9 cell.setAttribute("msg", i);
10 cell.setAttribute("onclick", ShowMsg);
11 cell.appendChild(document.createTextNode('shlomo goldberg'));
12
13 row.appendChild(cell);
14 table.appendChild(row);
15 }
16 }
17
18 function ShowMsg() {
19 alert(event.srcElement.msg);
20 }