Category: Developer

งานพัฒนาระบบ, เขียนโปรแกรม

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

  • วิธีแจ้งเตือนจาก Google Forms เข้า LINE

    ต้องยอมรับว่า ปัจจุบันพฤติกรรมผู้ใช้ “ทั่วไป” จะเปิด LINE อ่านบ่อย และเร็วกว่าการเปิดอ่าน Email

    ต่อไปนี้ เป็นวิธีการ ตั้งค่าที่ Google Forms ว่า เมื่อมีคน Submit แบบฟอร์มมา ให้มา Alert ที่ LINE ของเรา หรือ ส่งเข้า LINE Group ก็ได้ โดยอาศัยความสามารถของ Google App Scripts ที่เรียก REST API ของ LINE

    สร้าง หรือ แก้ไข Google Forms ที่ต้องการ

    จากนั้น ไปที่ “More” หรือ ปุ่มสามจุดแนวตั้งด้านขวามือบน แล้ว คลิกที่ Script Editor

    จากนั้น ใส่ Google App Script

    ตามนี้ ในที่นี้ ตั้งชื่อ Function คือ sendLineNotification

    **** อย่าลืมเปลี่ยน YOUR-TOKEN-GO-HERE ที่จะได้จากขั้นตอนต่อไป ****

    function sendLineNotification(e)
    {
      // เลือกใช้ Form ที่กำลังใช้งานนี้
      var form = FormApp.getActiveForm() 
      
      // รับค่าจาก Form Response
      var itemResponses = e.response.getItemResponses();  
      
      // ข้อความที่แสดงในบรรทัดแรก
      var result="New Response" 
      
      // Loop แต่ละข้อคำถาม และ คำตอบ
      for (var i = 0; i < itemResponses.length; i++) {
        var itemResponse = itemResponses[i];
        
        // ต่อข้อความจากทุกคำถาม เป็นข้อความยาวข้อความเดียว
        // getTitle คือ Question Title แต่ละข้อ
        // getResponse คือ ถามตอบที่ส่งมา
        result += '\n'+itemResponse.getItem().getTitle()+': '+itemResponse.getResponse()
      }
      
      // สร้างรูปแบบที่จะส่งไปให้ LINE -- ในที่นี้คือข้อความอย่างเดียว
      var formData = {
        'message': result,
      };
      
      // LIINE token : ได้มาจาก https://notify-bot.line.me/my/
      // ในตัวอย่างนี้ เป็นแบบ Personal
      var token = 'YOUR-TOKEN-GO-HERE'
      
      // POST แบบใน Token ใน Header ไปยัง LINE Notify REST API
      var options = {
        'method' : 'post',
        'headers' : {'Authorization': "Bearer "+token},
        'contentType': 'application/x-www-form-urlencoded',
        'payload' : formData
      }
      UrlFetchApp.fetch('https://notify-api.line.me/api/notify', options)
    }
    

    ตั้งชื่อ Project, Save แล้ว Run

    ** อย่าลืม ตั้งชื่อ Project แล้ว Save ด้วย

    จากนั้น กดปุ่ม Run เพื่อให้เกิดการขอ Authorization ตาม OAuth Scope

    ซึ่งจะเจอ Error นี้ ก็ไม่เป็นไร (เพราะไม่มี ข้อมูลส่งมาจริง ๆ นั่นเอง) ให้กด Dismiss ไป

    ไปตั้ง Trigger

    ไปที่ เมนู Edit > Current project’s triggers

    ตั้งค่า Trigger ให้ทำงานทันทีที่มีการ Submit แบบฟอร์ม

    Trigger คือการตั้งค่าให้ Script นี้ทำงานอัตโนมัติ เมื่อมีการ Submit แบบฟอร์ม

    คลิก Add Trigger แล้วเลือก Function “sendLineNotification” เลือก “on form submit” และ “Notify me immediately” เพื่อให้เมื่อมีการ Submit แบบฟอร์ม ก็จะแจ้งทาง LINE ทันที

    จากนั้น กดปุ่ม Save

    ผลที่ได้คืออย่างนี้

    ขั้นตอนการขอ LINE Token

    ไปที่เว็บไซต์

    https://notify-bot.line.me/my/

    แล้ว Login ด้วย LINE Account ของท่าน

    จากนั้น คลิกปุ่ม Generate token

    ตั้งชื่อ และ เลือกว่าจะ Notify ไปที่ใด เราสามารถเลือกได้ว่า

    • ให้ Notify ไปที่เราคนเดียว
    • ให้ Notify ไปยัง Group Chat

    *** เราต้องเพิ่ม Line Notify เป็นเพื่อนก่อน และ Invite เข้าไปใน Group Chat นั้น ๆ ด้วย

    จากนั้น คลิกปุ่ม Generate Token

    ก็จะได้ Token ให้คลิกปุ่ม Copy แล้วคลิก Close

    จากนั้น นำไปแทนที่ YOUR-TOKEN-GO-HERE ใน Google App Script ข้างต้น แล้ว Save

    เราสามารถสร้าง Token สำหรับใช้งานในกิจกรรมที่แตกต่างกันได้ หลาย ๆ อัน เช่น อาจจะมี ต้องการให้แจ้งเตือนในกลุ่มที่แตกต่างกันออกไป เป็นต้น

    เมื่อมีคน Submit แบบฟอร์ม ก็จะมี LINE แจ้งเตือน

    อันนี้ แบบ Basic ง่าย ๆ เดี๋ยวค่อยมาเล่าการใช้งานที่ซับซ้อนกว่านี้

    หวังว่าจะเป็นประโยชน์ครับ

  • การ Connect Navicat ผ่าน xampp-linux 7.3.12 บน Ubuntu 18.04

    1. Download ไฟล์ ntunnel_mysqli.php
      https://qrgo.page.link/6G6uX
    2. โยน File ชื่อว่า ntunnel_mysqli.php เข้าไปใน Server ที่ wwwroot
    3. ทดสอบโดยการเข้าเว็บบราว์เซอร์ ด้วย : 192.168.xxx.xxx/ntunnel_mysqli.php แล้วลอง login ดูว่าผ่านไหม ?
    4. เข้าไปที่โปรแกรม Navicat
    5. ไปที่เมนู Connection เลือกเอาเลยว่าต้องการ Connection แบบไหน

    6. ไปที่ General
    – Connection Name = ตั้งชื่ออะไรก็ได้
    – Host Name / IP Address = localhost
    – Port = 3306
    – User Name = root หรือ User ที่เรา Add ใน phpmyadmin
    – Password = Password ที่เรา Add ใน phpmyadmin

    7. ไปที่ HTTP
    – ติ๊กเลือก Use HTTP Tunnel
    – Tunnel URL : https://192.168.xxx.xxx/ntunnel_mysqli.php หรือ https://xxxx.com/ntunnel_mysqli.php

    8. Test Connection

    หาก Connect ไม่ผ่าน ให้เข้าไปแก้ไฟล์ my.cnf บรรทัดที่เขียนว่า skip-networking ให้ไป # ปิดใว้ แล้ว Restart Service ใหม่อีกครั้ง

    หมายเหตุ : ผมได้ทดสอบกับ xampp-linux 7.3.12 บน Ubuntu 18.04
    php 5.4 up มันจะใช้ mysqli เป็นส่วนใหญ่ เลยต้องใช้ ntunnel_mysqli

  • ปัญหา “A potentially dangerous Request.Form value was detected from the client (ctl00$ContentPlaceHolder1$txtAbstractEng="…ontrol ” แก้ไขได้อย่างไร

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

    ปัญหา :

    ในการบันทึกข้อมูลลงบางเว็บไซต์เราจะอาจจะพบปัญหาว่าหลังจากเราป้อนข้อมูลเสร็จแล้ว แต่ทำไมไม่สามารถบันทึกข้อมูลได้ เกิด error เช่น

    เมื่อบันทึกจะมีข้อความขึ้นดังภาพข้างล่าง ป้อนใหม่บันทึกใหม่ก็ยังไม่ได้ โอ๊ยเครียด จะทำยังไงดี

    สาเหตุ :

    อาจจะเนื่องมาจากมีการ copy ข้อมูลมาจากแหล่งอื่นที่มีตัวอักษรพิเศษบางตัว  เช่น ? ติดมาด้วย ทำให้เราจะไม่สามารถบันทึกข้อมูลลงฐานได้ เราจะทำอย่างไร

    การแก้ไข : สามารถแก้ไขได้หลายวิธี คือ

    1. ในกรณีที่เป็นผู้ใช้งาน เราสามารถแก้ไขง่ายๆ ได้โดยการ นำ ? ออกจากข้อความ ดังรูปข้างล่าง แล้วบันทึกใหม่

    2. ในกรณีที่เป็นผู้พัฒนาระบบ เราจะเพิ่มข้อความ ValidateRequest=”false” ลงใน source ของหน้าจอที่ error ดังรูปข้างล่าง

    เพียงเท่านี้ปัญหาดังกล่าวก็จะหมดไปแล้วค่ะ ไม่ยากเลยใช่มั้ยคะ

    แล้วพบกันใหม่ค่ะ

  • วิธีติดตั้ง Expo CLI สำหรับพัฒนา Mobile App ด้วย React Native

    สำหรับผู้พัฒนาที่ต้องการพัฒนา Mobile App แต่รู้สึกว่ายังไม่พร้อมศึกษา React Native แบบจริงจัง สามารถใช้งาน Expo Framework โดยสามารถใช้ได้ทั้งในการพัฒนา หรือ Build ขึ้น Store ได้เลยทั้ง iOS/Android ด้วยภาษา JavaScript/TypeScript

    โดยวันนี้จะเริ่มด้วยแนะนำวิธีติดตั้ง Tools สำหรับพัฒนาชื่อ Expo CLI ครับ

    • Reference : https://docs.expo.io/versions/latest/
    • Installation Version
      • windows 10 version 1909 64 bit
      • npm 12.14.0 LTS
      • python 3.8
      • Expo SDK 36
    • ติดตั้ง Node Js (โหลดติดตั้งแบบ LTS)
      https://nodejs.org/en/
    • ถ้ามีแจ้งไฟล์ไม่ปลอดภัยกดข้ามไป
    • จะมีให้เลือกว่าจะลง Chocolatey หรือเปล่า เพื่อติดตั้ง Module เพิ่มเติม และแนะนำติดตั้ง Node-Gyp ซึ่งจะต้องติดตั้งเองภายหลัง
    • ติดตั้ง Python ก่อนติดตั้ง Node-Gyp ผ่าน Windows Store (หลังกด Get ไม่ต้อง Sign In ก็ได้)
    • เปิด windows cmd (Run as Administrator หรือไม่ก็เลือก Start->Node.js command prompt)
    • ติดตั้ง node-gyp
      npm install -g node-gyp
    • ติดตั้ง Expo CLI ด้วย npm
      npm install -g expo-cli
    • ทดสอบสร้างโปรเจ๊คใหม่ดังนี้
      • expo init
    • สั่งรัน Web สำหรับ Debug จะพบว่า Error
    • สำหรับ Expo SDK 36 ต้องแก้ \node_modules\metro-config\src\defaults\blacklist.js ดังนี้
      var sharedBlacklist = [
      /node_modules[\/\\]react[\/\\]dist[\/\\].*/,
      /website\ /node_modules\/.*/,
      /heapCapture\/bundle\.js/,
      /.*\/__tests__\/.*/
      ];

    สามารถทดสอบเปิดได้ผ่านโปรแกรม Expo ใน Android/IOS หรือ Emulator Android หรือจะผ่าน USB Debug Android ก็ได้ครับ โดยได้ทั้ง QR-Code หรือ Exp URL Copy ไปแป๊ะในโปรแกรมได้ครับ (ต้องอยู่ในวง Network เดียวกันยกเว้นทดสอบโดยใช้ Tunnel)

  • 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 ครับ

  • เค้าเอาไฟล์ MP4 บน Google Drive ไปแสดงใน Video Player บนเว็บได้อย่างไร

    สมมุติว่า เรามีไฟล์วิดีโอเป็น .mp4 อยู่ไฟล์หนึ่ง อยู่ใน Google Drive ต้องการเผยแพร่ เฉพาะบน Website ของเราเท่านั้น จะต้องทำอย่างไร?

    Javascript video player

    สิ่งแรกที่ต้องมีคือ ตัว Video Player บนเว็บ ลอง Google ด้วยคำว่า “javascript video player” ดู มีหลายตัวให้เลือกใช้ แต่ในที่นี้ ขอทดลองกับ video.js (เว็บไซต์ https://videojs.com )

    คลิกที่ USE NOW ( https://videojs.com/getting-started/ )

    จากนั้น ลองสร้างไฟล์ test.html โดยเอา Code จาก Video.js CDN ไปแปะเลย

    <head>
      <link href="https://vjs.zencdn.net/7.6.5/video-js.css" rel="stylesheet">
    
      <!-- If you'd like to support IE8 (for Video.js versions prior to v7) -->
      <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
    </head>
    
    <body>
      <video id='my-video' class='video-js' controls preload='auto' width='640' height='264'
      poster='MY_VIDEO_POSTER.jpg' data-setup='{}'>
        <source src='MY_VIDEO.mp4' type='video/mp4'> <!-- แก้ตรงนี้ -->
        <source src='MY_VIDEO.webm' type='video/webm'>
        <p class='vjs-no-js'>
          To view this video please enable JavaScript, and consider upgrading to a web browser that
          <a href='https://videojs.com/html5-video-support/' target='_blank'>supports HTML5 video</a>
        </p>
      </video>
    
      <script src='https://vjs.zencdn.net/7.6.5/video.js'></script>
    </body>

    จาก Code นี้ JavaScript จาะเรียกไฟล์ .MP4 จากไฟล์ชื่อ MY_VIDEO.mp4 ซึ่ง ถ้าเอา test.html นี้ไปวางบน Web Server ก็หมายความว่า เราต้องมีไฟล์ MY_VIDEO.mp4 ด้วย

    ไฟล์ MP4 บน Google Drive

    ตัวอย่างเช่น เราอาจอัดคลิปวิดีโอการสอน อยากจะเผยแพร่บนเว็บไซต์ของหน่วยงาน ผ่าน JavaScript Video Player อย่าง video.js ข้างต้น ก็สามารถทำได้ดังนี้

    1. แชร์ไฟล์ดังกล่าว ให้เป็น Anyone with the link can View
    2. แล้ว copy link นั้นมา หน้าตาประมาณนี้

      https://drive.google.com/open?id=FILE_ID
    3. จะเห็นคำว่า id= FILE_ID ตรงนี้ให้ Copy เก็บไว้

    แต่การที่เราจะเอา Link นี้ไปใช้ใน Video Player ตรง ๆ ไม่ได้ เพราะมันเป็นการเรียกใช้ Google Drive ไม่ใช่การเรียก File Content

    GoogleAPI

    วิธีการที่จะ Get Content ของไฟล์ที่ต้องการออกมากจาก Google Drive สามารถเรียกผ่าน Google API ซึ่ง หากจะทำเองก็สามารถทำได้ มีพวก node.js ให้ใช้งานอยู่ แต่พบว่า สามารถเรียกใช้ www.googleapis.com ได้ โดยอ้างอิงจาก https://googleapis.github.io/

    ในที่นี้ จะเรียกผ่าน Google Drive API ใน Version 3 รูปแบบ URL จะเป็นดังนี้

    https://www.googleapis.com/drive/v3/files/FILE_ID?alt=media&key=API_KEY

    ในการใช้งาน ต้องการ 2 ส่วน

    • FILE_ID ได้จากการแชร์ไฟล์ข้างต้น
    • API_KEY ได้มาจากการสร้าง Credential บน Google Cloud Platform วิธีการทำตามนี้ https://cloud.google.com/docs/authentication/api-keys

    การใช้งาน Google API นั้น มีส่วนทั้งที่ต้องจ่ายเงิน และส่วนที่ใช้ฟรี แต่ถูกจำกัด Quota ในกรณี Google Drive API สามารถใช้ได้ฟรี แต่จะมี Quota อยู่ โดยดูได้จาก https://developers.google.com/drive/api/v3/about-sdk

    ประกอบร่าง

    เมื่อได้ FILE_ID และ API_KEY มาแล้ว ก็เอาไปใส่ใน Code ข้างต้น

    <head>
      <link href="https://vjs.zencdn.net/7.6.5/video-js.css" rel="stylesheet">
    
      <!-- If you'd like to support IE8 (for Video.js versions prior to v7) -->
      <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
    </head>
    
    <body>
      <video id='my-video' class='video-js' controls preload='auto' width='640' height='264'
      poster='MY_VIDEO_POSTER.jpg' data-setup='{}'>
        <source src='https://www.googleapis.com/drive/v3/files/FILE_ID?alt=media&key=API_KEY' type='video/mp4'> <!-- เปลี่ยนตรงนี้ -->
        <source src='MY_VIDEO.webm' type='video/webm'>
        <p class='vjs-no-js'>
          To view this video please enable JavaScript, and consider upgrading to a web browser that
          <a href='https://videojs.com/html5-video-support/' target='_blank'>supports HTML5 video</a>
        </p>
      </video>
    
      <script src='https://vjs.zencdn.net/7.6.5/video.js'></script>
    </body>

    หวังว่าจะเป็นประโยชน์ครับ

    Disclaimer: จุดประสงค์ของบทความนี้ เพื่อแนะนำวิธีการทำเท่านั้น โปรดนำความรู้นี้ไปใช้งานอย่างสร้างสรรค์นะครับ ผู้เขียนบทความไม่เกี่ยวข้องใด ๆ กับผู้นำไปใช้ทั้งสิ้น