Category: การพัฒนา Web Application

  • Bootstrap Modal Full Screen

    หลายๆ ท่านที่เคยใช้งาน Bootstrap เป็น Frontend Framework น่าจะเคยใช้ modal กันมาบ้าง ซึ่ง modal เป็นจาวาสคลิปต์ปลั๊กอิน มีไว้สำหรับการแสดงผลข้อมูล ทั้งรูปภาพ ข้อความ หรือแบบฟอร์มรับข้อมูล ( html input form ) ในลักษณะป๊อปอัพ ซึ่ง modal ของ bootstrap สามารถแสดงผลได้หลายขนาด ทั้งแบบปกติ แบบเล็ก และแบบใหญ่ ขึ้นอยู่กับ class ที่เราสามารถระบุเพิ่มเข้าไปว่าต้องการให้แสดงผลเป็นแบบไหน

    ตัวอย่างโค้ด modal dialog และปุ่มสำหรับเปิด modal

    <!-- Button trigger modal -->
    <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">Modal</button>
    
    <!-- Modal -->
    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    	<div class="modal-dialog" role="document">
    		<div class="modal-content">
    			<div class="modal-header">
    				<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    				<h4 class="modal-title" id="myModalLabel">Modal title</h4>
    			</div>
    			<div class="modal-body">
    				...
    			</div>
    
    		</div>
    	</div>
    </div>
    

    จะได้ผลลัพธ์ดังรูป

    ถ้าต้องการให้ modal แสดงผลใหญ่ขึ้นหรือเล็กลง ให้ระบุ modal-lg modal-sm หลัง modal-dialog ดังตัวอย่าง

    <div class="modal-dialog modal-lg" role="document">
    <div class="modal-dialog modal-sm" role="document">
    

    ถ้าเราต้องการให้ modal สามารถแสดงผลแบบเต็มจอ (full screen) จะไม่สามารถทำได้ (อ้างอิงจากเวอร์ชัน 3.3 ที่ผู้เขียนใช้งาน แต่จากการตรวจสอบล่าสุดพบว่าเวอร์ชัน 5.0 สามารถทำได้แล้ว)

    แต่เราจะใช้ความรู้ในเรื่อง css มาปรับแต่งเพิ่มเติมเพื่อให้สามารถแสดงผลได้ตามความต้องการ โดยเราจะต้องเพิ่ม css class ที่ระบุคุณสมบัติที่จำเป็น ดังตัวอย่าง

    <style>
    .fullscreen {
    	margin: 0;
    	top: 0;
    	left: 0;
    	width: 100% !important;
    	height: 100% !important;
    }
    </style>
    

    ระบุ class fullscreen ไว้ด้านหลัง modal-dialog

    <div class="modal-dialog fullscreen" role="document">

    modal จะได้แสดงผลเต็มจอดังรูป

    และเพื่อให้การแสดงผล modal มีความยืดหยุ่นและมีการทำงานใกล้เคียงกับ dialog ของ Windows ทั่วไป คือสามารถขยายให้เป็น full screen และย่อให้กลับมาขนาดเท่าเดิม โดยสิ่งที่เราต้องทำเพิ่มคือ

    1. เพิ่มปุ่ม fullscreen
      • เมื่อ modal แสดงผลอยู่ในสภาพปกติ
      • เมื่อคลิกปุ่ม fullscreen จะเปลี่ยนการแสดงผล modal ให้เป็นแบบ fullscreen
      • ซ่อนปุ่ม fullscreen และแสดงผลปุ่ม restore แทน
    2. เพิ่มปุ่ม restore
      • เมื่อ modal แสดงผลในรูปแบบ fullscreen
      • เมื่อคลิกปุ่ม restore จะเปลี่ยนการแสดงผล modal กลับไปเป็นสภาพปกติ
      • ซ่อนปุ่ม restore และแสดงผลปุ่ม fullscreen แทน

    โดยมีขั้นตอนดังต่อไปนี้

    1. เพิ่มปุ่ม fullscreen และปุ่ม restore ใน div class=”modal header”

    <div class="modal-header">
            //ปุ่ม Close
    	<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    
            //ปุ่ม restore
    	<button type="button" class="close restore-diloag" title="restore" style="display: none; vertical-align: middle" tabindex="-1"><i class='fa fa-clone' style="font-size: 16px; font-weight: bolder"></i>&nbsp;</button>
    
            //ปุ่ม fullscreen
    	<button type="button" class="close fullscreen-dialog" title="maximize" style="vertical-align: middle" tabindex="-1"><i class='fa fa-window-maximize' style="font-size: 16px"></i>&nbsp;</button>
    	<h4 class="modal-title" id="myModalLabel">Modal title</h4>
    </div>
    

    จะเห็นว่าปุ่มที่เพิ่มขึ้นมาจะมีการระบุชื่อ class “restore-dialog” และ “fullscreen-dialog” ซึ่งจะใช้ในการอ้างถึงในโค้ด jQuery ที่ใช้ควบคุมการทำงานเมื่อมีการคลิกปุ่มนั้นๆ

    2. เนื่องจากผู้เขียนใช้ icon ที่อยู่ใน font awesome ดังนั้นจะต้องเพิ่ม link style sheet เพื่ออ้างไปถึงไฟล์ css ของ font awesome ภายนอกไซต์ที่กำลังพัฒนา (CDN) โดยไปเพิ่มไว้ใน tag <head></head>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />

    3. เพิ่มชุดคำสั่ง jQuery

    <script>
    	$(function () {
    
    		//เมื่อคลิกปุ่ม fullscreen
    		$(document).on('click', '.fullscreen-dialog', function (e) {
    
    			//เพิ่ม class fullscreen เพื่อให้แสดงผลแบบเต็มจอ
    			$('div.modal-dialog').addClass("fullscreen");
    
                            //แสดงปุ่ม restore
    			$('div.modal-dialog').find('.restore-diloag').show();
    
                            //ซ่อนปุ่ม fullscreen
    			$('div.modal-dialog').find('.fullscreen-dialog').hide();
    		});
    
    		//เมื่อคลิกปุ่ม restore
    		$(document).on('click', '.restore-diloag', function (e) {
    
                            //ลบ class fullscreen เพื่อให้กลับไปแสดงผลเหมือนเดิม
    			$('div.modal-dialog').removeClass("fullscreen");
    
                            //ซ่อนปุ่ม restore
    			$('div.modal-dialog').find('.restore-diloag').hide();
    
                            //แสดงปุ่ม fullscreen
    			$('div.modal-dialog').find('.fullscreen-dialog').show();
    		});
    	});
    </script>

    4. ทดสอบ ก็จะได้ผลลัพธ์ดังภาพ

    จะเห็นว่ามีปุ่ม fullscreen แสดงอยู่ เมื่อกด modal จะแสดงผลเป็น fullscreen ดังภาพ

    และเมื่อกดปุ่ม restore หน้าจอ modal ก็จะแสดงผลกลับไปเป็นเหมือนเดิม

    หวังว่าบทความนี้จะเป็นประโยชน์ไม่มากก็น้อย น่าจะพอเป็นแนวทางให้ผู้อ่านนำไปประยุกต์ใช้กับงานของตัวเองนะครับ

    สวัสดีครับ


    แหล่งข้อมูลอ้างอิง

  • จะทำอย่างไรให้สามารถดึงข้อมูลมาแสดงผลด้วย Progress bar โดยใช้ .Net (C#)

              จากบทความก่อนหน้านี้ ผู้เขียนได้แนะนำเกี่ยวกับ Progress bar และวิธีการใช้งานเบื้องต้นกันไปแล้ว ซึ่งใครที่ยังไม่ได้อ่าน สามารถอ่านเพิ่มเติมได้ ที่นี่ มาถึงในบทความนี้ ผู้เขียนจึงขอนำความรู้ดังกล่าวมาต่อยอดประยุกต์ใช้กับการทำงานจริงที่มีการดึงข้อมูลตอน Runtime มาแสดงผลด้วย Progress bar โดยผู้เขียนจะไม่ขอลงรายละเอียดในส่วนของการสร้างสไตล์ชีทและการกำหนดค่าต่างๆแล้ว แต่จะเน้นในส่วนของการดึงข้อมูลมาแสดงแทน โดยผู้เขียนจะพยายามยกตัวอย่างให้เห็นหลายแนว เพื่อให้ผู้อ่านเห็นภาพในการนำไปใช้มากขึ้น ซึ่งแต่ละแบบจะต้องทำอย่างไรบ้าง มาดูกันเลยค่ะ

    แบบแถบละสี

    1. ดึงข้อมูลจากฐานข้อมูล และจัดเตรียม Tag Html ที่จะใช้ในการแสดงผล
        private void getData()
        {
            ////////////////////เป็นการสมมุติการดึงข้อมูลมาใส่ Datatable ที่ชื่อว่า dtProgress ซึ่งเป็นจำนวนของผลไม้แต่ละชนิด
    
            StringBuilder strProgress = new StringBuilder();
            DataTable dtProgress = new DataTable();
            dtProgress.Columns.AddRange(new DataColumn[2] { 
                             new DataColumn("Percent", typeof(int)),
                            new DataColumn("Name",typeof(string))});
    
            dtProgress.Rows.Add(25, "Orange");
            dtProgress.Rows.Add(56, "Grape");
            dtProgress.Rows.Add(45, "Mango");
            dtProgress.Rows.Add(100, "Banana");
          
          ////////////////////เป็นการวนลูปค่าเพื่อสร้างแท็ก html ในการแสดงผลแถบ Progress bar
             int i = 0;
             for ( i = 0; i <= dtProgress.Rows.Count -1; i++) 
             {
             
         ////////////////////เป็นการแสดงชื่อผลไม้แต่ละชนิดบนแถบ Progress bar
                strProgress.Append("<h3 class=\"progress-title\">" + dtProgress.Rows[i]["Name"] + "</h3>");
                strProgress.Append("<div class=\"progress-outer\">");
                strProgress.Append("<div class=\"progress\">");
    
         ////////////////////เป็นการแสดงกำหนดขนาดให้กับแถบสี Progress bar ตามข้อมูล % ในแถวที่วน และมีการ ดึงค่าสไตล์ชีทจากการเรียกใช้ฟังก์ชั่น getCss()
    
    ตามเงื่อนไขของจำนวน % ด้วย
                strProgress.Append("<div class=\"progress-bar progress-bar-striped " + getCss(int.Parse(dtProgress.Rows[i]["Percent"].ToString())) + " \" style=\"width:" + dtProgress.Rows[i]["Percent"] + "%;\"></div>");
    
    
         ////////////////////แสดงจำนวน % ของแต่ละแถบ Progress bar
    
                strProgress.Append("<div class=\"progress-value\"><span>" + dtProgress.Rows[i]["Percent"] + "</span>%</div>");
                strProgress.Append("</div></div>");
             }
    
         ////////////////////นำค่า Tag Html ที่เตรียมไว้ มาแสดงผลด้วย Literal
    
             ltrProgressBar.Text = strProgress.ToString();
    
        }

    2. เมธอดในการแปลงค่าสไตล์ชีทเพื่อปรับสีตามจำนวนที่ส่งมาเป็นพารามิเตอร์

    private string getCss(int Percent)
        {
            string ReturnResult = "";
    
            if (Percent >= 0 && Percent <= 25) 
            {
                ReturnResult = "progress-bar-danger";
            }
            else if (Percent > 25&& Percent <= 50) 
            {
                ReturnResult = "progress-bar-warning"; 
            }
            else if (Percent > 50 && Percent <= 75)
            {
                ReturnResult = "progress-bar-info";
            }
            else if (Percent > 75 && Percent <= 100)
            {
                ReturnResult = "progress-bar-success";
            }
            return ReturnResult;
        }

    จากโค้ดข้างต้นจะเป็นการกำหนดสไตล์ชีทที่จะใช้ ซึ่งจะขึ้นอยู่กับจำนวนค่า % ที่ส่งมาเป็นพารามิเตอร์ โดยจะแบ่งออกเป็น 4 ช่วง

    • สีแดง ช่วงตั้งแต่ 0 – 25 %
    • สีส้ม ช่วงตั้งแต่ 26 – 50 %
    • สีฟ้า ช่วงตั้งแต่ 51 – 75 %
    • สีเขียว ช่วงตั้งแต่ 76 – 100 %

    ตัวอย่างการเรียกใช้งาน

        protected void Page_Load(object sender, EventArgs e)
        {
            getData();
        }

    ผลลัพธ์

    แบบหลายสีในแถบเดียวกัน(แบบที่ 1)

              โดยในตัวอย่างนี้ จะเป็นการแสดงข้อมูลจำนวนผลไม้เป็น % รวมในแถบ Progress bar เดียวกัน ซึ่งจะแยกตามสี และมีบอกจำนวนรวมถึงชื่อผลไม้ให้ทราบ อีกทั้งยังแสดงจำนวนรวมของผลไม้ทุกชนิดด้วย โดยมีวิธีการทำ ดังนี้ค่ะ

    1. ดึงข้อมูลจากฐานข้อมูล และจัดเตรียม Tag Html ที่จะใช้ในการแสดงผล
        private void getMultiFruitColorData()
        {
            StringBuilder strProgress = new StringBuilder();
            DataTable dtProgress = new DataTable();
            dtProgress.Columns.AddRange(new DataColumn[2] { 
                             new DataColumn("Percent", typeof(int)),
                            new DataColumn("Name",typeof(string))});
            dtProgress.Rows.Add(25, "Orange");
            dtProgress.Rows.Add(12, "Grape");
            dtProgress.Rows.Add(7, "Mango");
            dtProgress.Rows.Add(25, "Banana");
    
            int i = 0;
            int percent = 0;
            string CssStr = "";
            int Total = 0;
            
                strProgress.Append("<h3 class=\"progress-title\">Multiple-fruits</h3>");
                strProgress.Append("<div class=\"progress-outer\">");
                strProgress.Append("<div class=\"progress\">");
            for (i = 0; i <= dtProgress.Rows.Count - 1; i++)
            {
                percent = int.Parse(dtProgress.Rows[i]["Percent"].ToString());
    
    
    ////////////////////คำนวณผลรวม % ของผลไม้ทุกชนิดตามการวนรอบที่จะแสดงในแถบ Progress bar
    
                Total += percent;
                switch (i) 
                {
                    case 0: CssStr = "progress-bar-danger"; break;
                    case 1: CssStr = "progress-bar-warning"; break;
                    case 2: CssStr = "progress-bar-info"; break;
                    case 3: CssStr = "progress-bar-success"; break;
                }
    
    ////////////////////เป็นการแสงค่า % ของผลไม้แต่ละชนิดในแถบ Progress bar เดียวกัน โดยแสดงชื่อผลไม้ และจำนวน % ของผลไม้แต่ละชนิดด้วย
    
                strProgress.Append("<div class=\"progress-bar progress-bar-striped " + CssStr + "\" style=\"width:" + percent + "%;\">" + dtProgress.Rows[i]["Name"] + "(" + percent + "%)</div>");
               
            }  
    
     ////////////////////เป็นการแสงผลรวม % ของผลไม้ทุกชนิดในแถบ Progress bar
    
            strProgress.Append("<div class=\"progress-value\"><span>" + Total + "</span>%</div></div>");
            strProgress.Append("</div></div>");
    
            ltrProgressBar.Text = strProgress.ToString();
    
        }
    

              จากโค้ดตัวอย่างข้างต้น จะเห็นว่าการสร้างแท็ก Html จะแตกต่างจากแบบแรก คือจะมีการสร้างใน <div class=\”progress\”> เดียวกัน ซึ่งมีหลักการคล้ายกับการสร้าง Progress bar อย่างง่ายหลายสีในแถบเดียวกันที่เคยกล่าวไว้แล้วในบทความก่อนหน้านั่นเอง

    ผลลัพธ์

    แบบหลายสีในแถบเดียวกันและแสดงหลายแถบ Progress Bar(แบบที่ 2)

              ในตัวอย่างนี้ เป็นการแสดงผลแถบสีแยกตามช่วงของข้อมูลบน Progress bar แต่ละแถบ โดยการแสดงผลจะแบ่งสีตามปริมาณข้อมูลในแต่ละช่วง ดังนี้

    สีแดง ช่วงตั้งแต่ 0 – 25 % สีส้ม ช่วงตั้งแต่ 26 – 50 % สีฟ้า ช่วงตั้งแต่ 51 – 75 % สีเขียว ช่วงตั้งแต่ 76 – 100 %

    หากข้อมูลที่ต้องการแสดงผลตกอยู่ในช่วงใดก็จะมีการแสดงแถบสีนั้นขึ้นมาให้เห็นตามลำดับ โดยมีวิธีการทำต่อไปนี้ค่ะ

    1. ดึงข้อมูลจากฐานข้อมูล และจัดเตรียม Tag Html ที่จะใช้ในการแสดงผล
        private void getMultiColorData()
        {
            StringBuilder strProgress = new StringBuilder();
            DataTable dtProgress = new DataTable();
            dtProgress.Columns.AddRange(new DataColumn[2] { 
                             new DataColumn("Percent", typeof(int)),
                            new DataColumn("Name",typeof(string))});
    
            dtProgress.Rows.Add(25, "Orange");
            dtProgress.Rows.Add(56, "Grape");
            dtProgress.Rows.Add(45, "Mango");
            dtProgress.Rows.Add(100, "Banana");
    
            int i = 0;
            int j = 0;
            int maxRange = 0;
            int percent = 0;
            for (i = 0; i <= dtProgress.Rows.Count - 1; i++)
            {
                percent= int.Parse(dtProgress.Rows[i]["Percent"].ToString());
    
    
    ////////////////////วนเพื่อสร้าง Progress bar ใหม่ในผลไม้แต่ละชนิด
    
                strProgress.Append("<h3 class=\"progress-title\">" + dtProgress.Rows[i]["Name"] + "</h3>");
                strProgress.Append("<div class=\"progress-outer\">");
                strProgress.Append("<div class=\"progress\">");
                maxRange = 0;
    
    ////////////////////คำนวณหาว่าค่าของ % ตกอยู่ในช่วงใด 1-4(เนื่องจากแบ่งออกเป็นช่วงละ 25 % และรวมเป็น 100%)
    
    
                if (percent >= 0 && percent <= 25)
                {
                    maxRange = 1;
                }
                else if (percent > 25 && percent <= 50)
                {
                    maxRange = 2;
                }
                else if (percent > 50 && percent <= 75)
                {
                    maxRange = 3;
                }
                else if (percent > 75 && percent <= 100)
                {
                    maxRange = 4;
                }
    
    ////////////////////วนลูปเพื่อแสดงผลสีในแต่ละช่วงบน Progress bar โดยมีการเรียกใช้งานเมธอด getCssRange()
    
                for (j = 1; j <= maxRange; j++)
                {
                    strProgress.Append(getCssRange(percent, j, maxRange));
                 }
                strProgress.Append("<div class=\"progress-value\"><span>" + dtProgress.Rows[i]["Percent"] + "</span>%</div></div>");
                strProgress.Append("</div></div>");
            }
    
            ltrProgressBar.Text = strProgress.ToString();
    
        }

    2. สร้างเมธอดที่ใช้ในการสร้างแท็ก Html ในการแสดงผลแถบสี ซึ่งในส่วนของกระบวนการคำนวณแถบสีจะไม่ขอลงในรายละเอียด แต่แสดงไว้ให้เห็นภาพการทำงานหลักๆเท่านั้น ดังนี้ค่ะ

        private string getCssRange(int Percent,int Range,int MaxRange)
        {
            string ReturnResult = "";
    
            switch (Range)
            {
                case 1:
                    if (MaxRange > Range)
                        ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-danger\" style=\"width:25%;\"></div>";
    
                    else 
                    {
                        Percent = Percent >= 25 ? 25 : Percent - (25 * (Range - 1));
                    ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-danger\" style=\"width:" + Percent + "%;\"></div>";
                    }
                    break;
                case 2:
                    if (MaxRange > Range)
                        ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-warning\" style=\"width:25%;\"></div>";
    
                    else
                    {
                        Percent = Percent >= 50 ? 50 : Percent - (25 * (Range - 1));
                        ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-warning\" style=\"width:" + Percent + "%;\"></div>";
                    }
                   
                    break;
    
                case 3:
                    if (MaxRange > Range)
                        ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-info\" style=\"width:25%;\"></div>";
    
                    else
                    {
                        Percent = Percent >= 75 ? 75 : Percent- (25* (Range-1));
                        ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-info\" style=\"width:" + Percent + "%;\"></div>";
                    }
                     break;
    
                case 4:
    
                     if (Percent==100)
                         ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-success\" style=\"width:25%;\"></div>";
                     else
                     {
                         Percent =   Percent - (25 * (Range - 1));
                         ReturnResult = "<div class=\"progress-bar progress-bar-striped progress-bar-success \" style=\"width:" + Percent + "%;\"></div>";
                     }
                      break;
    
            }
             return ReturnResult;
        }
    

    ผลลัพธ์

    หมายเหตุ : จากตัวอย่างข้างต้น เป็นเพียงการยกตัวอย่างเพื่อให้ผู้อ่านเข้าใจการประยุกต์ใช้งาน และการทำงานร่วมกับ Progress bar เพิ่มมากขึ้นเท่านั้น ซึ่งผู้อ่านสามารถดัดแปลง และมีวิธีการรวมถึงเทคนิคที่แตกต่างออกไปที่จะนำมาใช้ในการพัฒนาเพื่อแสดงผลข้อมูล ขึ้นกับอัลกอริธึมของแต่ละท่าน

              จากบทความนี้จะเห็นได้ว่า วิธีการดึงข้อมูลมาแสดงผลด้วย Progress bar แบบนี้ จะมีความยืดหยุ่นกว่าแบบที่มีการกำหนดค่าตายตัวในบทความก่อนหน้า อีกทั้งยังสามารถแสดงจำนวนแถบ Progress bar และสีได้ไม่จำกัด ขึ้นอยู่กับข้อมูล การกำหนดเงื่อนไขในการแสดงผล และความต้องการของผู้พัฒนาที่จะดึงข้อมูลมาแสดงผลนั่นเอง และผู้เขียนหวังเป็นอย่างยิ่งว่า บทความนี้ จะพอเป็นแนวทางในการนำไปใช้งานจริงให้กับทุกท่านได้นะคะ ขอบคุณค่ะ ^^

    แหล่งข้อมูลอ้างอิง :

    https://bestjquery.com/tutorial/progress-bar/demo78/

    https://www.jquery-az.com/boots/demo.php?ex=51.0_5

  • มาทำความรู้จักและเรียนรู้การใช้งาน Progress bar ในเบื้องต้นกันเถอะ

              โดยปกติแล้วในการพัฒนาเว็บไซต์ของเรา คงมีบางเวลาที่เราอาจจะอยากแสดงผลข้อมูลของเราในรูปแบบของ Progress bar ซึ่งเป็นแถบของข้อมูล เพื่อเพิ่มมุมมองให้กับการแสดงผลให้ไม่น่าเบื่อจำเจแทนที่จะเป็นเพียงการแสดงผลตัวเลขเฉยๆ โดยเจ้า Progress bar นี้จะทำให้เราเห็นภาพได้ว่า ข้อมูลของเราได้ดำเนินการใกล้ถึงเป้าหมายแล้วหรือยัง ซึ่งขึ้นอยู่กับวัตถุประสงค์ในการนำไปใช้ ดังนั้นในบทความนี้ ผู้เขียนจึงขอแนะนำวิธีการใช้งาน Progress bar แบบเบื้องต้น โดยจะมีขั้นตอนง่ายๆ 3 ขั้นตอน ดังนี้

    1. การกำหนสไตล์ชีท โดยเราจะใช้สไตล์ชีทเหล่านี้ เพื่อช่วยให้การแสดงผลของ Progress bar ของเราสวยงามมากยิ่งขึ้น ซึ่งการกำหนดสไตล์ชีทสามารถทำได้ 2 วิธี คือแบบที่กำหนดในไฟล์เลย หรือแยกเป็นไฟล์สไตล์ชีทต่างหากได้ ซึ่งโดยส่วนตัวผู้เขียนขอแนะนำให้ทำเป็นแบบแยกไฟล์สไตล์ชีทออกมาต่างหากแล้วอ้างถึงจากไฟล์ที่เรียกใช้แทน เพื่อง่ายต่อการปรับปรุง และใช้งานในครั้งต่อไปค่ะ

    ไฟล์ Progress.css

      .progress-title {
        font-size: 18px;
        font-weight: 700;
        color: #000;
        margin: 0 0 10px;
      }
    
    .progress-outer {
        background: #fff;
        padding: 5px 60px 5px 5px;
        border: 5px solid #bebfbf;
        border-radius: 45px;
        margin-bottom: 20px;
        position: relative;
    }
    
    .progress {
        background: #bebfbf;
        border-radius: 20px;
        margin: 0;
    }
    
        .progress .progress-bar {
            border-radius: 20px;
            box-shadow: none;
            animation: animate-positive 2s;
        }
    
        .progress .progress-value {
            font-size: 20px;
            font-weight: 700;
            color: #6b7880;
            position: absolute;
            top: 3px;
            right: 10px;
        }
    
        .progress-bar.active{
        animation: reverse progress-bar-stripes 0.40s linear infinite, animate-positive 2s;
        }
       @-webkit-keyframes animate-positive{
        0% { width: 0%; }
        }
       @keyframes animate-positive {
        0% { width: 0%; }
        }
    
       .progress-bar-striped {
        background-image: linear-gradient(
    45deg
    ,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);
        background-size: 1rem 1rem;
      }
      .progress-bar {
        display: -ms-flexbox;
        display: flex;
        -ms-flex-direction: column;
        flex-direction: column;
        -ms-flex-pack: center;
        justify-content: center;
        overflow: hidden;
        color: #fff;
        text-align: center;
        white-space: nowrap;
         transition: width .6s ease;
       }
       .progress {
        display: -ms-flexbox;
        display: flex;
        height: 1rem;
        overflow: hidden;
        font-size: .75rem;
        background-color: #e9ecef;
        border-radius: .25rem;
        box-shadow: inset 0 0.1rem 0.1rem rgb(0 0 0 / 10%);
        }
     

    เพิ่มเติม : การอ้างอิงไฟล์สไตล์ชีทจากภายนอก โดยที่อยู่ของไฟล์ก็ขึ้นกับการระบุของแต่ละท่าน

    <link href="dist/css/Progress.css" rel="stylesheet">

    2. การกำหนดพื้นที่ในการแสดงผล Progress bar ในส่วนของแท็ก body ในไฟล์ html

    <div class="container">
        <div class="row">
            <div class="col-md-6">
    
             <!-- progress bar-->
                <h3 class="progress-title">Basic Progress</h3>  <!-- progress bar Title-->
                <div class="progress-outer">
                    <div class="progress">
                        <!-- กำหนดสไตล์ชีทเพื่อแสดงแถบสี และขนาดของ progress bar -->
                        <div class="progress-bar progress-bar-striped progress-bar-info" style="width:85%;"></div>
                       <div class="progress-value"><span>85</span>%</div> <!-- แสดงข้อความจำนวน % บน progress bar -->
                    </div>
                </div>
            <!-- End progress bar-->
          
            </div>
        </div>
    </div>

    คำอธิบาย : จากตัวอย่าง จะเห็นว่าเราสามารถปรับแต่งและใส่ข้อมูลให้กับ Progress bar 3 ส่วนคือ

    • ข้อความบนแถบ Progress bar ได้ในส่วนของ Progress-title คือ <h3 class=”progress-title”>Basic Progress</h3>
    • กำหนดความกว้างของ Progress bar ได้ผ่านทาง style-inline คือ style=”width:85%;
    • แสดงข้อความจำนวนของข้อมูลบนแถบ Progress bar คือ <div class=”progress-value“><span>85</span>%</div> นั่นเอง

    3. การเรียกใช้งาน jQuery เพื่อการแสดงผล Progress bar ของเราให้มีการเพิ่มขึ้นของจำนวนเลขที่แสดงตั้งแต่ 0 จนถึงจำนวนเลขนั้น เช่น หากเลขที่ต้องการแสดงคือ 60% ตัวเลขแสดงจำนวนดังกล่าวจะค่อยๆเปลี่ยนแปลงเพิ่มขึ้นโดยเริ่มจาก 0 จนถึง 60 นั่นเอง

    <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
     <script>
    $(document).ready(function(){
        $('.progress-value > span').each(function(){
            $(this).prop('Counter',0).animate({
                Counter: $(this).text()
            },{
                duration: 1500,
                easing: 'swing',
                step: function (now){
                    $(this).text(Math.ceil(now));
                }
            });
        });
    });
     </script>

    ผลลัพธ์

    เพิ่มเติม
              จากตัวอย่างข้างต้น จะเป็นการแสดงผล Progress bar แบบพื้นฐานอย่างง่าย เพียงเท่านี้ท่านก็จะสร้าง Progress bar ได้ด้วยตนเองแล้ว แต่หากท่านใดที่อยากเพิ่มสีสันและความสวยงามให้กับ Progress bar ของท่าน ก็สามารถทำได้ดังตัวอย่างนี้ค่ะ
    1. ปรับแก้เพิ่มเติมในส่วนของการกำหนดพื้นที่ในการแสดงผล

    <div class="container">
        <div class="row">
            <div class="col-md-6">
    
             <!-- progress bar-->
                <h3 class="progress-title">Progress1</h3>  <!-- progress bar Title-->
                <div class="progress-outer">
                    <div class="progress">
                        <!-- กำหนดสไตล์ชีทเพื่อแสดงแถบสี และขนาดของ progress bar -->
                        <div class="progress-bar progress-bar-striped progress-bar-danger" style="width:25%;"></div>
                       <div class="progress-value"><span>25</span>%</div> <!-- แสดงข้อความจำนวน % บน progress bar -->
                    </div>
                </div>
    
            <!-- End progress bar-->
                <h3 class="progress-title">Progress2</h3>
                <div class="progress-outer">
                    <div class="progress">
                        <div class="progress-bar progress-bar-striped progress-bar-warning" style="width:50%;"></div>
                        <div class="progress-value"><span>50</span>%</div>
                    </div>
                </div>
                <h3 class="progress-title">Progress3</h3>
                <div class="progress-outer">
                    <div class="progress">
                        <div class="progress-bar progress-bar-striped progress-bar-info" style="width:75%;"></div>
                        <div class="progress-value"><span>75</span>%</div>
                    </div>
                </div>
                <h3 class="progress-title">Progress4</h3>
                 <div class="progress-outer">
                    <div class="progress">
                        <div class="progress-bar progress-bar-striped progress-bar-success" style="width:90%;"></div>
                        <div class="progress-value"><span>90</span>%</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    2. เพิ่มสไตล์ชีทที่ใช้สำหรับเพิ่มสีสันให้กับ Progress bar ของเรา

    .progress-bar-danger {
        background-color: #d9534f;
    }
    .progress-bar-warning {
        background-color: #f0ad4e;
    }
    .progress-bar-success {
        background-color: #5cb85c;
    }
    .progress-bar-info {
        background-color: #5bc0de;
    }

    ผลลัพธ์

              จากตัวอย่างข้างต้น จะเป็นวิธีการสร้าง Progress bar ที่มีการใส่สีสันให้กับแต่ละแถบเส้น แต่ลูกเล่นของการแสดงผล Progress bar ยังสามารถทำได้หลายแบบ ซึ่งผู้เขียนจะขอแนะนำอีกวิธี ซึ่งเป็นการสร้าง Progress bar แบบหลายสีในแถบเดียวกันโดยมีวิธีการเพิ่มเติม ดังนี้ค่ะ

    การกำหนดพื้นที่ในการแสดงผล Progress bar ในส่วนของแท็ก body ในไฟล์ html

    <div class="container">
        <div class="row">
            <div class="col-md-6">
    
                  <h3 class="progress-title">Multiple-color Progress</h3>
                    <div class="progress-outer">
                <!-- การกำหนดแถบสีใน 1 แถบ progress bar-->
                        <div class="progress">
    
                            <!-- แถบสีแดงใน progress bar ขนาด 25%-->
                            <div class="progress-bar progress-bar-danger progress-bar-striped" style="width: 25%">25%
                            </div>
                              <!-- แถบสีส้มใน progress bar ขนาด 25%-->
                            <div class="progress-bar progress-bar-warning progress-bar-striped" style="width: 25%">50%
                            </div>
                             <!-- แถบสีฟ้าใน progress bar ขนาด 25%-->
                            <div class="progress-bar progress-bar-info progress-bar-striped " style="width: 25%">75%
                            </div>
                             <!-- แถบสีเขียวใน progress bar ขนาด 25%-->
                            <div class="progress-bar progress-bar-success progress-bar-striped active" style="width: 10%">10%
                            </div>
                            <div class="progress-value">
                                <span>85</span>%</div>
                        </div>
                    </div>
          
            </div>
        </div>
    </div>

              จากโค้ดตัวอย่างข้างต้น จะสังเกตเห็นว่าการกำหนดค่าต่างๆจะมีลักษณะกับหลักการที่กล่าวไว้แล้วข้างต้น แต่จะแตกต่างกันตรงที่การแสดงผลหลายแถบสีในแถบเดียวกันจะมีการกำหนด progress bar ภายใต้แท็ก <div class=”progress”> เดียวกัน และหากต้องการกำหนดให้มีกี่แถบสีก็สามารถเพิ่มสี และกำหนดขนาดของแต่ละแถบสีได้ตามต้องการ

    ผลลัพธ์

              โดยบทความนี้ก็ถือเป็นเพียงส่วนหนึ่งของการแนะนำการใช้งาน รวมถึงลูกเล่นของ Progress bar ในเบื้องต้นเท่านั้น เนื่องจากรูปแบบและการใช้งานของ Progress bar ยังมีให้เลือกใช้ เลือกลองกันอีกมากมายหลายแบบเลยนะคะ ผู้เขียนหวังว่าความรู้จากบทความนี้จะเป็นพื้นฐานและตัวช่วยให้กับนักพัฒนาสามารถนำไปประยุกต์ใช้ในงานของตนได้ไม่มากก็น้อยค่ะ ^^

    แหล่งข้อมูลอ้างอิง :

    https://bestjquery.com/tutorial/progress-bar/demo78/

    https://www.jquery-az.com/boots/demo.php?ex=51.0_5

  • รู้จักเอแจ๊กซ์ (AJAX) และการใช้งาน

    AJAX ย่อมาจากคำว่า Asynchronous JavaScript and XML ซึ่งหมายถึงการพัฒนาเว็บแอพพลิเคชั่นที่ประมวลผลในเบื้องหลังเป็นเทคนิคในการพัฒนาเว็บแอปพลิเคชันเพื่อให้สามารถโต้ตอบกับผู้ใช้ได้ดีขึ้น ทำให้ความรู้สึกการใช้งานโปรแกรมเหมือนกับเดสก์ท็อปแอปพลิเคชัน

    ปกติแล้วในภาษาสคริปต์ที่ใช้งานกับเว็บไซต์จะมีการทำงานประมวลผลแบบเป็นลำดับ (synchronous) โดยที่คำสั่งแรกจะต้องประมวลผลให้เสร็จสิ้นก่อนแล้วถึงจะทำงานในคำสั่งถัดไป แต่กระบวนการทำงานแบบเอแจ๊กซ์เมื่อบราวเซอร์ (Browser) ร้องขอข้อมูลไปยังเซิร์ฟเวอร์ (Server) บราวเซอร์จะไปทำงานคำสั่งถัดไปทันที (asynchronous) โดยที่ไม่ต้องรอการตอบกลับจากเซิร์ฟเวอร์ก่อน

    ทำให้การตอบสนองต่อผู้ใช้งานดูรวดเร็วขึ้น และเมื่อเซิร์ฟเวอร์ประมวลผลเสร็จแล้วถึงจะส่งข้อมูลกลับมาที่เอแจ๊กซ์และให้เอแจ๊กซ์ทำงานกับข้อมูลที่ส่งกลับมาอีกทีซึ่งสามารถเขียนโค้คการทำงานดังนี้

    ตัวอย่างโค้คการทำงาน AJAX ของโดยใช้ jQuery

    $.ajax({
        	type: 'GET',
        	url: 'send-ajax-data.php',
        	dataType: "JSON", // data type expected from server
        	success: function (data) {
               	console.log(data);
        	},
        	error: function(error) {
               	console.log('Error: ' + error);
        	}
    });
    

    และปัจจุบันในการเขียน JavaScript เพื่อเรียกใช้งาน AJAX นั้นเราไม่จำเป็นต้องพึ่งพา jQuery อีกต่อไปแล้วซึ่งสามารถเขียนโค้ดการทำงานได้ดังนี้

    วิธีที่ 1  ใช้ XMLHttpRequest [1]

    var request = new XMLHttpRequest();
    request.open('GET','https://tutorialzine.com/misc/files/my_url.html', true);
    
    request.onload = function (e) {
        if (request.readyState === 4) {
    
            // Check if the get was successful
            if (request.status === 200) {
                console.log(request.responseText);
            } else {
                console.error(request.statusText);
            }
        }
    };
    
    // Catch errors:
    request.onerror = function (e) {
        console.error(request.statusText);
    };
    
    request.send(null);
    

    วิธีที่ 2 ใช้ Fetch API [2]

    fetch('./api/some.json')
      .then(
        function(response) {
          if (response.status !== 200) {
            console.log('Looks like there was a problem. Status Code:' +
     response.status);
            return;
          }
    
          // Examine the text in the response
          response.json().then(function(data) {
            console.log(data);
          });
        }
      )
      .catch(function(err) {
        console.log('Fetch Error :-S', err);
      });
    

    อ้างอิง:

    https://tutorialzine.com/2014/06/10-tips-for-writing-javascript-without-jquery [1]

    https://developers.google.com/web/updates/2015/03/introduction-to-fetch [2]

    https://www.javascripttutorial.net/javascript-fetch-api/  

    วิดีโอ: https://www.youtube.com/watch?v=F1TECaRf-uA&feature=youtu.be&t=2375

  • อยากดึงข้อมูลมาแสดงใน TreeView จะทำอย่างไรดี?

              ในบทความนี้ ผู้เขียนก็ยังคงอยู่ในเรื่องของ TreeView เช่นเคย เพื่อต่อยอดจากบทความก่อนในหัวข้อเรื่อง “มาทำความรู้จักกับพื้นฐานการใช้งาน “TreeView” สำหรับมือใหม่กันดีกว่า” ที่เป็นบทความเกี่ยวกับเรื่องการแนะนำวิธีจัดการกับ TreeView ด้วยการกำหนดคุณสมบัติต่างๆ แต่งสีเติมกลิ่น ให้ TreeView ของเราน่าสนใจยิ่งขึ้น แต่ข้อมูลที่นำมาใช้ในการแสดงผลยังคงเป็นในลักษณะกำหนดเองเป็นค่าตายตัวจากหน้าจอและยังไม่เน้นเรื่องดึงข้อมูลจากฐานข้อมูล ในบทความนี้จึงถือเป็นภาคต่อจากบทความที่แล้วและขอเน้นในส่วนของการดึงข้อมูลมาแสดงผลบน TreeView ในเชิงโปรแกรมกันบ้าง เพื่อให้ผู้อ่านได้ความรู้ทั้งในส่วนการกำหนดคุณสมบัติและการดึงข้อมูลมาแสดงไปประยุกต์ใช้ในงานพัฒนาร่วมกันได้

    ขั้นตอนในการดึงข้อมูลจากฐานข้อมูลมาแสดงใน TreeView

    1. สร้าง TreeView ที่ต้องการใช้ในการแสดงผลข้อมูล
      ตัวอย่าง code ในฝั่ง Client
      <body>
      <form id="form1" runat="server">
      <asp:TreeView ID="TvOrganization" runat="server" >
      </asp:TreeView>
      </form>
      </body>
    2. ติดต่อฐานข้อมูลเพื่อใช้ในการแสดงผล ซึ่งในตัวอย่างนี้จะขอสมมุติข้อมูลจาก datatable ที่สร้างขึ้นแทน
      ตัวอย่าง code ในฝั่ง Server (C#)
      • ฟังก์ชั่นตอน Page_Load
      protected void Page_Load(object sender, EventArgs e)
          {
              if (!this.IsPostBack)
              {   ///////ดึงข้อมูลวิทยาเขต โดยในการใช้งานจริงจะเป็นการติดต่อกับฐานข้อมูลเพื่อดึงค่าวิทยาเขตมาแสดง
                  DataTable dt = this.GetCampusData();
              
      ///////เรียกใช้งานฟังก์ชั่น PopulateTreeView() เพื่อนำค่าข้อมูลวิทยาเขตมาแสดงผลใน TreeView 
      โดยในกรณีนี้จะเริ่มสร้างจาก root node โดยส่งค่าพารามิเตอร์ของ parentId เป็น 0
                  this.PopulateTreeView(dt, 0, null);
              }
          }
      • ฟังก์ชั่นดึงข้อมูลวิทยาเขตและคณะ/หน่วยงาน
      private DataTable GetCampusData() {
       ///////เตรียมข้อมูลวิทยาเขต เนื่องจากในกรณีนี้เป็นการสมมุติโครงสร้างและข้อมูลวิทยาเขตโดยสร้างเป็น DataTable 
      เสมือนเป็นตารางวิทยาเขตในฐานข้อมูล
      DataTable dtCampus = new DataTable();
      dtCampus.Columns.AddRange(new DataColumn[2] {
      new DataColumn("CampID", typeof(int)), 
      new DataColumn("CampNameThai",typeof(string)) }); 
      dtCampus.Rows.Add("01", "วิทยาเขตหาดใหญ่"); 
      dtCampus.Rows.Add("02", "วิทยาเขตปัตตานี");
      dtCampus.Rows.Add("03", "วิทยาเขตภูเก็ต"); 
      dtCampus.Rows.Add("04", "วิทยาเขตสุราษฎร์ธานี");
      dtCampus.Rows.Add("05", "วิทยาเขตตรัง"); return dtCampus; } private DataTable GetFacultyData() { ///////เตรียมข้อมูลคณะ/หน่วยงาน ในกรณีนี้เป็นการสมมุติโครงสร้างข้อมูลคณะ/หน่วยงานและสร้างเป็น DataTable โดยมีการระบุรหัสของวิทยาเขตไว้ด้วย ซึ่งในการทำงานจริงจะเป็นการดึงข้อมูลจากตารางที่เก็บข้อมูลคณะ/หน่วยงานแทน DataTable dtFaculty = new DataTable(); dtFaculty.Columns.AddRange(new DataColumn[3] { new DataColumn("FacID", typeof(int)), new DataColumn("FacNameThai",typeof(string)) , new DataColumn("CampID",typeof(string)) }); dtFaculty.Rows.Add("01", "สำนักงานอธิการบดี","01"); dtFaculty.Rows.Add("02", "ศูนย์คอมพิวเตอร์", "01"); dtFaculty.Rows.Add("03", "วิศวกรรมศาสตร์", "01"); dtFaculty.Rows.Add("54", "คณะรัฐศาสตร์", "02"); dtFaculty.Rows.Add("07", "ศึกษาศาสตร์", "02"); dtFaculty.Rows.Add("36", "วิทยาการสื่อสาร", "02"); dtFaculty.Rows.Add("81", "ศูนย์การเรียนรู้", "03"); dtFaculty.Rows.Add("56", "คณะศิลปศาสตร์และวิทยาศาสตร์", "04"); dtFaculty.Rows.Add("44", "คณะเทคโนโลยีและการจัดการ", "04"); dtFaculty.Rows.Add("46", "คณะพาณิชยศาสตร์และการจัดการ", "05"); dtFaculty.Rows.Add("66", "คณะสถาปัตยกรรมศาสตร์", "05"); return dtFaculty; }
      • ฟังก์ชั่นที่ใช้ในการวนแสดงข้อมูลที่ได้จากวิทยาเขตและคณะ/หน่วยงานมาแสดงใน TreeView
      private void PopulateTreeView(DataTable dtParent, int parentId, TreeNode treeNode)
      {
      ///////ดึงค่าข้อมูลคณะ/หน่วยงาน
      DataTable dtChild = this.GetFacultyData();
      DataRow[] drChild;
      
      ///////วนค่าข้อมูลวิทยาเขตจาก dtParent ที่เป็นพารามิเตอร์ที่ส่งมา
      foreach (DataRow row in dtParent.Rows)
      {
      
      if (parentId == 0) ///////กรณีที่เป็น root node ค่าของ parentId จะเท่ากับ 0 ซึ่งในที่นี้หมายถึง node วิทยาเขต นั่นเอง
      {
         TreeNode child = new TreeNode
        {  ///////กำหนดคุณสมบัติให้กับ root node ในส่วนของ Text,Value,ToolTip,SelectAction ตอน runtime 
      ขึ้นอยู่กับเงื่อนไขและจุดประสงค์ที่เราต้องการให้แสดงผล โดยในที่นี้จะนำค่าข้อมูลจากวิทยาเขตมาวนแสดง
      
      ///////สามารถกำหนด Style ตอนระบุ Text ได้ด้วย โดยในกรณีนี้ใส่ style ในแท็ก <span></span> นั่นเอง
          Text = "<span style='color:blue;font-weight:bold'>" + row["CampNameThai"].ToString() + "</span>" ,  
      
      ///////กำหนดค่าของ node เป็นรหัสวิทยาเขต
          Value = row["CampID"].ToString(),
      
      //////ระบุให้ ToolTip เป็นชื่อวิทยาเขต[รหัสวิทยาเขต]
          ToolTip = row["CampNameThai"].ToString() + "[" + row["CampID"].ToString() +"]", 
      
      ///////ระบุคุณสมบัติไม่ให้เลือกได้
          SelectAction = TreeNodeSelectAction.None, 
         };
      ///////เมื่อระบุคุณสมบัติและกำหนดค่าเรียบร้อยแล้วจะเพิ่ม node ดังกล่าวลงใน TreeView ที่ชื่อว่า TvOrganization
        TvOrganization.Nodes.Add(child); 
      
      ///////ดึงข้อมูลคณะ/หน่วยงานตามวิทยาเขตที่กำลังวนค่าซึ่งก็คือ row["CampID"].ToString()
        drChild = dtChild.Select("CampID=" + row["CampID"].ToString());
      
      ///////เรียกใช้ฟังก์ชั่น PopulateTreeView() โดยส่งค่าข้อมูลคณะ/หน่วยงานของวิทยาเขตที่กำลังวน(ตัวแปร drChild.CopyToDataTable())
      เพื่อวนสร้าง node ย่อยเพิ่มลงไปใน node วิทยาเขตที่กำลังจัดการ(ตัวแปร child)
      PopulateTreeView(drChild.CopyToDataTable(), int.Parse(child.Value), child); }
      else ///////กรณีที่เป็นการจัดการ node ย่อย ซึ่งในที่นี้หมายถึง node คณะ/หน่วยงาน { TreeNode child = new TreeNode { ///////กำหนดคุณสมบัติให้กับ node ย่อย
      ในส่วนของ Text,Value,ToolTip,SelectAction,ImageUrl,NavigateUrl,Target ตอน runtime ขึ้นอยู่กับเงื่อนไขและจุดประสงค์ที่เราต้องการให้แสดงผล โดยในที่นี้จะนำค่าข้อมูลจากคณะ/หน่วยงานมาวนแสดง
      ///////แสดงค่าข้อมูลคณะ/หน่วยงานที่กำลังวน Text = row["FacNameThai"].ToString() , ///////แสดงค่าข้อมูลรหัสคณะ/หน่วยงานที่กำลังวน Value = row["FacID"].ToString(), //////ระบุให้ ToolTip เป็นชื่อคณะ/หน่วยงาน[รหัสคณะ/หน่วยงาน] ToolTip = row["FacNameThai"].ToString() + "[" + row["FacID"].ToString() + "]", ///////ระบุคุณสมบัติไม่ให้สามารถคลิกเลือก node ได้ SelectAction = TreeNodeSelectAction.Select, ///////ระบุ url ของเพจที่ต้องการให้ลิงค์ไปโดยส่งค่าพารามิเตอร์ของรหัสคณะ/หน่วยงานไปด้วยกรณีที่ต้องการนำค่าข้อมูลไปใช้ต่อในเพจดังกล่าว NavigateUrl = "BasicTreeviewAll.aspx?FacId=" + row["FacID"].ToString(), ///////กำหนดให้เปิดเพจใหม่ Target="_blank", ///////กำหนดให้แสดงรูปภาพดาวหน้าข้อความใน node ดังกล่าว ImageUrl = "~/images/star.png", }; ///////เมื่อระบุคุณสมบัติและกำหนดค่าเรียบร้อยแล้วจะเพิ่ม node ดังกล่าวลงใน ตัวแปร treeNode(ซึ่งก็คือ node แม่ที่ถูกส่งมานั่นเอง) ซึ่งเป็นพารามิเตอร์ที่ส่งมาตอนเรียกใช้ฟังก์ชั่น PopulateTreeView() แต่ถ้าเป็นกรณี เรียกใช้ฟังก์ชั่นเพื่อสร้าง root node ค่า treeNode ที่ส่งมานี้จะเป็น null treeNode.ChildNodes.Add(child); } } }

      หมายเหตุ :
      1) การกำหนดคุณสมบัติให้กับ node ตอน RunTime เราสามารถเลือกระบุคุณสมบัติได้เช่นเดียวกับตอนกำหนดฝั่ง Client ที่เคยกล่าวไว้ในบทความก่อน โดย properties ที่สามารถระบุได้ขึ้นอยู่กับความต้องการของผู้ใช้ มีดังนี้

      2) การประยุกต์ใช้งานและการดึงข้อมูลที่จะนำมาวนแสดงสามารถปรับเปลี่ยนในแบบที่ท่านต้องการ เพื่อเพิ่มประสิทธิภาพในการทำงานของโปรแกรมให้รวดเร็วขึ้นได้ โดยกรณีนี้เพียงยกตัวอย่างเพื่อเน้นให้ดูการวนมาแสดงใน TreeView เท่านั้น

      ตัวอย่างแสดงผลลัพธ์ของการดึงข้อมูลมาแสดงใน TreeView จากโค้ดข้างต้น


              นอกจากนี้ ท่านยังสามารถเพิ่มความสามารถให้กับ TreeView ของท่านได้อีกหน่อยในกรณีที่ TreeView ที่ต้องการจัดการมี check box และต้องการให้สามารถเลือก node แม่และสามารถเลือก node ลูกทั้งหมดด้วยได้ (ลักษณะคล้ายกับแบบ Select All นั่นเอง) โดยใช้  jQuery เข้ามาช่วย โดยเพิ่ม code ที่เป็น jQuery  ดังนี้ ค่ะ

    1. อ้างอิงไฟล์ที่ใช้ในการทำงานร่วมกับ jQuery
      <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    2. ส่วนของ jQuery ที่ใช้ในการเลือกแบบ Select All ให้กับ node แม่และลูก
      <script type="text/javascript">
          $(function () {
              $("[id*=TvOrganization] 
      ////ทุกครั้งที่คอนโทรลที่มีชนิดเป็น checkbox ถูกคลิก
      input[type=checkbox]").bind("click", function () {
      ////จะหา tag table ที่ใกล้ที่สุด เพื่อแยกระหว่าง node แม่(วิทยาเขต)และลูก(คณะ/หน่วยงาน)
                  var table = $(this).closest("table");
                  if (table.next().length > 0 && table.next()[0].tagName == "DIV") {
                    ////เป็นการตรวจสอบว่าเป็น node ที่เป็นแม่หรือไม่
      โดยตรวจสอบว่าต้องเจอแท็ก table ถัดไป และแท็ก table ดังกล่าวต้องมีแท็ก DIV อยู่ด้วย
      var childDiv = table.next();

      ////นำค่าการเช็คของ check box ดังกล่าว มาใส่ไว้ในตัวแปร isChecked var isChecked = $(this).is(":checked");

      ////นำค่าจากตัวแปร isChecked ไปเซ็ทการเช็คหรือไม่เช็คใน check box ใน node ลูกทั้งหมด $("input[type=checkbox]", childDiv).each(function () { if (isChecked) { $(this).attr("checked", "checked"); } else { $(this).removeAttr("checked"); } }); } else { ////กรณีที่เป็น node ย่อยหรือ node ลูก var parentDIV = $(this).closest("DIV");

       ////ถ้าค่าของจำนวน node ย่อย เท่ากับจำนวนของการเช็คใน node ย่อยจะไปเช็ค check box ตัวแม่ด้วย
      แต่ถ้าไม่เท่ากันจะไปติ๊กเลือกออกจาก check box ตัวแม่ให้อัตโนมัติ
      if ($("input[type=checkbox]", parentDIV).length ==
      $("input[type=checkbox]:checked", parentDIV).length)
      { $("input[type=checkbox]", parentDIV.prev()).attr("checked", "checked"); } else { $("input[type=checkbox]", parentDIV.prev()).removeAttr("checked"); } } }); }) </script>

      คำอธิบายเพิ่มเติม :
             จากโค้ดของ jQuery เบื้องต้น ที่มีการแยกระหว่างส่วนของ node แม่และลูก เนื่องจากเมื่อดูจากโครงสร้าง Tag HTML ของ TreeView ที่ถูกสร้างขึ้นเมื่อทำการรันโปรแกรมเพื่อแสดงผล จะสังเกตว่าจะมีการสร้างเป็น Tag HTML ในลักษณะดังนี้

      ////ส่วนของการแสดงผล node แม่(วิทยาเขต) โดยในที่นี้คือ วิทยาเขตตรัง
      <table cellpadding="0" cellspacing="0" style="border-width:0;">
      <tbody>
      <tr>
      <td><a id="TvOrganizationn13"
      href="javascript:TreeView_ToggleNode(TvOrganization_Data,13,document.getElementById('TvOrganizationn13'),' '
      ,document.getElementById('TvOrganizationn13Nodes'))">
      <img src="xxxx" alt="Collapse <span style='color:blue;font-weight:bold'>วิทยาเขตตรัง</span>"
      style="border-width:0;">
      </a></td>
      <td style="white-space:nowrap;"><input type="checkbox" name="TvOrganizationn13CheckBox"
      id="TvOrganizationn13CheckBox"
      title="วิทยาเขตตรัง[5]"><span class="TvOrganization_0" title="วิทยาเขตตรัง[5]" id="TvOrganizationt13">
      <span style="color:blue;font-weight:bold">วิทยาเขตตรัง</span></span></td>
      </tr>
      </tbody>
      </table>

      ////ส่วนของการแสดงผล node ลูก(คณะ/หน่วยงาน) จะมีแท็ก DIV คั่นอยู่ ก่อนจะเจอแท็ก <table></table>ของ node ลูก

      <div id="TvOrganizationn13Nodes" style="display:block;">
      ////ในที่นี้จะมี 2 คณะ/หน่วยงานในวิทยาเขตตรัง คือ คณะพาณิชยศาสตร์และการจัดการ และคณะสถาปัตยกรรมศาสตร์
      ////คณะพาณิชยศาสตร์และการจัดการ
      <table cellpadding="0" cellspacing="0" style="border-width:0;">
      <tbody>
      <tr>
      <td><div style="width:20px;height:1px"></div></td>
      <td><img src="xxx" alt=""></td>
      <td><a href="BasicTreeviewAll.aspx?FacId=46" target="_blank"
      onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt14');"
      title="คณะพาณิชยศาสตร์และการจัดการ[46]" id="TvOrganizationt14i" tabindex="-1">
      <img src="images/star.png" alt="" style="border-width:0;"></a></td>
      <td style="white-space:nowrap;"><input type="checkbox" name="TvOrganizationn14CheckBox"
      id="TvOrganizationn14CheckBox" title="คณะพาณิชยศาสตร์และการจัดการ[46]">
      <a class="TvOrganization_0" href="BasicTreeviewAll.aspx?FacId=46" target="_blank"
      onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt14');"
      title="คณะพาณิชยศาสตร์และการจัดการ[46]" id="TvOrganizationt14">คณะพาณิชยศาสตร์และการจัดการ</a></td>
      </tr>
      </tbody>
      </table>
      ////คณะคณะสถาปัตยกรรมศาสตร์
      <table cellpadding="0" cellspacing="0" style="border-width:0;">
      <tbody>
      <tr>
      <td><div style="width:20px;height:1px"></div></td>
      <td><img src="xxxx" alt=""></td>
      <td><a href="BasicTreeviewAll.aspx?FacId=66" target="_blank"
      onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt15');"
      title="คณะสถาปัตยกรรมศาสตร์[66]" id="TvOrganizationt15i" tabindex="-1">
      <img src="images/star.png" alt="" style="border-width:0;"></a></td>
      <td style="white-space:nowrap;"><input type="checkbox" name="TvOrganizationn15CheckBox"
      id="TvOrganizationn15CheckBox" title="คณะสถาปัตยกรรมศาสตร์[66]">
      <a class="TvOrganization_0" href="BasicTreeviewAll.aspx?FacId=66" target="_blank"
      onclick="javascript:TreeView_SelectNode(TvOrganization_Data, this,'TvOrganizationt15');"
      title="คณะสถาปัตยกรรมศาสตร์[66]" id="TvOrganizationt15">คณะสถาปัตยกรรมศาสตร์</a></td>
      </tr>
      </tbody>
      </table>
      </div>

                จากแถบสีที่เน้นไว้ใน tag HTML ข้างต้น จะเห็นว่า  node แม่(วิทยาเขต)จะถูกสร้างเป็นแท็ก <table> </table> คลุมและถูกคั่นกับ node ลูก ด้วยแท็ก <div> </div> ก่อน node ลูกจะสร้างแท็ก <table> </table> คลุม node ของตัวเอง ทำให้ตอนจัดการกับ node แต่ละแบบใน jQuery จึงแยกส่วน node แม่และลูกด้วยแท็กดังกล่าวนั่นเองค่ะ

    3. ส่วนของ body ในการแสดงผล
      <body>
          <form id="form1" runat="server">
              <asp:TreeView ID="TvOrganization" runat="server" ShowCheckBoxes="All" >
              </asp:TreeView>
          </form>
      </body>

      หมายเหตุ : กรณีที่ต้องการใช้งานเกี่ยวกับ check box อย่าลืมกำหนดคุณสมบัติให้กับ TreeView เพื่อให้สามารถแสดง check box ไว้ด้วยนะคะ ซึ่งก็คือ การกำหนดค่าให้กับ ShowCheckBoxes นั่นเองค่ะ

    4. ตัวอย่างผลลัพธ์
      แบบที่ 1 เลือกที่  node วิทยาเขต จะเลือกที่ node คณะ/หน่วยงานในวิทยาเขตนั้นให้ทั้งหมด

      แบบที่ 2
      หากเลือกออกจากคณะ/หน่วยงานใดหน่วยงานหนึ่ง จะทำการเลือกออกที่  node วิทยาเขตให้อัตโนมัติ

               เพียงเท่านี้ท่านก็จะสามารถดึงข้อมูลจากฐานข้อมูลมาแสดงใน TreeView ของท่านได้แล้ว และนี่ก็อาจจะเป็นเพียงหนึ่งในวิธีการดึงข้อมูลมาแสดงใน TreeView ในเบื้องต้นที่ผู้เขียนศึกษาและนำมาประยุกต์ให้ดูเป็นตัวอย่างเท่านั้น หวังว่าผู้อ่านจะสามารถนำไปเป็นแนวทางในการนำไปประยุกต์ใช้กับงานของท่านได้ นอกจากนี้ท่านยังสามารถผนวกส่วนของการกำหนดคุณสมบัติที่ฝั่ง client กับการกำหนดคุณสมบัติตอนฝั่งเซิร์ฟเวอร์(C#) ร่วมกันได้ เพื่อเพิ่มประสิทธิภาพและลูกเล่นให้กับ TreeView ของท่านมากยิ่งขึ้นค่ะ หากมีส่วนใดผิดพลาดทางผู้เขียนขออภัยไว้ ณ ที่นี้ด้วยนะคะ ขอบคุณค่ะ

    แหล่งข้อมูลอ้างอิง :

  • มาทำความรู้จักกับพื้นฐานการใช้งาน “TreeView” สำหรับมือใหม่กันดีกว่า

              เชื่อว่านักพัฒนาโปรแกรม Web application ด้วย .Net หลายๆท่านอาจจะเคยได้ยินชื่อของเจ้า “TreeView” กันมาบ้างแล้ว หรือบางท่านก็อาจจะเกือบลืมเจ้าเครื่องมือตัวนี้ไปแล้วก็ตามเพราะมันอาจจะไม่ใช่เครื่องมือที่ถูกหยิบมาใช้บ่อยนัก ในบทความนี้ผู้เขียนจึงขอหยิบยกเจ้า “TreeView” มาปัดฝุ่น แนะนำลูกเล่นการใช้งาน การกำหนดคุณสมบัติต่างๆ และวิธีการใช้งานกันอย่างคร่าวๆก่อน เพื่อเป็นการปูพื้นฐานให้กับมือใหม่หัดใช้ TreeView และรื้อความทรงจำให้กับผู้ที่เคยใช้ TreeView มาก่อนหน้านี้ เผื่อความสามารถที่ซ่อนอยู่จะไปเตะตาตรงใจท่านใดที่กำลังมองหาการทำงานแบบนี้อยู่พอดี จนอยากนำเครื่องมือตัวนี้ไปประยุกต์ใช้เป็นอีกหนึ่งทางเลือกในการแสดงผลข้อมูลในงานพัฒนาของท่านกันอีกครั้งได้ค่ะ
              แต่ก่อนจะพูดถึงลูกเล่นการทำงานของ TreeView คงต้องเกริ่นนำกันก่อนว่าเจ้าเครื่องมือตัวนี้ถูกจัดอยู่ในจำพวก Navigation Control ซึ่งบางคนอาจเกิดคำถามว่า ข้อมูลแบบใดบ้างจึงจะเหมาะนำมาใช้งานแสดงผลกับเจ้า TreeView นี้ ซึ่งโดยความเห็นส่วนตัวแล้วนั้น ผู้เขียนคิดว่าข้อมูลที่เหมาะจะมาแสดงผลด้วย TreeView ควรจะเป็นข้อมูลที่มีลักษณะเป็นแบบ Hierarchy หรือเป็นลักษณะโครงสร้าง มีลักษณะข้อมูลเป็นลำดับชั้นย่อยๆ เช่น โครงสร้างหน่วยงาน โครงสร้างองค์กร หรือข้อมูลที่เป็นประเภทหลักและประเภทย่อย เป็นต้น และเพื่อไม่ให้เป็นการเสียเวลา เรามาเรียนรู้วิธีจัดการกับ TreeView ของเรากันเลยดีกว่าค่ะ

    ขั้นตอนสร้าง TreeView อย่างง่ายจาก Tool box ของ Visual studio .Net สามารถทำได้ดังนี้

    1. สร้าง TreeView โดยเลือกจากแท็บเครื่องมือ ในกลุ่ม Navigation มาวางในหน้าจอ design ของเรา ดังรูป


    2. การเพิ่มและจัดการ node ให้กับ TreeView ได้โดยการคลิกเลือก “Edit Nodes…” ดังภาพ


    3. การจัดการเพิ่ม-ลดข้อมูล node ในระดับต่างๆ จะแสดงภาพดังหน้าจอต่อไปนี้ เพื่อใช้ในการจัดการเพิ่ม-ลดข้อมูล node ในระดับต่างๆ ดังนี้



      โดยขั้นตอนการเพิ่ม – ลด node อย่างคร่าวๆ มีดังนี้
      • การเพิ่ม node ที่เป็น root (ลำดับแรกสุด) โดยการกดปุ่ม
      • การเพิ่ม node ระดับย่อย(child node) โดยการกดปุ่ม
      • การลบ node ที่ไม่ต้องการ สามารถทำได้โดยการกดปุ่ม
      • ปรับเปลี่ยนระดับความลึกของ node โดยคลิกเลือก node ที่ต้องการจัดการและกดปุ่ม เพื่อเลื่อนระดับความลึกมากน้อยได้ตามต้องการ ซึ่งจะเห็นได้ว่ามีการทำงานคล้ายกับการเยื้องย่อหน้าใน MS Word ที่เราคุ้นเคยกันดี
      • การเลื่อนลำดับบน-ล่างให้กับ node สามารถทำได้โดยกดปุ่ม

        ตัวอย่าง หน้าจอการจัดการ node ใน TreeView



                      จากภาพตัวอย่าง มีการเพิ่มและจัดการ node ข้อมูลโครงสร้างองค์กรตั้งแต่ระดับมหาวิทยาลัย วิทยาเขต และคณะ โดยการกำหนดค่าตายตัวจากหน้าจอ design ด้วยการระบุเอง ไม่ได้ดึงจากฐานข้อมูล ซึ่งท่านสามารถทดลองเพิ่มและจัดการได้ด้วยตัวเองเพื่อให้เข้าใจการทำงานมากขึ้น โดยลองทำตามขั้นตอนการจัดการ node ข้างต้น
                      นอกจากการเพิ่ม-ลด node แล้ว ท่านยังสามารถกำหนดคุณสมบัติให้กับ node ได้ด้วย โดยคลิกข้อมูล node ที่ต้องการจัดการจากฝั่งซ้ายมือ และกำหนดคุณสมบัติของ node ดังกล่าวในฝั่งขวามือ ซึ่งรายละเอียดการกำหนดคุณสมบัติต่างๆ ในแต่ละ node จะขอพูดในหัวข้อถัดไป (ข้อ 4.)ค่ะ

    4. กำหนดคุณสมบัติให้กับแต่ละ node เราสามารถกำหนดคุณสมบัติ (Properties) เฉพาะให้กับแต่ละ node ได้ โดยจะขอพูดถึงคร่าวๆ ที่คิดว่าน่าจะใช้อยู่บ่อยๆและน่าสนใจ ดังนี้
      • ShowCheckBox : เป็นการระบุว่าจะให้ node ดังกล่าวแสดงช่องให้เลือกหรือไม่
      • Checked : เป็นการระบุว่า ต้องการให้มีการทำเครื่องหมายถูกไว้ในกล่อง check box หรือไม่ ซึ่งต้องมีการกำหนดควบคู่กับ ShowCheckBox = “true” นั่นเอง
      • Text : ระบุว่าต้องการให้ node ดังกล่าวแสดงข้อความอะไร
      • Value : ระบุค่าที่จะกำหนดให้กับ node ดังกล่าว และสามารถเลือกดึงค่าไปใช้งานได้(ในกรณีที่จะนำไปพัฒนาโปรแกรมต่อ)
      • NavigateUrl : กำหนดว่าเมื่อกด node ดังกล่าวจะให้ไปยังหน้าจอใด โดยระบุชื่อเพจหน้าจอนั้น
      • Target : เป็นการระบุการเปิดเพจในกรณีที่มีการกำหนด NavigateUrl ไว้ว่าจะให้เปิดเพจใหม่ หรืออยู่ในหน้าเดิมนั่นเอง
      • ImageUrl : เป็นการระบุว่าต้องการให้แสดงเป็นรูปภาพอะไรหน้าข้อความใน node นั้นๆ
      • Selected : เป็นการระบุว่าจะให้ node ดังกล่าวสามารถคลิกลิงค์ได้หรือไม่
      • SelectAction : กำหนด action ที่จะให้ทำตอนกดเลือกลิงค์ใน node นั้น
        1) Expand : เมื่อหากต้องการให้คลิกแล้วขยาย node ย่อย ซึ่งเมื่อคลิกแล้วจะย่อ-ขยาย node ย่อยได้
        2) SelectExpand : จะเป็นการระบุให้มีการขยาย node เช่นกัน แต่จะต่างกันตรงที่เมื่อขยาย node ย่อยแล้วจะไม่ย่อ-ขยายให้อีกแบบ Expand นั่นหมายถึงว่าจะสามารถคลิกลิงค์ของ node เพื่อขยายได้เท่านั้น แต่จะไม่สามารถย่อกลับมาได้นั่นเอง
        3) None : เมื่อไม่ต้องการให้คลิกได้
      • ToolTip : เป็นการระบุข้อความที่ต้องการให้แสดงเมื่อชี้ไปที่ node นั้นๆ
      • Expanded : เป็นการกำหนดว่า ตอนเริ่มต้นจะให้ node ย่อยของ node ดังกล่าวขยายไว้หรือไม่

        ตัวอย่าง ผลลัพธ์จากการกำหนดลองกำหนดค่าต่างๆให้กับบาง node


                      จากภาพ จะเห็นว่าแต่ละ node มีการแสดงผลแตกต่างกันตามที่เราระบุ เช่น บาง node มีการกำหนดให้แสดงภาพหน้าข้อความ บาง node ไม่สามารถคลิกลิงค์ได้ เช่น มหาวิทยาลัยสงขลานครินทร์ และบาง node มี check box อยู่หน้าข้อความให้เลือก และบาง node มีการยุบ node ย่อยไม่แสดงในตอนเริ่มต้น เป็นต้น
    5. กำหนดคุณสมบัติให้กับทุก node จาก properties ของคอนโทรล TreeView ซึ่งจะแตกต่างจากการกำหนดในแต่ละ node ในข้อ 4. เนื่องจากวิธีการกำหนดคุณสมบัติแบบนี้ จะเหมาะกับกรณีที่ไม่ต้องการระบุคุณสมบัติแยกในแต่ละ node แต่ต้องการให้เป็นไปในแบบเดียวกันทั้ง TreeView ทำให้ลดระยะเวลาที่จะต้องกำหนดรูปแบบให้กับทุก node ที่ต้องการให้แสดงผลเหมือนกัน โดยจะขอยกตัวอย่างให้กับคุณสมบัติบางตัวที่อาจจะจำเป็นต้องใช้ ดังนี้
      • ShowCheckBox : เป็นการกำหนดคุณสมบัติคล้ายกับที่กำหนดให้กับแต่ละ node แต่หากมากำหนดที่ตรงนี้ จะทำให้ทุก node แสดงหรือซ่อนกล่อง check box ได้จากจุดเดียว โดยมีให้เลือก 4 ตัวเลือก ดังนี้

        1) All : กำหนดให้ทุก node แสดง check box

        ตัวอย่าง ผลลัพธ์จากการกำหนด ShowCheckBox =”All”


        จากภาพจะเห็นว่า มี check box อยู่ในแต่ละ node ทั้งหมด โดยการกำหนดที่คุณสมบัติ ShowCheckBox =”All” นี้ที่จุดเดียว โดยไม่ต้องไปกำหนดที่แต่ละ node

        2) Leaf : กำหนดให้แสดง check box เฉพาะ node ลูกที่ไม่มี node ย่อย

        ตัวอย่าง ผลลัพธ์จากการกำหนด ShowCheckBox =”Leaf”


        จากภาพจะเห็นว่า จะแสดงผล check box เฉพาะ node ที่เป็นลูก และไม่มี node ย่อยอีก ซึ่งเรียก node แบบนี้ว่า “Leaf” นั่นเอง

        3) None : ไม่แสดง Checkbox ใน node ใดๆ เลย

        ตัวอย่าง ผลลัพธ์จากการกำหนด ShowCheckBox =”None”


        จากภาพจะเห็นว่า ไม่แสดงผล check box ใน node ใดๆเลย

        4) Parent : เป็นการแสดง check box เฉพาะตำแหน่ง node ที่มีลูก หรือ child node ที่ไม่ใช่ root node นั่นเอง

        ตัวอย่าง ผลลัพธ์จากการกำหนด ShowCheckBox =”Parent”


        จากภาพจะเห็นว่า จะแสดง check box เฉพาะ node ที่มีลูกในระดับย่อย และต้องไม่ใช่ root node นั่นเอง

        5) Root : จะแสดง check box เฉพาะตำแหน่ง root หรือ node ระดับแรกสุดเท่านั้น

        ตัวอย่าง ผลลัพธ์จากการกำหนด ShowCheckBox =”Root”

        จากภาพจะเห็นว่า จะแสดงผล check box ใน node ที่อยู่ในระดับ root หรือระดับแรกสุดนั่นเอง

      • ShowExpandCollapse : เป็นการระบุว่าต้องการให้แสดงตัวย่อ-ขยาย ที่เป็นเครื่องหมาย + และ – เพื่อย่อขยาย TreeView หรือไม่ หากกำหนดเป็น false จะไม่สามารถย่อ-ขยาย TreeView ดังกล่าวได้ โดยค่าตั้งต้นจะเป็น true ซึ่งหมายถึงสามารถย่อ-ขยายได้นั่นเอง

        ตัวอย่าง การกำหนดคุณสมบัติ ShowExpandCollapse =”false”

        จากภาพจะเห็นว่า ไม่สามารถย่อ-ขยายข้อมูลของ TreeView แต่ละ node ได้เลย

      • BorderStyle : เป็นการกำหนดรูปแบบของเส้นขอบของ TreeView ที่เราต้องการได้ เช่น solid dashed dotted เป็นต้น

        ตัวอย่าง การกำหนดคุณสมบัติของเส้นขอบ BorderStyle เป็น Double


      • CollapseImageUrl : เป็นการระบุ url ภาพที่ต้องการนำมาใช้แสดงแทนเครื่องหมาย – เพื่อให้กดแล้วย่อ node ย่อย
      • ExpandImageUrl : เป็นการระบุ url ภาพที่ต้องการนำมาใช้แสดงแทนเครื่องหมาย + เพื่อให้กดแล้วขยาย node ย่อย
      • NoExpandImageUrl : เป็นการระบุ url ภาพที่ต้องการนำมาใช้แสดงในกรณีที่ node ดังกล่าวไม่มี node ย่อย

        ตัวอย่าง ผลลัพธ์ของการระบุค่าของ CollapseImageUrl ให้เป็นรูปเครื่องหมายลบ กำหนดค่า ExpandImageUrl ให้เป็น url ของรูปที่เป็นเครื่องหมายบวก และกำหนด NoExpandImageUrl เป็นรูปไอคอนสีฟ้า ดังรูป

        หมายเหตุ : รูปภาพที่กำหนดในการย่อ-ขยายจะแสดงผลเมื่อ ShowLines เป็น false เท่านั้น

      • ImageSet : เป็นการกำหนดภาพที่ต้องการให้แสดงหน้า node ลักษณะคล้ายกับ bullet ดังตัวอย่างในภาพ



        จากภาพ จะเห็นว่าในฝั่งซ้ายมือ จะมี “ตัวเลือกรูปแบบ” ให้เลือกหลายแบบด้วยกัน และเมื่อเราคลิกแต่ละรูปแบบจะมีตัวอย่างผลลัพธ์แสดงให้ดูฝั่งขวามือ ซึ่งท่านสามารถเลือกให้เหมาะสมกับเนื้อหาในข้อมูลของท่านได้ หรือจะกำหนดรูปแบบเองจากคุณสมบัติที่กล่าวไว้ก่อนหน้านี้ได้นั่นเอง โดยท่านสามารถเลือกกำหนดคุณสมบัติเช่นนี้ได้จากการคลิกเลือก “Auto Format” ได้เช่นกัน ดังภาพ



        เมื่อเราคลิกเลือก “Auto Format…” จะปรากฎภาพหน้าจอดังนี้



        ซึ่งจะเห็นได้ว่า มีลักษณะการจัดการเดียวกับตอนเรากำหนดคุณสมบัติจาก ImageSet นั่นเอง

      • การกำหนด style ให้กับ node แต่ละแบบ ไม่ว่าจะเป็น LeafNodeStyle NodeStyle ParentNodeStyle หรือ RootNodeStyle ท่านก็สามารถกำหนดรูปแบบและตกแต่งความสวยงามให้กับ node แต่ละแบบได้ เช่น การใส่พื้นหลัง สีตัวอักษร หรือ แม้กระทั่งการระบุ style sheet ที่จัดทำไว้ก็สามารถทำได้เช่นกัน

      • LevelStyles : เป็นการกำหนด Style ให้กับแต่ละ level โดยจะเรียงตามลำดับ style ของแต่ละ node เริ่มจาก root ตามลำดับ ดังภาพ



        ตัวอย่าง ผลลัพธ์ของการกำหนด LevelStyles 3 ระดับข้างต้น โดยกำหนดให้ Level แรก มีสีตัวอักษรเป็นสีม่วง และ Level ที่ 2 มีสีตัวอักษรเป็นสีชมพู และ Level ที่ 3 มีตัวอักษรสีเขียว ดังภาพ



      • ExpandDepth : เป็นการกำหนดว่าจะให้การแสดงผล TreeView ขยายเริ่มต้นที่กี่ระดับ โดยค่าตั้งต้นจะเป็นแบบ FullyExpand ซึ่งหมายถึงขยายทั้งหมดตอนเริ่มต้น

        ตัวอย่าง ผลลัพธ์การระบุ ExpandDepth = “1”

      • DataSourceID : เป็นการระบุแหล่งข้อมูลให้กับการแสดงผล TreeView ให้มาจากการดึงข้อมูล ไม่ใช่การระบุค่า node ตายตัวจากหน้าเพจ
      • NodeIndent : ระยะการเยื้องหน้าของ node แต่ละระดับ โดยมีค่าตั้งต้นเท่ากับ 20 ซึ่งท่านสามารถลดหรือเพิ่มได้ตามความเหมาะสม
      • ShowLines : เป็นการระบุว่าต้องการให้แสดงเส้นโยงเชื่อมของ node แต่ละระดับหรือไม่
      • SelectedNodeStyle : เป็นการกำหนด style ให้กับ node ที่โดนเลือกคลิก เช่น การระบุพื้นหลัง หรือการกำหนดสีตัวอักษร เป็นต้น
        ตัวอย่าง ผลลัพธ์การระบุ SelectedNodeStyle ให้พื้นหลังเป็นสีม่วงและตัวอักษรสีขาว โดยเมื่อคลิกที่ node ใดก็ตามก็จะแสดงผลดังที่ได้ระบุไว้ที่ node นั้น

                  หวังว่าเนื้อหาในบทความนี้จะสามารถแนะนำให้ท่านได้รู้จักกับ TreeView แบบคร่าวๆ กันจนพอหอมปากหอมคอแล้วนะคะ ซึ่งจะเห็นได้ว่าในบทความนี้ ผู้เขียนได้พยายามรวบรวม และสอดแทรกตัวอย่างผลลัพธ์ในการระบุคุณสมบัติในแบบต่างๆจากการลองผิดลองถูก ทดลองกำหนดคุณสมบัติแต่ละแบบมาให้ดูกันพร้อมคำอธิบายตามความเข้าใจของผู้เขียนเอง เพื่อหวังให้ผู้อ่านได้เห็นภาพมากยิ่งขึ้น หากมีส่วนใดที่เข้าใจไม่ถูกต้องหรือผิดไป ทุกท่านสามารถแนะนำเพื่อให้ปรับปรุงแก้ไขได้นะคะ และหวังว่าเนื้อหาเหล่านี้จะเป็นประโยชน์และสามารถนำไปประยุกต์ใช้กับงานพัฒนาของท่านได้ไม่มากก็น้อย หากมีส่วนใดผิดพลาดทางผู้เขียนต้องขออภัยไว้ ณ ที่นี้ด้วยค่ะ ขอบคุณที่ติดตามอ่านจนจบนะคะ ^^

  • djsurvey – Google Forms Alternative #01

    ต่อจาก ddready – แพ็ครวม django + bootstrap4 + crispy form + docker พร้อมใช้งาน ในบทความนี้ ผมได้พยายามทำให้ใช้งาน Django ได้ง่ายขึ้น จนได้ แบบสำรวจอย่างง่าย พร้อมใช้งาน ใน 3 ขั้นตอน

    Prerequesite

    ติดตั้ง Python 3.6+ หรือ ใช้ Python Container แล้ว

    Repository

    https://github.com/nagarindkx/djsurvey

    ง่าย ๆ 3 ขั้นตอน

    1. Clone Repository

    ใช้คำสั่ง git

    git clone https://github.com/nagarindkx/djsurvey.git

    หรือ Download ไปก็ได้

    https://github.com/nagarindkx/djsurvey/archive/master.zip

    2. กำหนดข้อคำถามในแบบสำรวจ

    แก้ไขไฟล์

    /code/main/survey/models.py

    ตัวอย่างเช่น แบบสำรวจ ประกอบด้วย

    1. ชื่อ
    2. อีเมล
    3. เพศ
    4. วันเดือนปีเกิด
    5. ผลไม้ที่ชอบ
    6. ข้อเสนอแนะ

    ก็สร้าง Model ตามนี้ ( แรก ๆ อาจจะรู้สึกน่ากลัว แต่พอเข้าใจแล้ว มันง่ายมาก)

    from django.db import models
    class Survey(models.Model):
        fullname = models.CharField(
            verbose_name="ชื่อ",
            max_length=255,  blank=False)
        email = models.EmailField(
            verbose_name="อีเมล",
            blank=False)
        gender = models.CharField(
            verbose_name="เพศ",
            max_length=1,    blank=False,
            choices=[('F', 'หญิง'), ('M', 'ชาย')],
            default='F',
        )
        birthdate = models.DateField(
            verbose_name="วันเดือนปีเกิด",
            auto_now=False,  blank=False)
        fruit = models.CharField(
            verbose_name="ผลไม้ที่ท่านชอบ",
            max_length=1,    blank=False,
            choices=[('a', 'แอปเปิ้ล'), ('b', 'มะละกอ'),
                     ('c', 'กล้วย'), ('d', 'ส้ม')],
            default='c',
        )
        comment = models.TextField(
            verbose_name="ข้อเสนอแนะ",
            blank=True)

    แนะนำให้ใช้ Visual Studio Code จะทำงานได้ง่ายมาก

    3. Migrate แล้ว Run

    ใช้คำสั่งต่อไปนี้

    python manage.py migrate
    python manage.py runserver 0:8080

    ชมผลงาน

    http://localhost:8080/survey/

    หรือ ตกแต่งอีกนิดหน่อย ก็จะได้แบบนี้

    http://localhost:8080/advancedsurvey/

    สำหรับผู้ที่ใช้ Docker สามารถ ทำตามขั้นตอนใน แนวทางการพัฒนา Web Application ด้วย django จาก local docker สู่ Google Cloud Run เพื่อนำขึ้น Google Cloud Run ได้เลย (แต่ต้องเชื่อมกับ Database จริง ๆ ก่อนนะ – โปรดติดตามตอนต่อไป)

    คุณกำลังเจอปัญหาเหล่านี้อยู่ใช่ไม๊ ?

    • Google Forms ก็ง่ายดีแหล่ะ แต่ จะทำอย่างไรให้เก็บข้อมูลไว้ในฐานข้อมูลได้ ?
    • อยากให้ ผู้ใช้งาน Upload เอกสารเข้ามา / แก้ไขข้อมูล ซึ่ง Google Forms ก็ทำได้ แต่ต้อง Login ด้วย Google Account ก่อน จึงจะทำได้
    • Google Forms ก็ทำ Conditions ได้แหล่ะ (Go to section base on answer) แต่ ถ้าจะให้มีการคำนวนที่ซับซ้อนกว่านั้น ก่อนจะเลือกคำถามถัดไป จะทำอย่างไร ?

    ปัญหาเหล่านี้จะหมดไป เมื่อคุณใช้ Django !

    • ติดตั้งได้ บน Web Server ของคุณ!
    • Login ด้วย Facebook/Twitter/Google/Line หรือ Email หรือ จะเป็น Single Sign-On ก็ยังได้
    • ทุกอย่างสามารถ Customize ได้ ทำแบบสอบถามที่ซับซ้อนได้

    ไว้เจอกันในตอนต่อ ๆ ไปครับ

  • ddready – แพ็ครวม django + bootstrap4 + crispy form + docker พร้อมใช้งาน

    สำหรับใครที่อยากจะลองพัฒนา Web Application ด้วย django web framework ผมได้รวบรวมเป็นชุดเริ่มต้น ซึ่งจะสามารถสร้าง Responsive Web และ มีแบบฟอร์มที่สวยงามด้วย crispy form มาเรียบร้อย ใช้งานได้ทั้ง แบบ Python บนเครื่อง และ แบบ Docker ลองทำตามดูได้ครับ

    ต้นแบบ มี Bootstrap 4 พร้อมใช้งาน
    มี Login Form มาให้เลย
    เข้ามาในส่วนของ Profile และ Logout ได้

    Repository

    สามารถเปิด URL ต่อไปนี้ เพื่อไป Download หรือ จะใช้ git clone ก็ได้

    https://github.com/nagarindkx/ddready.git

    https://gitlab.psu.ac.th/kanakorn.h/ddready.git

    จากนั้น ให้เปิด cmd ไปยังตำแหน่งที่ clone ลงมา

    สำหรับผู้ที่ติดตั้ง python อยู่แล้ว

    แล้วใช้คำสั่งต่อไปนี้

    pip install -r requirements.txt
    cd code
    cd main
    waitress-serve --listen *:8080 main.wsgi:application

    สำหรับผู้ที่จะใช้ Docker

    บน Windows ใช้คำสั่งต่อไปนี้

    set PROJECTNAME="projectname"
    set GCP-PROJECT-ID="gcp-project-id"
    set SERVICE="service"
    docker build --rm -f "Dockerfile" -t %PROJECTNAME%:dev .
    docker run -d -v %CD%\code:/code -p 8080:8080 --name %PROJECTNAME% %PROJECTNAME%:dev
    docker exec -it %PROJECTNAME% /bin/sh -c "[ -e /bin/bash ] && /bin/bash || /bin/sh"

    ทดสอบใช้งาน

    http://localhost:8080

    ในตอนต่อไป จะแนะนำวิธีการสร้าง แบบสอบถาม ทดแทนการใช้ Google Forms ครับ

  • แนวทางการพัฒนา Web Application ด้วย django จาก local docker สู่ Google Cloud Run

    ในการพัฒนาแอพพลิเคชั่น เราก็จะเจอปัญหานึงเสมอ ๆ คือ เวอร์ชั่น (Version) ของเครื่องมือที่ใช้ในการพัฒนานั้น แต่ละโปรเจคมีความแตกต่างกัน เช่น ในกรณีของ การพัฒนา Web Application ด้วย django web framework เราอาจจะอยากใช้ python รุ่นล่าสุด คือ 3.8 แต่ในขณะเดียวกัน เมื่อหลังบ้านต้องการไปติดต่อ Tensorflow 2.0 ซึ่งยังต้องใช้งานกับ Python 3.6 เป็นต้น วิธีแก้ไขปัญหาทั่วไปคือ ติดตั้ง package ‘virtualenv’ เพื่อให้การพัฒนาแต่ละโปรเจค มี Environment แตกต่างกันได้

    แต่จากการใช้งานจริง พบว่า สุดท้าย ตอนเอาไป Production บนเครื่อง Server ก็ต้องตามไปติดตั้งเครื่องมือ และรุ่นที่ถูกต้อง แม้ใน Python จะมีคำสั่ง pip install -r requirements.txt ก็ตาม แต่ก็ยังไปติดปัญหาว่า OS ของเครื่องที่จะ Production นั้น รองรับรุ่นของเครื่องมืออีกหรือไม่ด้วย

    แนวทางการใช้ Container ด้วย Docker จึงเป็นที่นิยม เพราะ เมื่อเราพัฒนาเสร็จแล้ว สามารถ Pack เข้าไปใน Container แล้วเอาไป Deploy ได้ โดย (แทบจะ) ไม่ต้องกังวลกับ Environment ปลายทาง อีกทั้ง ยังสามารถทดสอบ Environment ใหม่ ๆ ก่อนจะ Deploy ได้ด้วย เช่นการเปลี่ยนรุ่นของ Python เป็นต้น

    ในบทความนี้ จะนำเสนอ แนวทางการสร้าง docker container เพื่อใช้เป็นฐานในการพัฒนา django และ สามารถต่อยอด ติดตั้ง package อื่น ๆ ตามต้องการ ตั้งแต่ Development ไปจนถึง Deployment สู่ Serverless Environment อย่าง Google Cloud Run

    สร้าง Development Container

    เริ่มจาก สร้างโฟลเดอร์ใหม่ขึ้นมา ในนั้นมี 2 ไฟล์ คือ Dockerfile และ requirements.txt กับ โฟลเดอร์ ชื่อ code

    Dockerfile

    • ใช้ image ของ python เป็นรุ่น 3.7-slim ซึ่งตัดส่วนที่ไม่จำเป็นออกแล้ว (ไม่ใช้ alpine เนื่องจาก พบรายงานว่า แม้จะมีขนาดเล็กกว่า แต่ถูกจำกัดทรัพยากรบางอย่าง ทำให้ทำงานได้ช้ากว่า)
    • สร้าง /code แล้วเข้าไปใช้พื้นที่นี้ (เหมือนคำสั่ง mkdir /code ; cd /code อะไรประมาณนั้น)
    • สั่งให้ copy ไฟล์ requirements.txt ไปใช้ที่ root ( / )
    • จากนั้น Upgrade คำสั่ง pip เป็นรุ่นล่าสุด แล้ว ติดตั้ง package ตามที่กำหนดใน requirements.txt
    • เปิด Port 8080 ไว้ เพื่อใช้ในการทดสอบ และเป็นไปในแนวทางเดียวกับการใช้บน Google Cloud Run ต่อไป
    FROM python:3.7-slim
    WORKDIR /code/
    COPY requirements.txt /
    RUN pip install -U pip \
        && pip install -r /requirements.txt
    EXPOSE 8080

    requirements.txt

    ในการพัฒนา django เมื่อทำการติดตั้ง package ใดเพิ่มเติมด้วยคำสั่ง pip install ก็จะบันทึกรายการ พร้อมรุ่นของ package มาในไฟล์นี้ ในที่นี้ ใช้ django, guincorn และ whitenoise เป็นหลัก (จะมีรายการ dependency ติดเข้ามาด้วย)

    Django==2.2.6
    gunicorn==19.9.0
    pytz==2019.3
    sqlparse==0.3.0
    whitenoise==4.1.4

    จากนั้นใช้คำสั่งต่อไปนี้ สร้าง (build) docker image จากไฟล์ Dockerfile ข้างต้น โดยมี option ที่เกี่ยวข้องดังนี้

    docker build --rm -f "Dockerfile" -t mydjango:dev .
    • –rm เมื่อ build แล้ว ก็ลบ container ชั่วคราวทิ้ง
    • -f กำหนดว่าจะเรียกจากไฟล์ใด วิธีนี้ มีประโยชน์ เวลาที่จะต้องมี Dockerfile ทั้ง Development และ Production ในโฟลเดอร์เดียวกัน ซึ่งจำเป็นต้องใช้ชื่อไฟล์ที่แตกต่างกัน
    • -t เป็นตั้งชื่อ docker image และ ชื่อ tag
    • . คือ ให้ build จากตำแหน่งปัจจุบัน

    ขั้นตอนนี้จะได้ docker image ชื่อ mydjango และมี tag เป็น dev แล้ว้

    (ในที่นี้ พัฒนาบนเครื่องคอมพิวเตอร์ที่เป็น Windows 10 ซึ่ง %CD% จะให้ค่า Current Directory แบบ Absolute path ออกมา เช่นเดียวกับบน Linux ที่ใช้ $(pwd) )

    ต่อไป สั่ง run ด้วยคำสั่ง และ options ดังต่อไปนี้

    docker run --rm -it -p 8080:8080  -v %CD%\code:/code  mydjango:dev bash
    • –rm เมื่อจบการทำงาน ก็ลบ container ชั่วคราวทิ้ง
    • -it คือ interactive และเปิด TTY
    • -p เพื่อเชื่อม port 8080 จากภายนอก เข้าไปยัง port 8080 ภายใน container
    • -v เพื่อเชื่อม Volume หรือโฟลเดอร์ของเครื่อง host กับ /code ภายใน container ขั้นตอนนี้สำคัญ
    • bash ข้างท้าย เพื่อส่งคำสั่ง เรียก bash shell ขึ้นมา ซึ่งจะสัมพันธ์กับ -it ข้างต้น ทำให้สามารถใช้งาน shell ภายใน container ได้เลย

    ผลที่ได้คือ bash shell และ อยู่ที่ /code ภายใน container

    root@757bcbb07c7f:/code#

    ตอนนี้ เราก็สามารถสร้าง django ได้ตามปรกติแล้ว (คลิกดูตัวอย่างเบื้องต้น) แต่ในตัวอย่างนี้ จะเริ่มจากการสร้าง project ชื่อ main เพื่อใช้ในขั้นตอนต่อไป ด้วยคำสั่งต่อไปนี้

    django-admin startproject main
    cd main

    ในระหว่างการพัฒนา สามารถใช้คำสั่ง runserver โดยเปิด Port 8080 ใน container เพื่อทดสอบได้ดังนี้ (สอดคล้องตามที่อธิบายข้างต้น)

    python manage.py runserver 0.0.0.0:8080

    สร้าง Production Docker Image

    คำสั่งข้างต้น สามารถใช้ได้เฉพาะขั้นตอนการพัฒนา แต่เมื่อพัฒนาเสร็จแล้ว ควรใช้ Application Server แทน ในที่นี้จำใช้ gunicorn แต่ก่อนอื่น จะต้องปรับ Configuration ของ django ให้พร้อมในการ Deployment ก่อน

    main/settings.py

    # แก้ไข
    DEBUG = False
    ALLOWED_HOSTS = ['localhost','SERVICE-ID.run.app']
    
    # เพิ่ม
    MIDDLEWARE = [
        ...
        # Whitenoise
        'whitenoise.middleware.WhiteNoiseMiddleware',
        ...
    ]
    # เพิ่ม
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')

    มีเพิ่มเติมคือ whitenoise ซึ่งเป็น package สำหรับจัดการเกี่ยวกับการให้บริการ static file ในตัว มิเช่นนั้นจะต้องไปตั้งค่าใน Web Server ให้จัดการแทน

    เมื่อเราตั้งค่า DEBUG = False จะต้องกำหนด ALLOWED_HOSTS เสมอ ในที่นี้กำหนดให้เป็น localhost และ Production URL (SERVICE-ID.run.app) ที่จะเกิดขึ้นเมื่อสร้าง Service บน Google Cloud Run ครั้งแรกไปแล้ว (ค่อยกลับมาแก้ไขแล้ว Revision อีกครั้ง)

    ใช้คำสั่งต่อไปนี้เพื่อรวบรวม static files ต่าง ๆ มาไว้ในที่เดียวกัน ในที่นี้ คือที่ โฟลเดอร์ static

    python manage.py collectstatic

    ทดสอบ Production ด้วย gunicorn ด้วยคำสั่งต่อไปนี้

    gunicorn --bind 0.0.0.0:8080 main.wsgi

    ทดสอบเรียก Local Admin Console ( http://localhost:8080/admin ) ดู ถ้าเรียก static file เช่นกลุ่ม css ได้ ก็พร้อมสำหรับจะนำขึ้น Google Cloud Run ต่อไป

    สุดท้าย สร้าง Production Dockerfile และ สรุป requirements.txt ดังนี้

    Dockerfile.production

    FROM python:3.7-slim
    WORKDIR /code
    COPY ./code/* ./
    RUN pip install -U pip \
        && pip install -r requirements.txt
    EXPOSE 8080
    CMD [ "gunicorn","--bind","0.0.0.0:8080", "main.wsgi"]

    requirements.txt

    pip freeze > requirements.txt

    จากนั้น ใช้คำสั่งต่อไปนี้ เพื่อสร้าง Production Docker Image (ออกมาจาก Development Container shell ก่อน) โดยจะใช้ tag เป็น latest

    docker build -t mydjango:latest -f "Dockerfile.production" .

    ส่ง Production Docker Image ขึ้น Google Container Registry

    Google Cloud Run จะเรียกใช้ docker image ที่อยู่บน Google Container Registry เท่านั้น

    • เปิด Google Console
    • สร้าง Project ใหม่ และ ตั้งค่า Billing
    • เปิดใช้งาน Google Cloud Run และ Google Container Registry
    • ติดตั้อง Google Cloud SDK เพื่อให้สามารถ push ขึ้นได้ และ ยืนยันตัวตนด้วย Google Account

    แล้วใช้คำสั่งต่อไปนี้ เพื่อ tag

    docker tag mydjango:latest gcr.io/YOUR-GCP-PROJECT-ID/SERVICE-NAME
    • YOUR-GCP-PROJECT-ID เป็น Project ID ที่สร้างขึ้น
    • SERVICE-NAME ชื่อ service ที่จะสร้าง

    แล้วก็ push ขึ้น Google Container Registry

    docker push gcr.io/YOUR-GCP-PROJECT-ID/SERVICE-NAME

    สร้าง Google Cloud Run Service

    สร้าง Service โดยเลือก Image ที่ต้องการ

    เมื่อเสร็จแล้วจะได้ URL อย่าลืมเอาไปแก้ไขใน main/settings.py ในส่วนของ ALLOWED_HOSTS แทน SERVICE-ID.run.app

    จากนั้น build, tag และ push ขึ้น Google Cloud Registry อีกครั้ง แล้ว Deploy New Revision เป็นอันเรียบร้อย

    อันนี้เป็นการ Proof of Concept ในบทความต่อไป จะนำเสนอตัวอย่างการใช้งานจริงครับ