Month: July 2017

  • การปรับเปลี่ยนรูปแบบการแสดงผลเส้นทางระหว่างพิกัดจุดบนแผนที่ Google Map APIs ด้วย DirectionsTravelMode

              ก่อนที่เราจะไปเริ่มเนื้อหาของบทความี้ ผู้เขียนต้องขอท้าวความเดิมตอนที่แล้วของบทความก่อน ซึ่งผู้เขียนได้พูดถึงวิธีการแสดงผลเส้นทางทางระหว่างพิกัดจุดบนแผนที่ Google Map APIs ด้วย DirectionsService ในเบื้องต้นไว้ (สามารถศึกษาเพิ่มเติมได้จากบทความ : การแสดงเส้นทางระหว่างพิกัดจุดบนแผนที่ Google Map APIs ด้วย DirectionsService ในเบื้องต้น )  สำหรับในบทความนี้ผู้เขียนจึงอยากต่อยอดการทำงาน และเพิ่มลูกเล่นให้กับการแสดงผลแผนที่ด้วยการปรับเปลี่ยนการกำหนดรูปแบบการแสดงผลของเส้นทางให้ผู้เยี่ยมชมเว็บไซต์  ซึ่งเราจะให้ผู้ใช้สามารถเลือกรูปแบบในการแสดงผลได้ว่า ต้องการดูเส้นทางในรูปแบบใดตามรูปแบบ Mode ที่ผู้ใช้เลือกมา เช่น เส้นทางเดิน ทางถนน หรือขนส่งสาธารณะ เป็นต้น โดยวิธีการดังกล่าวนี้เหมาะกับเว็บไซต์ที่มีความเกี่ยวข้องกับความต้องการที่ต้องการทราบเส้นทางในแต่ละรูปแบบ เพื่อเป็นประโยชน์ในการนำไปประยุกต์ใช้กับงานของแต่ละท่านได้ค่ะ

       ตัวอย่างผลลัพธ์ที่ได้จากบทความที่แล้ว 

    ซึ่งจากตัวอย่างโค้ดในบทความที่แล้ว การกำหนด DirectionsTravelMode เป็น DRIVIING ซึ่งในความเป็นจริงแล้วยังมีรูปแบบอื่นๆให้เลือกใช้ด้วยกันทั้งหมด 4 รูปแบบ ดังนี้

    DRIVING (Default):เป็นโหมดตั้งต้นให้หากไม่ได้มีการกำหนดไว้ ซึ่งเป็นโหมดที่แสดงเส้นทางการขับขี่ด้วยยานพาหนะ
    BICYCLING: เป็นโหมดสำหรับเส้นทางที่เตรียมไว้สำหรับผู้ขับขี่จักรยาน
    TRANSIT: เป็นโหมดสำหรับแสดงเส้นทางระบบขนส่งสาธารณะ เช่น  รถบัส รถไฟ หรือแม้แต่เครื่องบิน เป็นต้น
    WALKING: เป็นโหมดสำหรับแสดงเส้นทางการเดินถนน

              ซึ่งผู้เขียนจะขอยกตัวอย่างในส่วนของการเลือกรูปแบบเส้นทางและผลลัพธ์ของแต่ละรูปแบบ ดังตัวอย่างโค้ดต่อไปนี้

    • การกำหนดรูปแบบของเส้นทางในการแสดงผลบนแผนที่
    1. โค้ด Javascript
       <script type="text/javascript">
      function initialize() {
       // ประกาศเรียกใช้งาน DirectionsService เพื่อการแสดงผลให้มีลักษณะเป็น Global
       window.directionsService = new google.maps.DirectionsService();
       window.directionsDisplay = new google.maps.DirectionsRenderer();
       var map;
       var bounds = new google.maps.LatLngBounds();
       var mapOptions = {
       mapTypeId: 'roadmap'
       };
      
      // แสดงผลแผนที่ในหน้าจอตาม Element ที่กำหนด
       map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
       map.setTilt(45);
      
      // กำหนดพิกัดจุดให้กับจุดเริ่มต้นและเส้นสุด
       window.markers = [
       ['Place1', 51.501546, -0.142000],
       ['Place2', 51.512051,-0.091225]
       ];
      // ให้แสดงผลสิ่งที่ตั้งค่าไว้ในพื้นที่แผนที่ที่กำหนด
       directionsDisplay.setMap(map);
      // กำหนดค่าเริ่มต้นของรูปแบบให้เป็นเส้นทางการเดิน (walking mode)
       calcRoute();
      }
      // เป็นฟังก์ชั่นในการคำนวณเส้นทางระหว่างสองจุดพิกัดบนแผนที่และเลือกกำหนดค่า Mode ในการแสดงผล
       function calcRoute() {
        var selectedMode = document.getElementById('travelType').value;
        var request = {
       
        origin: new google.maps.LatLng(markers[0][1], markers[0][2]),
       
        destination: new google.maps.LatLng(markers[1][1], markers[1][2]),
      
      //// //กำหนดรูปแบบการแสดงผลเส้นทางโดยเริ่มต้นให้เป็นเส้นทางการเดิน(ตามรายการแรกที่เลือก)
        travelMode: google.maps.TravelMode[selectedMode]
        };
        
       directionsService.route(request, function(response, status) {
       if (status == google.maps.DirectionsStatus.OK) {
       directionsDisplay.setDirections(response);
       }
       });
       }
       </script>
    2. ส่วนของการแสดงผลใน body
      <body> 
      <div id="map_wrapper">
       <div id="map_canvas" class="mapping"></div>
      </div>
      <div id="travel_selector">
       <p><strong>Mode of Travel: </strong>
       <select id="travelType" onchange="calcRoute();">
       <option value="WALKING">Walking</option>
       <option value="BICYCLING">Bicycling</option>
       <option value="DRIVING">Driving</option>
       <option value="TRANSIT">Transit</option>
       </select></p>
      </div>
      </body>
    3. ผลลัพธ์ในแต่ละรูปแบบ
    • แบบที่ 1 DRIVING Mode :

     

    • แบบที่ 2 BICYCLING Mode:

    • แบบที่ 3 TRANSIT Mode:


    • แบบที่ 4 WALKING Mode:


                จากตัวอย่างจะเห็นได้ว่าเป็นพิกัดของประเทศในต่างแดน เนื่องจากก่อนหน้านี้ ผู้เขียนลองใช้พิกัดจุดบนพื้นที่ประเทศไทย แต่พบว่ามีบาง Mode ยังไม่รองรับ เช่น เส้นทางจักรยาน ซึ่งเมื่อเลือกกำหนดโหมดดังกล่าวจะไม่เห็นการเปลี่ยนแปลงใดๆ จึงหันไปยกตัวอย่างจาก London แทนเพื่อให้ผู้อ่านได้เห็นความแตกต่างในการแสดงผลแต่ละแบบได้ชัดเจนขึ้น แต่เพื่อไม่ให้เป็นการน้อยเนื้อต่ำใจกัน ผู้เขียนก็ได้ลองเอาพิกัดของพื้นที่ในประเทศไทยมาลองทำดูให้ผู้อ่านได้เห็นแถมมาด้วยว่าพื้นที่ของเราจะเห็นเส้นทางเป็นยังไงในแต่ละแบบกันบ้าง ดังนี้ค่ะ
      ตัวอย่างการแสดงเส้นทางระหว่างสนามบินสุวรรณภูมิและเขตจตุจักร
      1) แบบ Transit mode

       

      จะเห็นได้ว่า เมื่อคลิกที่รูปสัญลักษณ์เครื่องหมายคำพูด จะแสดงรายละเอียดเกี่ยวกับข้อมูลการขนส่งสาธารณะนั้นๆ เช่น รถเมล์สายใด รถไฟฟ้า BTS สายใด เป็นต้น

      2) แบบ Walking Mode


      3) แบบ Driving Mode

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


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

     

  • การแสดงเส้นทางระหว่างพิกัดจุดบนแผนที่ Google Map APIs ด้วย DirectionsService ในเบื้องต้น

              หลังจากที่ก่อนหน้านี้ ผู้เขียนเคยได้มีโอกาสศึกษาบทความเกี่ยวกับความสามารถของ Google Map APIs มาบ้างแล้วนั้น ผู้เขียนเห็นว่าเรื่องเกี่ยวกับแผนที่นับเป็นอีกหัวข้อที่น่าสนใจในการพัฒนาเว็บไซต์ในปัจจุบัน โดยเฉพาะเว็บไซต์ที่มีส่วนเกี่ยวข้องกับสถานที่ และที่ตั้ง เพราะถือเป็นการเพิ่มลูกเล่นให้มีความตื่นตาตื่นใจยิ่งขึ้น โดยความสามารถของแผนที่ที่ใน Google Map APIs มีมาให้ใช้กันได้ในหลายรูปแบบ ขึ้นอยู่กับความต้องการของผู้พัฒนาแต่ละคน อาทิ การกำหนดพิกัดจุด การแสดงเส้นทาง การค้นหาละติจูด-ลองจิจูดจากการคลิกบนแผนที่ หรือจนกระทั่งการดึงพิกัดมาจากฐานข้อมูลเพื่อมาแสดงผล เป็นต้น โดยในความเป็นจริงแล้ว ลูกเล่นเกี่ยวกับการทำงานกับแผนที่ยังมีอีกมากมาย แต่ในบทความนี้ ผู้เขียนจะขอพูดถึงในส่วนของการแสดงเส้นทางระหว่างจุดสองจุดในแบบเบื้องต้นเพื่อทำความเข้าใจก่อนนำไปประยุกต์ใช้ ดังนี้

    การแสดงเส้นทางโดยเบื้องต้นเมื่อทราบจุดพิกัดละติจูด-ลองจิจูดบนแผนที่

    1. อ้างอิงไฟล์ที่ใช้ในการทำงานร่วมกับ Google Map APIs
      <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&language=en" async defer></script>
      
    2. ส่วนของ Javascript ที่ใช้ในการแสดงเส้นทางระหว่างพิกัด 2 จุดบนแผนที่
      <script type="text/javascript">
      /////////การกำหนดค่าละติจูด-ลองจิจูดระหว่าง 2 ตำแหน่ง ในที่นี้คือ มหาวิทยาลัยสงขลานครินทร์ และสวนสาธารณะหาดใหญ่
      var markers = [
       {
       "title": 'มหาวิทยาลัยสงขลานครินทร์',
       "lat": '7.006941', 
       "lng": '100.498412',
       "description": '<b>มหาวิทยาลัยสงขลานครินทร์:</b> (อังกฤษ: Prince of Songkla University; อักษรย่อ: ม.อ.) เป็นมหาวิทยาลัยแห่งแรกในภาคใต้ของประเทศไทย ตาม พระราชบัญญัติมหาวิทยาลัยสงขลานครินทร์ พ.ศ. ๒๕๑๑ ก่อตั้งในปี พ.ศ. 2510 ต่อมา พระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดชได้พระราชทานชื่อเมื่อวันที่ 22 กันยายน พ.ศ. 2510 จึงถือว่าวันที่ 22 กันยายนของทุกปี เป็นวันสงขลานครินทร์'
       }
       ,
       {
       "title": 'สวนสาธารณะหาดใหญ่',
       "lat": '7.042899', 
       "lng": '100.507664',
       "description": '<b>สวนสาธารณะเทศบาลนครหาดใหญ่:</b> เป็นแหล่งพักผ่อนหย่อนใจของคนเมืองแห่งนี้ มีทัศนียภาพที่สวยงาม เต็มไปด้วยด้วยแมกไม้เขียวขจี มีอ่างเก็บน้ำขนาดใหญ่ สัตว์น้ำนานาชนิดมากมาย สมบูรณ์ด้วยธรรมชาติอันบริสุทธิ์ ที่รอคอยต้อนรับนักท่องเที่ยวให้ได้สัมผัสกับความร่มรื่นของพรรณไม้นานาชนิด'
       }
       
       ];
      ///////เป็นการกำหนดค่าต่างๆตอนที่ฟอร์มมีการโหลด
      
      window.onload = function () {
      
      //////กำหนดค่ากึ่งกลางการแสดงผลแผนที่ ระยะใกล้ และชนิดการแสดงผลของแผนที่
       var mapOptions = {
       center: new google.maps.LatLng(markers[0].lat, markers[0].lng),
       zoom: 10,
       mapTypeId: google.maps.MapTypeId.ROADMAP
       };
      
      //////ประกาศ Element ที่จะใช้ในการแสดงผล
       var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
       var infoWindow = new google.maps.InfoWindow();
      
       var lat_lng = new Array(); ///สร้างตัวแปรอาร์เรย์เพื่อเก็บค่าละติจูด-ลองจิจูด
       var latlngbounds = new google.maps.LatLngBounds();
      
      /// วนพื่อเก็บค่าละติจูด-ลองจิจูดในตัวแปรอาร์เรย์ และเก็บค่าในการพิกัดจุดของแต่ละจุดที่มี
       for (i = 0; i < markers.length; i++) {
       var data = markers[i]
       var myLatlng = new google.maps.LatLng(data.lat, data.lng);
       lat_lng.push(myLatlng);
      
      
       var marker = new google.maps.Marker({
       position: myLatlng,
       map: map,
       title: data.title
       });
      
       latlngbounds.extend(marker.position);
      
      //////กำหนดเมื่อมีอีเวนต์คลิก ให้แสดงผลรายละเอียดที่กำหนดไว้ในตัวแปรของ marker ที่กำหนดไว้ในแต่ละตำแหน่ง
       (function (marker, data) {
       google.maps.event.addListener(marker, "click", function (e) {
       infoWindow.setContent(data.description);
       infoWindow.open(map, marker);
       });
       })(marker, data);
       }
       map.setCenter(latlngbounds.getCenter());
       map.fitBounds(latlngbounds);
       
       //***********ส่วนของการแสดงเส้นทาง****************//
       
       //ประกาศ Path Array
       var path = new google.maps.MVCArray();
       
       //ประกาศการใช้งาน Direction Service
       var service = new google.maps.DirectionsService();
       
       //กำหนดสีของเส้นทางที่ต้องการ
       var poly = new google.maps.Polyline({ map: map, strokeColor: '#4986E7' });
       
       //วนลูปเพื่อวาดเส้นทางระหว่างจุดที่มีในแผนที่
       for (var i = 0; i < lat_lng.length; i++) {
       if ((i + 1) < lat_lng.length) {
       var src = lat_lng[i];
       var des = lat_lng[i + 1];
       path.push(src);
       poly.setPath(path);
       service.route({
       origin: src,
       destination: des,
       travelMode: google.maps.DirectionsTravelMode.DRIVING
      /////กำหนด Mode ในการแสดงผลเส้นทาง(จะกล่าวเพิ่มเติมในภายหลัง)
       }, function (result, status) {
       if (status == google.maps.DirectionsStatus.OK) {
       for (var i = 0, len = result.routes[0].overview_path.length; i < len; i++) 
      {
       path.push(result.routes[0].overview_path[i]);
       }
       }
       });
       }
       }
      
      </script>
    3. ส่วนของ body ในการแสดงผล
      <body>
       <form id="form1" runat="server">
      <div id="dvMap" style="width: 500px; height: 500px">
      </div>
       </form>
      </body>
    4. ตัวอย่างผลลัพธ์ที่ได้ หมายเหตุ: หากต้องการเปลี่ยนสีเส้นทางในการแสดงผล สามารถทำได้โดยการกำหนดสี จากโค้ดดังตัวอย่าง คือ
      var poly = new google.maps.Polyline({ map: map, strokeColor: ‘#4986E7‘ }); ซึ่งสามารถเปลี่ยน strokeColor ในส่วนของตัวอักษรสีน้ำเงินให้เป็นสีที่ท่านต้องการได้

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

    หมายเหตุ: หากผู้ใดสนใจบทความอื่นๆเกี่ยวกับการพัฒนาโปรแกรมด้วยแผนที่ Google Map APIs ที่ผู้เขียนเคยเขียนไว้ก่อนหน้านี้ สามารถติดตามได้จากลิงค์ต่อไปนี้ค่ะ
    1) ทำอย่างไรให้สามารถกำหนดจุดพิกัดบนแผนที่ Google map แบบจุดเดียวและหลายจุดจากฐานข้อมูลได้ด้วย ASP.NET C#
    2) ทำอย่างไรให้สามารถกำหนดจุดพิกัดบนแผนที่ Google map แบบจุดเดียวและหลายจุดจากฐานข้อมูลได้ด้วย ASP.NET C# (ภาคต่อ)
    3) การดึงค่าละติจูดและลองจิจูดของสถานที่ด้วย Places search box บน Google Maps
    4) การค้นหาสถานที่ด้วย Places search box และแสดงผลภาพจากข้อมูล Street View บน Google Maps


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

 

  • Itextsharp #4 คู่มือเทคนิคพื้นฐานการใช้งาน PdfTable สำหรับมือใหม่ ตอนที่ 2

    บทความนี้สำหรับผู้ที่ยังไม่ได้อ่านบทความก่อนหน้านี้ สามารถอ่านบทความได้ที่ Itextsharp #3 คู่มือเทคนิคพื้นฐานการใช้งาน PdfTable สำหรับมือใหม่ ตอนที่ 1 เพื่อความเข้าใจต่อเนื่องกันนะครับ โดยเนื้อหาในบทความนี้เป็นส่วนของใช้งาน Table ที่ผู้เขียนเองใช้ในการทำงานคือการทำ Nest Table นั้นเองโดยปกติการสร้างเอกสาร1ใบ ผู้เขียนจะใช้ Table ตัวแรกในการกำหนดรูปแบบหน้าตาของเอกสาร การจัดตำแหน่งสัดส่วนต่างๆ หลังจากนั้นก็ใช้ Table ซ้อนเข้าไปตามส่วนต่างๆตามที่ออกแบบไว้มาจัดการส่วนของข้อมูล จึงจำเป็นต้องใช้งาน Nest Table เราไปดูตัวอย่างรูปกันก่อนดีกว่าครับ

    จากตัวอย่างจะพบว่าสำหรับคนที่เขียนโปรแกรมก็คือการซ้อนตารางปกติที่พบเจอได้ในการเขียนโปแกรม จากรูปคือเอาTable2 ใส่ใน Cell ที่1ของ Table1 หรือพูดภาษาของเขียนโปรแกรมคือเขียน Table2 ลงใน <TD> แรกของ Table1 นั้นเอง ซึ่งถามว่าทำงานคล้ายๆกับตารางทั่วไปแล้วสามารถรวมCell ก่อนเพิ่มตารางได้ไหมใน ItextSharp ทำได้เหมือนกันครับ ตามรูปเลยครับ

    จากตัวอย่างเป็นการรวม Collumn แล้วทำการเพิ่ม Table2 เข้าไปโดยใน ItextSharp เรากำหนดCollumn ของTable1และTable2 เท่ากัน ตัวโปรแกรมจะจัดขนาดของ Cell ให้เท่ากันอัตโนมัติเมื่อทำการแสดงผลเหมือนในรูปตัวอย่างครับ ส่วนการเขียนโปแกรมนั้นง่ายมากๆเพิ่มขั้นตอนจากตอนที่1มานิดเดียว เราไปดู Code กันเลยดีกว่าครับ

    PdfPCell PdfCell = null;
    
    PdfPTable PdfTableH = new PdfPTable(3);
    float[] tbHwidths = { 50f, 50f, 50f };
    PdfTableH.SetWidths(tbHwidths);
    PdfTableH.WidthPercentage = 100;
    
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 2 Cell 1", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTableH.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 2 Cell 2", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTableH.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 2 Cell 3", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTableH.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 2 Cell 4", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTableH.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 2 Cell 5", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTableH.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 2 Cell 6", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTableH.AddCell(PdfCell);
    
    //-----------------------------------------------------------------//
    
    PdfPTable PdfTable = new PdfPTable(3);
    float[] tbwidths = { 50f, 50f, 50f };
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    
    PdfCell = new PdfPCell(PdfTableH);// <---------------------------------#1
    PdfTable.AddCell(PdfCell);
    
    //PdfTable.AddCell(new PdfPCell(PdfTableH)); <-------------------------#2
    
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 1 Cell 2", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 1 Cell 3", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 1 Cell 4", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 1 Cell 5", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 1 Cell 6", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Table 1 Cell 7", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfTable.AddCell(PdfCell);
    

    ตัวอย่าง Code ผู้เขียนแบ่งเป็น 2ส่วนด้วยกันคือส่วนแรกเป็นการสร้าง Table2ก่อน เพราะเราจะเอาTableนี้ไปใส่ในTable1อีกที การเขียนก็เหมือนจากตัวอย่างที่ผ่านๆมาในบทความก่อนหน้านี้ เรามาดูส่วนที่2กันส่วนที่ต่างจากส่วนแรกคือ บรรทัดที่(#1) PdfCell = new PdfPCell(PdfTableH); โค๊ดนี้คือการเพิ่ม Table2 ลงไปใน Cell ที่เราต้องการครับ หรือจะใช้อีกรูปแบบ(#2)คือ PdfTable.AddCell(new PdfPCell(PdfTableH)); แค่นี้เราก็ทำ NestTable เสร็จสิ้นเป็นที่เรียบร้อย ง่ายไหมครับ แล้วถ้าเราจะรวม Cell ก่อนเพิ่ม Table ละจะทำยังไง หลายคนอาจทำได้โดยไม่ต้องดูตัวอย่างของผู้เขียนแล้วก็ได้ครับ แต่เราไปดูตัวอย่างกันดีกว่าครับ

    PdfCell = new PdfPCell(PdfTableH);
    PdfCell.Colspan = 3;
    PdfTable.AddCell(PdfCell);
    หรือ
    PdfTable.AddCell(new PdfPCell(PdfTableH) { Colspan = 3 });
    

    เหมือนที่คิดไว้ไหมครับหรือหลายๆคนอาจเขียนได้แบบอื่นก็ไม่ผิดครับ จากตัวอย่างแค่เพิ่มคำสั่ง Colspan เข้าไปใน Cell ก็เป็นอันเสร็จเรียบร้อย จบส่วนของการทำ Nest Table แล้ว เรามาดูตัวอย่างการใช้งานจริงจากผู้เขียนสักตัวอย่างกันครับ

    จากรูปตัวอย่างเอกสารประกอบไปด้วยส่วนของ Header Table1 ที่แสดงผลทุกหน้ากระดาษ และมีส่วนของเนื้อหาในหน้าแรกเป็นส่วนของ Body Table1 แล้วมีตารางของข้อมูลจำนวนหลายรายการโดยเมื่อตารางนี้ขึ้นหน้าใหม่ให้ทำการแสดงหัวตารางไปด้วย ผู้เขียนจะให้ส่วนนี้เป็น Table2 หรือ NestTable นั้นเอง ถ้าทุกท่านนึกภาพออกแล้วเราไปดูตัวอย่าง Code กันดีกว่าครับ

    PdfPCell PdfCell = null;
    
    PdfPTable PdfTableH = new PdfPTable(3);
    float[] tbHwidths = { 50f, 50f, 50f };
    PdfTableH.SetWidths(tbHwidths);
    PdfTableH.WidthPercentage = 100;
    PdfTableH.HeaderRows = 1;
    
    PdfCell = new PdfPCell(new Phrase(new Chunk("Header Table 2", bold)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfCell.Colspan = 3;
    PdfCell.FixedHeight = 20f;
    PdfTableH.AddCell(PdfCell);
    
    for (int i = 0; i < 60; i++)
    {
        PdfCell = new PdfPCell(new Phrase(new Chunk("Body Table 2", fnt)));
        PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
        PdfCell.PaddingBottom = 8;
        PdfTableH.AddCell(PdfCell);
    }
    
    PdfPTable PdfTable = new PdfPTable(1);
    float[] tbwidths = { 500f };
    PdfTable.SetWidths(tbwidths);
    PdfTable.WidthPercentage = 100;
    PdfTable.HeaderRows = 1;
    PdfTable.SplitLate = false;
    PdfTable.KeepTogether = true;
    
    PdfCell = new PdfPCell(new Phrase(new Chunk("Header Table 1", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfCell.PaddingLeft = 10;
    PdfTable.AddCell(PdfCell);
    PdfCell = new PdfPCell(new Phrase(new Chunk("Body Table 1", fnt)));
    PdfCell.HorizontalAlignment = Element.ALIGN_CENTER;
    PdfCell.PaddingBottom = 8;
    PdfCell.PaddingLeft = 10;
    PdfTable.AddCell(PdfCell);
    PdfTable.AddCell(new PdfPCell(PdfTableH));
    

    จาก Code ตัวอย่างผู้เขียนได้นำคำสั่ง HeaderRows มาใช้งานร่วมด้วยเพื่อให้ทำการยึดหัวตารางทั้งสองตารางเอาไว้ในหน้ากระดาษในหน้าถัดๆไปด้วย และผู้เขียนได้เพิ่มคำสั่งมาอีก 2 คำสั่งด้วยกัน เป็นคำสั่งเสริมขึ้นมาเพื่อให้การแสดงผลของข้อมูลสวยงามและถูกต้องตามที่เราต้องการ คือ PdfTable.SplitLate = false; และ PdfTable.KeepTogether = true; คำสั่งดังกล่าวใช้ในกรณีเราทำ NestTable ที่มีการแสดงผลมากว่า1หน้ากระดาษ แต่ถ้าเอกสารที่ทำมีเพียง1หน้ากระดาษแน่นอน คำสั่งดังกล่าวไม่ต้องเขียนก็ได้ครับ แล้วถ้าไม่ใส่ไปเลยได้ไหมถึงเอกสารจะมีหลายหน้า ผู้เขียนแนะนำว่าควรใส่ เพราะไม่มีคำสั่งนี้ Nest Table จะไม่แสดงผลในหน้าแรกเสมอครับแต่จะเลื่อนไปแสดงผลในหน้าที่สองแทน เนื่องจาก Itextsharp ทำการเลื่อนให้เองอัตโนมัติเมื่อตารางนั้นล้นเกินหน้ากระดาษแรก นั้นเอง

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

  • การเรียกใช้งาน (Register) Bootbox.js ด้วย C#.NET

    ในการออกแบบเว็บฟอร์มบันทึกข้อมูลลงฐานข้อมูลนั้น นักพัฒนาเว็บแอ๊พปลิเคชั่นส่วนใหญ่จะออกแบบเป็นลำดับขั้นตอนการทำงานประมาณนี้

    1. ผู้ใช้เปิดเว็บฟอร์มขึ้นมาด้วยเว็บบราวเซอร์
    2. ผู้ใช้กรอกข้อมูลลงในเว็บฟอร์ม
    3. ผู้ใช้กดปุ่มบันทึกข้อมูล
    4. ระบบตรวจสอบ (Validate) ข้อมูลที่ผู้ใช้กรอกเข้ามา
      1. ถ้าผ่านก็บันทึกข้อมูลลงฐานข้อมูล
      2. ถ้าไม่ผ่านก็จะแจ้งข้อความแจ้งเตือนผู้ใช้งานให้ตรวจสอบข้อมูลใหม่อีกครั้ง
    5. ระบบจะแจ้งผลการบันทึกข้อมูลว่า
      1. “บันทึกข้อมูลสำเร็จ” กรณีที่บันทึกสำเร็จ หรือ
      2. “เกิดข้อผิดพลาดในการบันทึกข้อมูล” ในกรณีที่มีข้อผิดพลาด

    การพัฒนาเว็บด้วย ASP.NET นั้นในขั้นตอนที่ 4 จะถูกเขียนด้วยโค้ด C#.NET ซึ่งเป็น Server Side Script ส่วนขั้นตอนที่ 5 นั้นเราสามารถใช้ Dialog ของ Bootbox.js ซึ่งเป็น Client Side Script มาช่วยได้ ซึ่งในบทความนี้จะแสดงวิธีการเขียนโค้ด C#.NET ให้เรียกใช้ Bootbox Dialog ได้เลย  (อ่านบทความ การสร้าง JavaScript Dialog ด้วย Bootbox.js ได้ที่นี่) และสร้างเป็นฟังก์ชั่นสำเร็จรูปไว้เรียกใช้งานใหม่ได้ (Reuse)

     

    การรันคำสั่ง Bootbox.js ซึ่งเป็น JavaScript ผ่าน C#.NET นั้นจะต้องใช้ ScriptManager ช่วยลงทะเบียนสคริปต์ (Register Script) ดังนี้

    รูปที่ 1 การ Register Script ด้วย ScriptManager

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

    รูปที่ 2 การแสดงข้อความแจ้งผู้ใช้หลังการบันทึกข้อมูล

    ผลลัพธ์ที่ได้จากโค้ดข้างต้นจะเป็นดังรูปที่ 3

    รูปที่ 3 ผลลัพธ์ของข้อความแจ้งเตือนจากการบันทึกข้อมูล

    แน่นอนว่าในการพัฒนาเว็บแอ๊พปลิเคชัน 1 ครั้ง จะประกอบด้วยฟอร์มบันทึกข้อมูลมากมาย ทำให้ต้องเขียนโค้ดซ้ำๆ กันหลายครั้ง จากโค้ดข้างต้นเราสามารถ Optimize โค้ดได้อีกโดยให้สามารถเรียกใช้งานและแก้ไขโค้ดในภายหลังได้ง่ายขึ้น โดยการย้ายส่วนลงทะเบียนสคริปต์ไปไว้ในฟังก์ชั่นกลางสร้างเป็น Library (ในที่นี้จะตั้งชื่อว่า CoreBLL) สำเร็จรูปไว้ใช้ต่อไปดังนี้

    รูปที่ 4 CoreBLL

    หลังจากที่สร้าง CoreBLL เสร็จแล้วให้แก้ไขโค้ดบันทึกข้อมูลดังรูปที่ 5

    รูปที่ 5 โค้ดบันทึกข้อมูลลงฐานข้อมูล

    จะเห็นว่า CoreBLL ทำให้โค้ดในการบันทึกข้อมูลฟอร์มสั้นลง ง่ายขึ้น และช่วยลดความผิดพลาดในการเขียนโค้ดลง ในขณะที่หน้าจอผลลัพธ์ (รูปที่ 3) ยังคงเหมือนเดิม

     

  • การสร้าง JavaScript Dialog ด้วย Bootbox.js

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

    JavaScript Confirm บน Google Chrome

     

    JavaScript Confirm บน Mozilla Firefox
    ตัวอย่างโค้ดเรียกใช้งาน JavaScript Confirm

    จากรูปจะเห็นว่า JavaScript Confirm บน Google Chrome และ Mozilla Firefox หน้าตาไม่เหมือนกัน ทั้งๆที่ใช้โค้ดเดียวกัน และปัญหาอีกอย่างหนึ่งที่พบคือ หากเราต้องการให้ข้อความ “คุณต้องการลบข้อมูลรายการนี้ใช่หรือไม่?” มีการขึ้นบรรทัดใหม่ ใส่สี เพิ่มขนาดฟอนต์ จัดตัวหนา ตัวเอียงก็ไม่สามารถทำได้เลย แต่ถ้าต้องการให้แก้ปัญหาเหล่านี้ได้ก็ต้องใช้ตัวช่วย นั่นคือ Bootbox.js ซึ่งเป็น JavaScript library ที่ใช้งานร่วมกับ Bootstrap โดยใช้ Bootstrap modal มาทำหน้าที่แทน JavaScript Dialog ต่างๆ ทั้ง Alert, Confirm, Prompt และรวมถึง Custom Dialog ด้วย ทำให้หน้าตาของ Dialog จะเหมือนกันทุก Browser และสามารถจัดรูปแบบการแสดงผลได้ตามต้องการโดยใช้ CSS

    วิธีการติดตั้ง

    1. เข้าไปที่เว็บไซต์ http://bootboxjs.com และเลือกดาวน์โหลดไฟล์ชื่อ bootbox.min.js หรือถ้าไม่ต้องการดาวน์โหลดก็สามารถใช้ CDN (https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js) ได้เช่นกัน
    2. ใส่โค้ดอ้างอิงไปยัง bootbox.min.js ใน header tag ดังนี้
      <script src=”path/to/script/bootbox.min.js”></script>
      หรือ
      <script src=https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js></script>

    ตัวอย่างการใช้งาน Confirm Dialog

    1. กำหนดชื่อ CSS class ให้กับปุ่มลบ ในที่ตั้งชื่อว่า “confirm”

      กำหนดชื่อ CSS Class ให้กับปุ่มลบ
    2. แทรกโค้ด JavaScript ใน HTML ดังนี้

      JavaScript สำหรับ Confirm Dialog
    3. ลองเปิดเว็บด้วย Google Chrome และ Mozilla Firefox ก็จะได้ผลลัพธ์เหมือนกันดังรูป

      Confirm Dialog ที่สร้างขึ้นด้วย Bootbox.js

    นอกจาก Confirm Dialog แล้ว ท่านสามารถดูตัวอย่าง Dialog แบบอื่นๆ ได้จากที่นี่ เพียงเท่านี้ก็จะสามารถสร้าง Dialog สวยๆ และมีความยืดหยุ่นไว้ใช้งานได้แล้ว

     

  • ติดตั้ง Microsoft Office 2010 บน Linux Mint 18.2

         สวัสดีวันค่ะ… บล็อคนี้เราก็ยังคงอยู่กับ Linux Mint “Sonya” ที่มาพร้อมกับ Applicationพื้นฐานติดตั้งมาด้วย สำหรับคนที่ยังไม่คุ้นเคยกับ Linux ก็จะมีคำถามว่าแล้วโปรแกรมนี้ที่เคยใช้ในฝั่ง Windows มันมีให้ใช้ใน Linux มั้ย อย่างเช่น Microsoft Office อันนี้ Linux ก็มี LibreOffice ให้ใช้แทน และ LibreOffice Writer สามารถ Save เป็น นามสกุล .doc, .docx มาเปิดบน Windows ได้ แต่ Fonts อาจจะเพี้ยนๆหน่อยตอนเอามาเปิดบน Windows ก็มีทางเลือกให้เราติดตั้ง Fonts ที่ต้องการลงไป ดังภาพที่ 1

     

     

    ภาพที่1 ติดตั้ง Font บน Linux

    หรือไม่แน่ใจว่า Office ตัวอื่นจะประสบปัญหาอะไรไหมตอนเอาไปเปิดกับ Windows อยากได้โปรแกรมของ Microsoft Office ทั้งหมดเอาไปใช้เลย!! ก็ทำได้ ก่อนอื่นก็ต้องลง PlayOnLinux ซึ่งเป็นโปรแกรมที่ช่วยให้สามารถใช้โปรแกรม Windows บน Linuxได้ โดยทำตามขั้นตอนดังนี้ค่ะ

    Step1: ไปที่ Software Manager > Search Palyon… > Install > รอวนไปค่ะ ช้าเร็วขึ้นกับเน็ตด้วย ตามภาพที่ 2

    ภาพที่2 Install PlayOnLinux

    Step2: เปิดโปรแกรม PlayOnLinux ดังภาพที่ 3

    ภาพที่3 Open PlayOnLinux

    เมื่อรัน PlayOnLinux ขึ้นมา ให้กด Install ดังภาพที่ 4

    ภาพที่4 หน้าจอ PlayOnLinux 

    เลือกเมนู Office และเลือก Microsoft Office Version ที่ต้องการติดตั้ง ตามภาพที่ 5

    ภาพที่5 List Program in Office Category

    จากนั้นก็ Next Step ไปค่ะ ตามภาพที่ 6

    ภาพที่6 Installation Wizard

    ระหว่างทางนั้น ในเมื่อชีวิตเราไม่ได้โรยด้วยกลีบกุหลาบ Error ตามภาพที่ 7 ก็มา  ตั้งสติแล้วก็ไปลง winbind ซะ!!!

    ภาพที่7 Fatal Error

    กลับมาลง Office กันอีกที Again & Again(ไปฟังเพลงปลอบใจพลางนะ) ถ้าคุณได้ไปต่อมันก็จะขึ้นให้ Browse ไปยังที่เก็บไฟล์ .exe ตามภาพที่ 8 กด Open ไปอีกหน้าจอ แล้วกด Next รอจนติดตั้งเสร็จ

    ภาพที่8 Setup File

    ในที่สุดก็ติดตั้งเสร็จ จะแสดงผลลัพธ์ดังภาพที่ 9  ซึ่ง Shortcut ถูกสร้างไว้บน Desktop สามารถเรียกใช้ได้เลย ตามภาพที่ 10

    ภาพที่9 Installed Program

    ภาพที่10 Office Shortcut on Desktop

  • การเติมข้อมูล PDF Fill Form ผ่านโปรแกรมด้วย iTextSharp

    เนื่องจากในช่วงที่ผ่านมาผมได้เข้าร่วมในโครงการที่ต้องพัฒนาโปรแกรมที่มีการกรอกข้อมูลลงฟอร์ม และต้องการให้พิมพ์ข้อมูลต่างๆเป็น PDF จึงได้มีโอกาสศึกษาการใช้ PDF Fill Form และ iText Sharp Library เพื่อนำมาใช้ในการพัฒนา ผมจึงคิดว่าน่าจะเอาสิ่งที่ได้ศึกษามาเล่าสู่กันฟัง เผื่อมีท่านใดสนใจจะนำไปใช้ครับ

    เริ่มต้นทำสร้าง PDF Fill Form

    โดยทั่วไปเราจะใช้งาน Pdf File เพื่ออ่านกันเป็นส่วนใหญ่ แต่จริงๆแล้ว PDF นั้นสามารถจะสร้าง form สำหรับใช้กรอกข้อมูลลงบนตัวเอกสารได้ด้วยครับ โดยมีวิธีการดังนี้

    1.นำเอกสารแบบฟอร์ม ซึ่งเป็นไฟล์ word มาทำการสั่ง export  เป็นไฟล์ PDF หรือถ้ามีไฟล์ PDF ที่เป็นแบบฟอร์มอยู่แล้วก็สามารถนำมาใช้ได้เลย โดยทำตามภาพนะครับ

    2.นำไฟล์ PDF ที่ได้มา เปิดด้วยโปรแกรม Adobe Acrobat Pro

    3.คลิก Tools เพื่อทำการ edit โดยโปรแกรมจะถามว่าต้องการให้โปรแกรมสร้าง field อัตโนมัติให้หรือไม่ ถ้าตอบตกลงโปรแกรมจะสร้าง field ข้อมูลให้ในพื้นที่เอกสารที่คาดว่าจะเป็นช่องว่างสำหรับกรอกข้อมูลให้

    4.ทำการแก้ไขชื่อ field ข้อมูลให้เป็นชื่อที่เราต้องการ โดยคลิกเมาส์ขวาที่กล่อง field และเลือกเมนู property จะมี Popup ให้แก้ไขรายละเอียดต่างๆของ field

    5.หากต้องการเพิ่ม field ใหม่ เราสามารถเพิ่ม รูปแบบ field หลายแบบ เช่น

    – Text Box เป็น Field ที่ใช้เก็บข้อความต่างๆ

    – Check Box เป็น Field ที่ใช้เก็บค่าในการเลือกข้อมูลในฟอร์มแบบช่องสี่เหลี่ยม

    – Radio Box เป็น Field ที่ใช้เก็บค่าในการเลือกข้อมูลในฟอร์มเช่นกัน แต่จะแตกต่างกับ Check Box ที่เป็นวงกลม และจะเลือกค่าได้เพียงค่าเดียวในกลุ่มข้อมูลชุดเดียวกัน เช่น การกรอกข้อมูลเพศ ที่จะเลือกได้เพียงแค่เพศเดียว

    6.เมื่อสร้าง field จนครบถ้วนก็ทำการบันทึกไฟล์ คลิกเลือกไปที่เมนู File -> Save เพียงเท่านี้ก็จะได้ไฟล์ PDF ที่เป็นแบบฟอร์มส่งไปให้ผู้ใช้กรอกข้อมูล และบันทึกส่งเป็นไฟล์ PDF กลับมา

     

    ตัวอย่างการใช้ iText Sharp บน C# เติมค่าลงใน PDF Fill Form

    เพียงเท่านี้เราก็สามารถจะสามารถส่งข้อมูลจากโปรแกรมของเราไปกรอกในไฟล์ PDF ที่เราได้สร้างเป็น template ได้ พร้อมให้ user นำข้อมูลไปใช้ได้ทันทีครับ

  • การเรียกดูรายการ object ในฐานข้อมูล Oracle

    คำสั่งที่ใช้ในการเรียกดู รายการ object ในฐานข้อมูล Oracle

    • การเรียกดูรายการ object ทั้งหมดในฐานข้อมูล Oracle (เช่น table, view ฯลฯ)  สามารถเรียกดูได้จาก view ที่ชื่อว่า ALL_OBJECTS  ตัวอย่างคำสั่งคือที่ใช้เรียกดูคือ

     

    SELECT * FROM ALL_OBJECTS;

     

    โดยคำสั่งนี้จะแสดงรายการ object ทั้งหมดที่มี

     

    • แต่ในการใช้งานส่วนใหญ่ อาจจะต้องการเจาะจงดูแค่บางเงื่อนไข เช่น ต้องการดูรายการ table ทั้งหมด โดยเจาะจงแค่ schema ใด schema  หนึ่งเท่านั้น  ซึ่งสามารถใช้เงื่อนไขจากฟีลด์ต่อไปนี้ คือ
      • OBJECT_TYPE เป็นการเรียกดูตามเงื่อนไขของประเภท object เช่น หากต้องการดูเฉพาะ table จะใช้เงื่อนไขเป็น  WHERE OBJECT_TYPE = ‘TABLE’
      • OWNER เป็นการเรียกดูเฉพาะเจาะจง schema ใด schema  หนึ่ง เช่น ต้องการเรียกดูข้อมูลจาก schema ชื่อ SCOTT จะใช้เงื่อนไขเป็น WHERE OWNER = ‘SCOTT’
      • ตัวอย่างคำสั่งเต็ม ๆ กรณีที่ต้องการเรียกดูเฉพาะ table ทั้งหมดที่อยู่ใน schema ที่ชื่อ SCOTT

    SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE=’TABLE’ AND OWNER=’SCOTT’;

     

    ตัวอย่างการนำไปใช้ประโยชน์

    เพื่อให้เห็นภาพการนำไปใช้งานจริง จึงขอยกตัวอย่างที่เคยใช้งาน คือ การสร้างสคริปต์คำสั่ง sql ที่อ้างอิงชื่อ table ที่อยู่ใน schema ใด schema หนึ่ง โดยในที่นี้จะยกตัวอย่างการ grant สิทธิ์ในการเข้าถึงข้อมูลของ schema หนึ่งไปให้กับอีก schema หนึ่ง

    • ที่มาที่ไปคือ ในบางครั้ง เราต้องการ grant สิทธิ์ในการเข้าถึงข้อมูลของ schema หนึ่งไปให้กับอีก schema หนึ่ง เช่น ต้องการ grant สิทธิ์การเรียกดูข้อมูลใน table ชื่อ TABLE01 ของ schema ที่ชื่อ SCHEMA01 ให้ schema ที่ชื่อ SCHEMA02 สามารถเรียกดูข้อมูลได้ คำสั่งที่ใช้ในการ grant คือGRANT SELECT ON SCHEMA01.TABLE01 TO SCHEMA02;
    • แต่หากต้องการ grant หลาย ๆ  table ก็ต้องพิมพ์คำสั่งเหล่านี้ทีละคำสั่งซ้ำๆ ไปจนครบตามชื่อ talbe ที่ต้องการ grant ซึ่งถ้า table ที่ต้องการ grant มีเป็นจำนวนมากก็จะยิ่งใช้เวลามากยิ่งขึ้น และอีกปัญหาคือ มีโอกาสพิมพ์ชื่อ table ผิด
    • เทคนิคในการสร้างสคริปต์เพื่อช่วยให้การทำงานรวดเร็วขึ้นจะมีรูปแบบดังนี้คือSELECT ‘GRANT SELECT ON OWNER_SCHEMA.’ || OBJECT_NAME || ‘ TO OTHER_SCHEMA;’
      FROM ALL_OBJECTS
      WHERE OBJECT_TYPE = ‘TABLE’;

      เมื่อ

      • OWNER_SCHEMA คือชื่อของ schema ที่เป็นเจ้าของ table
      • OBJECT_NAME คือชื่อฟีลด์ที่อยู่ใน ALL_OBJECTS โดยเป็นข้อมูลของชื่อ object ซึ่งกรณีนี้คือชื่อของ table นั่นเอง
      • OTHER_SCHEMA คือชื่อของ schema ที่ได้รับการ grant สิทธิ์ให้เรียกดูข้อมูลใน table ของ OWNER_SCHEMA
      • WHERE OBJECT_TYPE = ‘TABLE’ เป็นการระบุเงื่อนไขว่าต้องการ object ที่เป็น table เท่านั้น

    ผลลัพธ์ที่ได้คือ

    GRANT SELECT ON OWNER_SCHEMA.TABLE01 TO OTHER_SCHEMA;

    GRANT SELECT ON OWNER_SCHEMA.TABLE02 TO OTHER_SCHEMA;

    GRANT SELECT ON OWNER_SCHEMA.TABLE03 TO OTHER_SCHEMA;

    GRANT SELECT ON OWNER_SCHEMA.TABLE04 TO OTHER_SCHEMA;

    …….

    …….

    …….

    GRANT SELECT ON OWNER_SCHEMA.TABLE99 TO OTHER_SCHEMA;

     

    โดยคำสั่งทั้งหมดจะเท่ากับจำนวน table ของ OWNER_SCHEMA นั่นเอง ซึ่งหากไม่ต้องการ grant table ไหนก็ลบคำสั่ง grant เฉพาะ table นั้นออกไปได้

    • จะเห็นว่าการใช้เทคนิคลักษณะนี้ จะทำให้สามารถสร้างสคริปต์คำสั่งที่มีลักษณะแบบเดียวกันได้ภายในเวลาอันรวดเร็ว และลดความผิดพลาดของการอ้างอิงชื่อ object ลงไปได้ด้วย
    • อ้างอิงข้อมูล https://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_2005.htm#i1583352

     

     

     

     

     

  • Unlimited multi level menu in mvc

    สวัสดีค่ะวันนี้เรามาว่ากันเรื่องเมนูกันดีกว่านะคะ คำว่าเมนู ผู้เขียนคิดว่าทุกคนต้องรู้จักแน่นอน เพราะในการพัฒนาแต่ละระบบนั้นส่วนใหญ่จะมีส่วนของงานหลายๆส่วน ทำให้มีการออกแบบหน้าจอการใช้งานหลายหน้าจอเพื่อรองรับการทำงานของระบบนั้น เมื่อส่งมอบระบบ แน่นอน!! ค่ะ ความต้องการของลูกค้าไม่หยุดแค่นั้นแน่นอน เมื่อความต้องการเพิ่ม การทำงานของหน้าจอก็เพิ่ม เมนูก็ต้องเพิ่มตามมาเช่นกัน ทำให้ผู้พัฒนาต้องไปแก้โค้ดในส่วนของเมนูทุกครั้งที่มีการเพิ่มเมนู การจัดหมวดหมูของเมนู หรือต้องการปรับเปลี่ยน path ที่ไปเรียกหน้าจอนั้นๆ แค่คิดก็ดูยุ่งยากต่อการจัดการแล้ว วันนี้ผู้เขียนจึงนำวิธีการออกแบบและพัฒนาในส่วนของเมนูที่ผู้เขียนได้ใช้พัฒนาใน MVC มาเป็นตัวอย่างให้ดูกันนะคะ สำหรับผู้อ่านที่ไม่ได้ใช้ MVC ก็สามารถนำไปปรับเปลี่ยนได้ค่ะ หลังจากพัฒนาแล้วระบบก็จะสามารถ เพิ่มเมนู หรือเปลี่ยน path ของเมนู หรือ จัดการกลุ่มของเมนู ได้โดยไม่ต้อง publish ระบบ ทุกครั้งที่มีการแก้ไข ทำให้ง่ายและไม่เสียเวลาในการจัดการเลยค่ะ เรามาเริ่มกันเลยค่ะ ผู้เขียนขอแบ่งการพัฒนาเป็นสองส่วนนะคะ คือ
    1.การพัฒนาในฐานข้อมูล : ในส่วนของการออกแบบฐานข้อมูลผู้อ่านต้องออกแบบให้มีการเก็บ id ของ parent เพื่อระบุให้รู้ว่าเมนูตัวนี้เป็นลูกของเมนูตัวไหน

    ตัวอย่างการออกแบบฐานข้อมูลของเมนู

    คอลัมภ์ คำอธิบาย
     ParentID Id ของ parent
    MenuID Id ของเมนู
    MenuName ชื่อของเมนู

    2.การพัฒนาระบบ : เป็นการพัฒนาระบบผู้เขียนจะใช้วิธีการพัฒนาแบบใช้ Recursive เข้ามาจัดการในส่วนของการแสดงเมนู โดยข้อดีของ Recursive คือเราสามารถจัดการได้ทั้งส่วนที่มีเมนูย่อย และไม่มีเมนูย่อย

    ตัวอย่างในส่วนของ Recursive ที่ใช้ใน View เพื่อการแสดงเมนู ( MVC)

    @helper GetSubMenus(IEnumerable<menutable> siteMenu, Nullable<int> parentID)

    {

        foreach (var i in Model.Where(a => a.ParentID.Equals(parentID)))

        {

            var submenu = Model.Where(a => a.ParentID.Equals(i.MenuID)).Count();

     

            <li class=”@(submenu > 0 ? “dropdown-submenu” : “dropdown”)”>

                <a href=”@(!string.IsNullOrEmpty(i.MenuLink) ? Url.Content(i.MenuLink) : “~/default)” style=”font-size:16px;”>@i.MenuName</a>

                @if (submenu > 0)

                {

                    <ul class=”dropdown-menu”>

                        @GetSubMenus(siteMenu, i.MenuID)

                        @* Recursive  Call for Populate Sub items here*@

                    </ul>

                }

            </li>

        }

    }

     

    @{

        var mymenu = @Model;

        var menuParentID = mymenu.First().ParentID;

    @if (mymenu != null && mymenu.Count() > 0)

    {

        <nav class=”navbar navbar-default”>

            <div class=”container-fluid”>

                <div class=”collapse navbar-collapse” id=”bs-example-navbar-collapse-1″>

                    <ul class=” nav navbar-nav”>

                        @GetSubMenus(mymenu, menuParentID)

                    </ul>

                </div>

            </div>

        </nav>

    }

    ตัวอย่างหน้าจอของเมนูที่เรียกใช้ Recursive เพื่อจัดการเมนู

    จากรูปจะเป็นตัวอย่างของเมนูที่มีเมนูย่อย โดยมีเมนูหลักเป็น Parent ในรูป คือ testsub2 โดยมีลูก(Child) เป็น jar2 และ jar และ jar ก็เป็น Parent โดยมี testSub เป็นลูก(Child) อีกครั้ง จะเห็นว่าไม่ว่าจะต้องการให้มีเมนูย่อยแค่ไหน Recursive ก็สามารถทำเราง่ายในการจัดการมากขึ้น โดยไม่ต้องมา copy code วางหลายๆครั้งให้ยุ่งยากอีกต่อไปค่ะ และที่สำคัญในตัวอย่างเราจะดึงข้อมูลเมนูมาจากฐานข้อมูล ไม่ว่าเราจะเพิ่มเมนู หรือเปลี่ยน path หรือเพิ่มเมนูย่อยในเมนูหลักลงลึกแค่ไหน เราก็ไม่ต้องมาเสียเวลานั่งแก้โค้ดในหน้าของเมนูอีกต่อไปแล้วนะคะ ผู้อ่านท่านใดมีการจัดเมนูหลายเมนู ลองนำไปปรับใช้กันดูนะคะ ขอบคุณค่ะ^^

     

     

     

    แหล่งอ้างอิง

    https://stackoverflow.com/questions/35326302/unlimited-multi-level-menu-in-mvc