עבודה עם גריד חכם בצד הלקוח היא הרבה יותר אפקטיבית מאשר עבודה עם גריד צד שרת, כמו זה המובנה בתוך asp.net
יש לא מעט אופציות באינטרנט, ולא פשוט לבחור ביניהן. לאחרונה הטמעתי כזה גריד באפליקציה שאני כותב, והיות וכל כמה חודשים הרכיבים מתעדכנים הייתי חייב לבדוק מחדש מה יש בשוק.
אז ככה. לjQuery UI עדיין אין קומפננטת גריד בחבילה. זה נמצא בתכנון, אבל יש עוד זמן עד שזה יהיה רלוונטי. רמת הגימור ב jQueryUI היא מאוד גבוהה ויש למה לחכות, ולעיתים קרובות ברגע שיוצאת גרסה חדשה היא הופכת לסטנדרט די מהר. בינתיים יש לא מעט רכיבי גריד טובים בשוק שהם פלאגינים מעל jQuery, עם פלוסים ומינוסים לכל אחד.
בדקתי את הגרידים הבאים :
FlexiGrid, jqGrid, SlickGrid, DataTables
גריד אמיתי תומך בעריכה בצד הלקוח, ולפיכך FlexiGrid ו DataTables יורדים. מהרבה בחינות אלו סה”כ טבלאות מסוגננות, כך שזה לא באמת מה שאנחנו מחפשים.
SlickGrid יפהפה, אבל לצערי *הרב* אין לו תמיכה נכון לעכשיו בשפות איזוטריות ולא חשובות שמשום מה כותבים בהן מימין לשמאל. בפרוייקט שלי אני צריך כזו תמיכה (מה לעשות, עברית) אז זה יורד מהפרק, ונשארנו רק עם jqGrid.
התקנת jqGrid :
ההתקנה די פשוטה; בדף ההורדה בוחרים הכל ולוחצים על Download (אפשר לבחור פחות מהכל ואז קבצי הJS והCSS קטנים יותר. לפיתוח ולימוד עדיף להוריד הכל, אבל חשוב לפני העלאה לפרודקשן להוריד רק את המינימום ההכרחי – שימו לב כי הגרסה המכווצת היא של 240KB ג’אווה סקריפט!!).

שימו לב כי חברת Trirand, שמתחזקת את הגריד מוכרת גם רכיבי צד שרת שעוטפים את הגריד. הרכיבים האלו הינם בתשלום, ולדעתי לא טובים יותר מדי (בדקתי רק את הרכיב של MVC). אין שום סיבה לשלם עליהם, והגריד הבסיסי לג’אווה סקריפט הוא חינמי לחלוטין.
בקובץ הזיפ שהורדנו ישנן 4 ספריות:

הקבצים אותם נצטרך הם:
1- ui.jqgrid.css – תחת ספריית הCSS – מכיל את העיצוב.
2. jquery.jqGrid.min.js – קובץ ה JS הראשי של הגריד, תחת ספריית JS.
3. grid.locale-he.js – תחת ספריית js\i18n – מכיל טקסטים בעברית לגריד
4. grid.locale-en.js – תחת ספריית js\i18n – מכיל טקסטים באנגלית (וכמו כן, באותה ספרייה נמצא את קובץ הלוקאליזציה עבור כל שפה נוספת שנרצה).
יחד עם זאת, לjqGrid יש תלות גם ב jQuery, וגם בCSS של jQueryUI -
1. jquery-1.7.min.js – הקובץ הראשי של jQuery. (מצורפת גם גרסה ישנה כלשהי של jQuery בתוך הזיפ)
2. jquery.ui.all.css – קובץ הCSS הראשי של jQuery UI, שלא מצורף בקובץ הזיפ.
על מנת להפעיל את הגריד יש לעשות שלושה דברים, לכתוב את הHTML לגריד, לכתוב את ה JS שמפעיל אותו, ולכתוב את צד השרת. בדוגמה להלן אני משתמש ב ASP.net MVC, אבל אפשר בהתאמות קלות להפעיל גם בכל פלטפורמת צד שרת אחרת)
הפעלת הגריד – הגרסה הנאיבית
1. HTML
לינקים לכל הקבצים הרלוונטים -
1:
2: <link href="../../Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" />
3: <link href="../../Content/ui.jqgrid.css" rel="stylesheet" type="text/css" />
4: <script src="../../Scripts/jquery-1.7.js" type="text/javascript"></script> 1:
2: <script src="../../Scripts/i18n/grid.locale-he.js" type="text/javascript">
1: </script>
2: <!--script src="../../Scripts/i18n/grid.locale-en.js" type="text/javascript"></script-->
3: <script src="../../Scripts/jquery.jqGrid.min.js" type="text/javascript">
</script>
והאלמנטים עליהם “יתלבש” jqGrid :
1: <div>
2:
3: <table id="list" ></table>
4: <div id="pager" ></div>
5:
6: </div>
2. JavaScript :
1: <script type="text/javascript"> 1:
2: $(function () { 3: $("#list").jqGrid({ 4: direction: 'rtl',
5: url: '/DemoGrid/GetAllItems/',
6: datatype: 'json',
7: mtype: 'GET',
8: colNames: ['#', 'שם', 'מחיר'],
9: colModel: [
10: { name: 'Id', index: 'Id', width: 60, align: 'right' }, 11: { name: 'Name', index: 'Name', width: 300, align: 'right', editable: true }, 12: { name: 'Price', index: 'Price', width: 200, align: 'right', editable: true}], 13: pager: $('#pager'), 14: rowNum: 10,
15: rowList: [5, 10, 20, 50],
16: sortname: 'Id',
17: sortorder: "desc",
18: viewrecords: true,
19: caption: 'הגריד הראשון שלי'
20: });
21: });
</script>
יש הרבה מאוד אפשרויות לקנפוג של הגריד, שעל רובם נתעקב בפוסטים אחרים. נכון לעכשיו מה שרלוונטי הוא:
שורה 3- יצירת הגריד על ידי פלאגין של jQuery.
שורה 5 – הURL אליו הגריד יגש על מנת להוריד נתונים בAJAX.
שורה 4 – מגדיר עבודה מימין לשמאל, מתאים לעברית.
שורה 9-12 – מגדיר את השדות והמיקום שלהם בגריד.
3. צד השרת – ממומש בasp.net mvc, אבל כל web service בכל טכנולוגיה אחרת (asp.net, php, ruby) יראה מאוד דומה:
1: public JsonResult GetAllItems()
2: {
3: var jsonItems = GetProductsMock()
4: .Select(p => new
5: {
6: id = p.ID,
7: cell = new[] {
8: p.ID.ToString(),
9: p.Name,
10: p.Price.ToString(),
11: }
12: }).ToArray();
13:
14: var jsonData = new
15: {
16: total = 2,
17: page = 1,
18: records = 10,
19: rows = jsonItems,
20: };
21:
22: return Json(jsonData, JsonRequestBehavior.AllowGet);
23: }
הקוד מחזיר רשימה של מוצרים, בצורה נאיבית, והופך אותם לJson בשביל לשלוח לצד הלקוח.
את ה”מוצרים” פשוט יצרתי תוך כדי ריצה, אך כמובן שבקוד אמיתי היינו נגשים לדטה בייס וכו’
מחלקת המוצר נראית כך:
1: public class Product
2: {
3: public int ID { get; set; }
4: public string Name { get; set; }
5: public double Price { get; set; }
6: }
והקוד שמחזיר רשימת מוצרים (למי שרוצה לשחזר את הקוד אצלו):
1: private List<Product> GetProductsMock()
2: {
3: var products = new List<Product>();
4:
5: products.Add(new Product { ID = 1, Name = "חציל", Price = 4 });
6: products.Add(new Product { ID = 2, Name = "קישוא", Price = 6.5 });
7: products.Add(new Product { ID = 3, Name = "מלפפון", Price = 3.3 });
8: products.Add(new Product { ID = 4, Name = "עגבניה", Price = 5 });
9: products.Add(new Product { ID = 5, Name = "אפרסמון", Price = 12 });
10: products.Add(new Product { ID = 6, Name = "אבטיח", Price = 24 });
11: products.Add(new Product { ID = 7, Name = "ענבים", Price = 22 });
12: products.Add(new Product { ID = 8, Name = "תפוח", Price = 13.2 });
13: products.Add(new Product { ID = 9, Name = "תפוז", Price = 6 });
14: products.Add(new Product { ID = 10, Name = "קלמנטינה", Price = 5.5 });
15: products.Add(new Product { ID = 11, Name = "בטטה", Price = 8 });
16: products.Add(new Product { ID = 12, Name = "תפוח אדמה", Price = 5 });
17: products.Add(new Product { ID = 13, Name = "בצל", Price = 4.4 });
18: products.Add(new Product { ID = 14, Name = "גזר", Price = 6.2 });
19: products.Add(new Product { ID = 15, Name = "אפונה", Price = 19.9 });
20: products.Add(new Product { ID = 16, Name = "כרובית", Price = 18 });
21: products.Add(new Product { ID = 17, Name = "פומלה", Price = 14.7 });
22:
23: return products;
24: }
אם נריץ עכשיו את האפליקציה אז נראה שהכל כבר מחובר, והגריד מראה מוצרים:

אם כי הגריד לא יגיב למיון מחדש או למעבר לדף אחר. כל פעם שננסה לעבור לדף אחר או למיין מחדש, תתבצע קריאה חדשה לGetAllItems, יחד עם פרמטרים רלוונטים (השדה שעל פיו ממיינים, מספר עמוד וכו’)
הפעלה מלאה של הגריד
על מנת שהגריד יגיב כמו שצריך, נשנה את המימוש הנאיבי של המתודה GetAllItems כך שהיא תשתמש בפרמטרים ותחזיר תוצאות רלוונטיות:
1: public JsonResult GetAllItems(JqGridSearchParameters gridSearch)
2: {
3: IEnumerable<Product> qry;
4:
5: if (gridSearch.SortDirection == SortOrder.Ascending)
6: qry = GetProductsMock().OrderBy(p => p.ID);
7: else
8: qry = GetProductsMock().OrderByDescending(p => p.ID);
9:
10: var jsonItems =
11: qry
12: .Skip((gridSearch.CurrentPage - 1) * gridSearch.PageSize)
13: .Take(gridSearch.PageSize)
14: .Select(p => new
15: {
16: p.ID,
17: p.Name,
18: p.Price,
19: }).ToList()
20: .Select(p => new
21: {
22: id = p.ID,
23: cell = new[] {
24: p.ID.ToString(),
25: p.Name,
26: p.Price.ToString(),
27: }
28: }).ToArray();
29:
30:
31: var totalPages = GetProductsMock().Count / gridSearch.PageSize + 1;
32:
33: var jsonData = new
34: {
35: total = totalPages,
36: page = gridSearch.CurrentPage,
37: records = jsonItems.Length,
38: rows = jsonItems,
39: };
40:
41: return Json(jsonData, JsonRequestBehavior.AllowGet);
42: }
JqGridSearchPamaters היא מחלקת עזר שהגדרתי, שמכילה את הפרמטרים שהגריד שולח מצד הלקוח:
1: public class JqGridSearchParameters
2: {
3:
4: public string _search { get; set; }
5: public string nd { get; set; }
6: public int page { get; set; }
7: public int rows { get; set; }
8: public string sidx { get; set; }
9: public string sord { get; set; }
10:
11: public int CurrentPage { get { return page; } }
12: public int PageSize { get { return rows; } }
13: public string SortColumn { get { return sidx; } }
14: public SortOrder SortDirection
15: {
16: get
17: {
18: if (sord == "asc")
19: return SortOrder.Ascending;
20: else
21: return SortOrder.Descending;
22: }
23: }
24:
25:
26: }
27:
28: public enum SortOrder
29: {
30: Ascending,
31: Descending
32: }
עכשיו הגריד יגיב למעבר לדפים אחרים, ובנוסף נוכל למיין, אך המיון תמיד יתבצע על פי ה ID. אפשר לבדוק איזו עמודה נלחצה ועל פי זה לבצע מיון, אך זה לא קוד אלגנטי יותר מדי.
על ידי שימוש ב DynamicLinq (הסבר מפורט בפוסט אחר) אפשר לכתוב קוד אלגנטי יותר ולהחליף את שורות 5-8 ב GetAllItems בשורות הבאות:
1: if (gridSearch.SortDirection == SortOrder.Ascending)
2: qry = GetProductsMock().AsQueryable().OrderBy(gridSearch.SortColumn);
3: else
4: qry = GetProductsMock().AsQueryable().OrderBy(gridSearch.SortColumn + " DESC");
כך שלא משנה מה האובייקטים איתם עובדים – אפשר יהיה למיין על פי כל שדה.
בשלב הזה יהיה לנו גריד פועל, עם תמיכה מלאה בעברית.
הגריד יכול לתמוך בהרבה מאוד אופציות נוספות, עריכה, מחיקה, הוספה, חיפוש וכו’ – בפוסטים הבאים.