Category: Javascript

  • วิธีการ set property ของ radio button ใน Dojo

    เนื่องจากช่วงนี้ ผู้เขียนมีโอกาสได้เข้ามาอยู่ในแวดวงของ Dojo และได้ประสบกับปัญหาในการที่จะ set property ของ Dojo ซึ่งในที่นี้คือ Radio Button หลังจากที่ได้ลองผิด ลองถูก Error กันหัวหมุน  จนสุดท้ายได้เจอทางออก  เลยอยากจะบันทึกไว้สำหรับตัวเองมาดูในอนาคต และเผื่อท่านอื่นที่ประสบปัญหาเดียวกัน มาเจอจะได้ลองนำไปใช้งานกันดูค่ะ Let’s GO!!!

     

    เนื่องจาก Radio Button เป็น Control ภายใต้ dijit/form/RadioButton ดังนั้น การเขียนคำสั่งเพื่อ set property จึงได้เป็นดังนี้

    dijit.byId(‘control_id‘).set(‘control_prop‘, value);

    control_id : id ของ control นั้น ๆ

    control_prop : property ของ control ที่ต้องการกำหนดค่า

    value : ค่าที่ต้องการกำหนด

     

    ตัวอย่างเช่น ต้องการกำหนดให้ radio button ที่มี id=”rdBtn1″ ไม่สามารถใช้งานแต่ยังแสดง(disable) และ

    id=”rdBtn2″ มีค่าโดยปริยายเป็นเลือกไว้ จะเขียน Code ได้ดังนี้

    dijit.byId(‘rdBtn1’).set(‘disabled’, true); 

    dijit.byId(‘rdBtn2’).set(‘checked’, true); 

     

    ซึ่ง properties ของ control ต่าง ๆ สามารถดูเพิ่มเติมได้จากเว็ปเพจของ Dojo ตามลิงค์นี้ค่ะ Dojo Documentation

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

  • การใช้ jQuery ร่วมกับ library อื่นๆ ด้วยโหมด no-conflict

    ในบางครั้งท่านผู้อ่านอาจจะมีปัญหา ในการนำ jQuery ไปใช้กับ ร่วมสคริปต์อื่นๆ หรือแม้กระทั่งพวก css framework ที่บางตัวจะมีการฝัง script ไว้ข้างในด้วย  ซึ่งอาจทำให้ script ของท่านทำงานผิดเพี้ยนไปจากที่ควรเป็น  วันนี้จะขอแนะนำเทคนิคในการแก้ปัญหาดังกล่าว นั่นก็คือ การปรับ jQuery ไปใช้งานในโหมด no-conflict นั่นเองค่ะ

     

    สิ่งที่พึงระวังสำหรับมือใหม่ก็คือ ตัว jquery เองนั้นจะใช้ตัวแปร $  อ้างถึงฟังก์ชั่น jQuery  ดังนั้น ถ้ามีสคริปต์ตัวอื่นที่ใช้ตัวแปร $ นี้เหมือนกันล่ะก็  เกิดปัญหาขึ้นแน่นอนค่ะ

    วิธีแก้ปัญหา

     วิธีที่ 1 คือให้สร้างตัวแปรเพิ่มขึ้นมาอีกตัวเพื่อใช้แทนเครื่องหมาย $

    ตัวอย่างพร้อมคำอธิบาย

    <script src="other_library.js"></script>
    
    <script src="jquery.js"></script>
    
    <script>
    
    //ในที่นี้เราประกาศตัวแปร $j แทนตัว $
    
    var $j = jQuery.noConflict();
    
    $j(document).ready(function(){
    
    $j("div").hide();
    
    });
    
    
    // ถึงตรงนี้ตัวแปร $ จะหมายถึงตัวแปรจากสคริปต์ other_library.js
    
    // mainDiv ดังนั้นคำสั่งข้างล่างนี้ $('main') จึงหมายถึงการเรียกฟังก์ชั่น
    
    // จาก other_library ไม่ใช่การเรียกฟังก์ชั่นของ jquery
    
    window.onload = function(){
    
    var mainDiv = $('main');
    
    }
    
    </script>
    
    

    วิธีที่ 2 ในกรณีที่ไม่ต้องการประกาศตัวแปรเพิ่ม ในที่นี้เราสามารถใช้งานตัวแปร $ ได้แต่เป็นการเรียกใช้แบบ locally scope(เรียกใช้เฉพาะในบล็อคของ jQuery เอง)

    ตัวอย่างพร้อมคำอธิบาย

    <script src="other_library.js"></script>
    
    <script src="jquery.js"></script>
    
    <script>
    
    jQuery.noConflict();
    
    jQuery(document).ready(function($){
    
    // การใช้ตัวแปร $ ในนี้จะหมายถึง jQuery (locally scope)
    
    $("div").hide();
    
    });
    
    // ส่วนการใช้ตัวแปร $ นี้จะหมายถึงการเรียกใช้แบบ global scope
    
    // ซึ่งในที่นี้หมายถึงการเรียกใช้ $ ของ other_library นั่นเอง
    
    window.onload = function(){
    
    var mainDiv = $('main');
    
    }
    
    </script>
    
    

    การเรียกใช้งานแบบนี้จะทำให้เราไม่สับสนกรณีที่เขียนโค๊ดยาวๆ หรือใช้ไลบราลีหลายตัว

    สองวิธีข้างต้น จะสังเกตว่าเรา include สคริปต์ jQuery หลังสคริปต์ตัวอื่น กรณีที่เรามีการ include สคริปต์ jQuery ก่อนสคริปต์ตัวอื่น จะทำอย่างไร?

    ในกรณีที่เรา include jQuery มาก่อนและหากสคริปต์ที่ตามหลังใช้ตัวแปร $ จะถือว่าตัวแปร $ นั้นเป็นของสคริปต์ที่ประกาศที่หลัง(override) ซึ่งถ้าเราต้องการใช้งาน jQuery จะทำได้โดยการเรียกใช้ฟังก์ชั่น  jQuery โดยตรง  ดังตัวอย่างข้างล่างนี้

    ตัวอย่างพร้อมคำอธิบาย

    <script src="jquery.js"></script>
    
    <script src="other_library.js"></script>
    
    <script>
    
    //เรียกใช้ jQuery ฟังก์ชั่นแบบเต็ม
    
    jQuery(document).ready(function(){
    
    jQuery("div").hide();
    
    });
    
     
    
    // เรียกใช้ตัวแปร $ ที่ระบุไว้ใน other_library.js
    
    window.onload = function() {
    
    var mainDiv = $('main');
    
    };
    
     
    
    </script>
    
    

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

    แหล่งอ้างอิงhttp://learn.jquery.com/using-jquery-core/avoid-conflicts-other-libraries/

     

  • วิธีการตรวจสอบข้อมูลในรูปแบบ JSON

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

    ซึ่งในบทความนี้จึงขอเสนอเว็บไซต์ที่ช่วยในการตรวจสอบข้อมูลและแบ่งชั้นของข้อมูลที่ซ้อนกันหลาย ๆ ชั้น ในรูปแบบ JSON ได้ คือ https://jsonformatter.curiousconcept.com

    1

    จากรูป  มีสิ่งที่ต้องระบุหลัก ๆ คือ

    1. JSON Data/URL สามารถวางข้อมูลหรือ URL ของข้อมูลได้ทั้งสองอย่าง
    2. JSON Standard เลือกว่า JSON ของเราสร้างโดยมาตรฐานใด หรือเราอยากตรวจสอบว่า JSON ที่เราสร้างอยู่ในมาตรฐานที่เราต้องการไหม2

      เมื่อกำหนดเรียบร้อยก็กดปุ่ม Process
      3

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

      หากข้อมูลผิดล่ะ จะเป็นไง ลองทำกันดู 

      4

      ในกรณีที่ไม่ถูกต้อง ระบบจะแสดงบรรทัด ที่ไม่ถูกต้อง แล่ะเมื่อคลิก มันจะแสดงสีแดงที่บรรทัดหรืออักษรที่ไม่ถูกต้องให้เราเห็นอีกด้วย

  • การอัปโหลดไฟล์หลาย ๆ ไฟล์พร้อมกันด้วย Dojo

    ที่มา

    การ upload แฟ้มข้อมูล (File) เป็นกิจกรรมที่อยู่คู่กับ Web application มาเนิ่นนาน ยิ่งเมื่อการพัฒนา Web application เข้าสู่ยุคสมัยของ Web 2.0 และเป็น Web 3.0 ในยุคปัจจุบันก็ยิ่งเกิดเครื่องมือต่าง ๆ เพื่ออำนวยความสะดวกในการ upload ไฟล์มากขึ้นรวมไปถึงความสามารถในการอัปโหลดหลาย ๆ ไฟล์พร้อมกัน (Multi-File Uploading)

    ณ เวลานี้มีเครื่องมือมากมายสำหรับนักพัฒนา Web application  ผู้อ่านอาจมีโอกาสได้ใช้งานเครื่องมือจากบางค่ายบ้างแล้ว แต่ในบทความนี้ผู้เขียนจะแนะนำวิธีการใช้งานเครื่องมือในการทำให้ Web application ของเราสามารถรองรับความต้องการในการอัปโหลดไฟล์หลาย ๆ ไฟล์ได้พร้อมกันตัวหนึ่งชื่อ HTML5 Multi-File Uploader ของ Dojo Toolkit ซึ่งทำงานได้ตามความต้องการของผู้เขียนดังนี้

    ความต้องการ

    1. สามารถ upload file ได้หลาย ๆ ไฟล์พร้อมกัน
    2. upload file ด้วย AJAX
    3. ต้องไม่มีการ Post Back หรือทำให้เกิดการ Load หน้า Web ใหม่
    4. สามารถปรับแต่งได้ตามความต้องการ

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

    ศึกษาคุณสมบัติของเครื่องมือ

    HTML5 Multi-File Uploader เป็นส่วนหนึ่งใน package ชื่อ dojox (dojox/form/Uploader) ซึ่งในความเป็นจริงแล้ว เครื่องมือตัวนี้ไม่ได้เจาะจงเฉพาะการใช้งาน HTML5 เท่านั้นแต่ยังคงใช้งานกับ Flash หรือ iframe ได้ด้วยตามแต่ผู้ใช้จะปรับแต่งเนื่องจาก Web browser แต่ละยี่ห้อก็มีข้อจำกัดแตกต่างกันไปตาม Browser engine และ Rendering engine

    ตามชื่อของเครื่องมือ Uploader ใช้ input ของ HTML5 เป็นองค์ประกอบหลัก จึงต้องกำหนดใน Form ให้รองรับการอัปโหลดไฟล์ด้วยการกำหนด attribute ชื่อ method และ enctype ดังนี้

     

    <form method=”post” enctype=”multipart/form-data”> 

     

    การสร้าง Widget ของ Uploader ทำได้ 2 รูปแบบดังนี้

    Programmatically

    require([

    “dojox/form/Uploader”

    ], function (Uploader) {

    myUploader = new dojox.form.Uploader();

    }

     

    Markup

    <input name=”uploadedFile” multiple=”true” type=”file” data-dojo-type=”dojox/form/Uploader” data-dojo-props=”label: ‘Select Some Files’,……..” />

    <div id=”files” data-dojo-type=”dojox/form/uploader/FileList” data-dojo-props=”uploaderId: ‘uploader’”></div>

    ลองใช้งาน

    เนื่องจากผู้เขียนพัฒนา Web application ด้วย Visual C# จึงจะยกตัวอย่างการประยุกต์การใช้งาน Uploader ร่วมกับ ASP.NET ซึ่งมีขั้นตอนดังนี้

    1. นำ Widget มาวางในส่วนที่เราต้องการ

    <input name=”uploadedfile” type=”file” id=”uploader” data-dojo-id=”fileUploader” data-dojo-type=”dojox/form/Uploader” data-dojo-props=”label: ‘Select files’, url: ‘../Test/TestUpload.ashx’, multiple: true” />
    <input type=”hidden” name=”hdnMasterId” id=”hdnMasterId” value=”test” />
    <input type=”hidden” name=”hdnFileDesc” id=”hdnFileDesc” value=”test” />
    <div id=”files” data-dojo-type=”dojox/form/uploader/FileList” data-dojo-props=”uploaderId: ‘uploader’”></div>

     

    เมื่อสังเกตุแล้วจะเห็นได้ว่าจะไม่มีปุ่ม Submit เนื่องจากผู้เขียนต้องการ upload file แบบ AJAX จึงไม่ต้องการให้ผู้ใช้กด ENTER แล้วส่งฟอร์มทั้งหมดไปทันที อีกจุดหนึ่งคือผู้เขียนต้องการส่งข้อมูลบางอย่างไปในคราวเดียวกันด้วยคือ  hdnMasterId และ hdnFileDesc

     

    ลอง Run ดูน่าจะได้น่าตาประมาณนี้

    ex1

    เมื่อเราลองเลือก file แล้ว ชื่อ file ที่เราเลือกจะแสดงอยู่ตำแหน่งด้านล่าง

    ex2

    2. กำหนดการทำงานในฝั่ง client

    ในขั้นตอนนี้เราจะต้องเขียน JavaScript เพื่อควบคุมการทำงานของ widget โดยผู้เขียนจะกำหนดให้ทำการ upload file แบบ AJAX เมื่อกดปุ่มใดปุ่มหนึ่งดังนี้

    fileUploader..set(“onComplete”, function(){

    //อะไรก็ตามที่ต้องให้ทำเมื่อทำการ upload เสร็จแล้ว

    });

    fileUploader.submit();

     

    3. กำหนดการทำงานในฝั่ง server

    ในส่วนของฝั่ง server เราก็ต้องมีการกำหนดการทำงานเช่นกัน เช่น การจัดเก็บไฟล์ การดึงข้อมูลจากการส่งข้อมูลแบบ AJAX เนื่องจากเรามีการส่งข้อมูลอื่น ๆ ไปด้วย ทั้งนี้เราไม่จะเป็นจะต้องใช้ web form มารองรับในการ upload เราสามารถใช้ ashx มาทำงานแทนที่ได้เลย การเขียนโปรแกรมฝั่ง server เป็นดังตัวอย่างด้านล่าง

    public void ProcessRequest(HttpContext context)
    {
    context.Response.ContentType = “text/plain”;
    JavaScriptSerializer js = new JavaScriptSerializer();
    string result = String.Empty;

    IDictionary<string, string> postData = new Dictionary<string, string>();

    foreach (string name in context.Request.Form.Keys)
    {
    //context.Response.Write(“<br>KEYS: ” + name);
    postData[name] = context.Request.Form[name];
    }

    //result = js.Serialize(new Response(false, postData[“hdnTest”], String.Empty));
    //context.Response.Write(result);

    string masterId = postData[“hdnMasterId”];
    string description = postData[“hdnFileDesc”];

    try
    {
    int len = context.Request.Files.Count;

    for (int i = 0; i < len; i++)
    {
    HttpPostedFile postedFile = context.Request.Files.Get(i) as HttpPostedFile;

    string[] fileNames = postedFile.FileName.Split(‘\\’);
    string fileName = String.Empty;

    if (fileNames.Length > 1)
    {
    fileName = fileNames[fileNames.Length – 1];
    }
    else
    {
    fileName = fileNames[0];
    }

    string[] fileType = postedFile.FileName.Split(‘.’);

    string uploadPath = context.Server.MapPath(Settings.Default.UploadFilePath);
    string newFileName = “[” + masterId + “]_” + fileName;
    string saveFileName = uploadPath + @”\” + newFileName;
    postedFile.SaveAs(saveFileName);

    OutboundMaster app = OutboundMaster.GetById(masterId);
    app.AddAttachedFile(newFileName, description);

    result = js.Serialize(new BizResponse(true));
    }

    context.Response.Write(result);
    }
    catch (Exception ex)
    {
    result = js.Serialize(new BizResponse(false, ex.Message, ex.StackTrace));
    context.Response.Write(result);
    }
    }

    จะเห็นได้ว่าตัวแปรที่มาจากการ post จะอยู่ในรูปแบบของ array ดังนั้นเราจะต้องทำการหาตัวแปรด้วย key ก่อน จากนั้นก็จะเข้าสู่ขั้นตอนการบันทึกไฟล์ตามที่เราออกแบบ

    ทั้งนี้ตัว Uploader มีข้อกำหนดข้อหนึ่งคือจะต้องมีการตอบสนองจากฝั่ง server หากไม่มีจะทำให้ Uploader แสดง error ถึงแม้ว่าการ upload file นั้นเสร็จสิ้นไปแล้วก็ตาม ดังนั้นที่ไฟล์ ashx จึงต้องมีการส่งข้อมูลกลับมาดังตัวอย่างด้านล่างนี้

    context.Response.Write(……);

     

    บทสรุป

    การใช้งาน Uploader อาจจะซับซ้อนมากน้อยขึ้นอยู่กับคนที่นำไปใช้ และถึงแม้ว่าเครื่องมือตัวนี้จะไม่ค่อย compatibility กับ Visual Studio เนื่องจากแนวคิดในการทำงานนั้นแตกต่างกัน แต่ยังคงสามารถนำมาประยุกต์ใช้งานเพื่อให้ได้ผลลัพธ์ตามที่ต้องการได้ และเนื่องจาก Dojo Toolkit นั้นเปิดเผย source code ทำให้เราสามารถทำความเข้าใจและจุดประกายแนวคิดใหม่ ๆ ได้อีกด้วย

  • สร้างกราฟด้วย Chart.js ร่วมกับ ASP.NET

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

        สำหรับ Chart.js นั้นเป็นเฟรมเวิร์คที่สร้างด้วยภาษา JavaScript ดังนั้นคุณสมบัติที่พ่วงมาด้วยคือการทำงานแบบ AJAX อย่างเต็มรูปแบบ ซึ่งในบทความนี้จะเป็นการนำเอามาใช้ร่วมกับเว็บแอพลิเคชัน ที่พัฒนาด้วย ASP.NET โดยวิธีการส่งข้อมูลในรูปแบบ JSON ผ่าน Web Services และทำการแปลงข้อมูล JSON ให้อยู่ในรูปแบบของ Object ที่มีโครงสร้างตรงตามที่ Chart.js ต้องการ เพื่อนำไปใช้แสดงผลในรูปแบบกราฟแท่ง กราฟเส้น กราฟวงกลม  ผ่าน HTML Tag ที่มีชื่อว่า Canvas ซึ่งมีการเพิ่มส่วนแสดงความหมายของสีต่างๆในกราฟ ที่ได้พัฒนาเพิ่มเติมขึ้นมาอีกด้วย

        ในบทความนี้จะยกตัวอย่างการสร้างกราฟใน 3 รูปแบบ และมีการกำหนดค่า Option ในการแสดงผลเท่าที่จำเป็นเท่านั้น สามารถอ่านวิธีการใช้งานเต็มรูปแบบได้ที่ http://www.chartjs.org/docs

    1. ทำการ Include ไฟล์ Javascript ของ chart.js ไว้ใน header (ในตัวอย่างเป็นการเรียกใช้งานจาก CDN หากต้องการใช้งานจากไฟล์ที่เก็บไว้ที่เว็บเซิฟเวอร์ให้ปรับแก้ src path)
    <script src="https://code.jquery.com/jquery-1.11.3.min.js" type="text/javascript"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js" type="text/javascript"></script>
    1. เพิ่ม canvas ในส่วนของ body
     <canvas id="report" width="600" height="300"></canvas>
    1. เขียน JavaScript เพื่อสร้างข้อมูล ตามโครงสร้างของกราฟแต่ละประเภท ในตัวอย่างจะเป็นโครงสร้างข้อมูลของกราฟแท่ง
     var dataDemo = { labels: ["Apple", "Sumsung", "ASUS", "OPPO"],
     datasets: [{
     label: "2557",
     fillColor: "#5B90BF",
     data: [20, 10, 9, 8]
     }]
     };
    1. ทำการสร้าง Context จาก canvas เพื่อนำไปสร้าง Chart Object โดยใช้คำสั่ง ดังนี้
     var ctx = $("#report").get(0).getContext("2d");
     var chart = new Chart(ctx).Bar(dataDemo, { bezierCurve: false });

     

    จาก 4 ขั้นตอนดังกล่าวเราจะได้โค้ดที่เมื่อทำการเพิ่มโครงสร้างของหน้าเว็บ และบันทึกเป็นไฟล์ html แบบนี้ chart.html  ลองเปิดดูจะพบว่าสามารถแสดงกราฟแท่งได้แล้ว

     

        แต่ในงานจริงนั้น รู้กันดีนะครับ ว่ามันไม่ง่ายอย่างนั้น โจทย์ของเราคือ สามารถนำข้อมูลจาก Database ซึ่งได้เขียน Query จนได้ข้อมูลแบบที่เราเรียกกันติดปากว่า Crosstab นั้นคือมีชื่อฟิลด์ข้อมูลที่มีความสัมพันธ์กันในแกน x และแกน y ซึ่งเป็นรูปแบบข้อมูลที่นำมาสร้างเป็นกราฟนั้นเอง ส่วนวิธีการนั้น ผมไม่ขอลงรายละเอียดในบทความนี้ แต่สำหรับท่านใดที่ใช้งานฐานข้อมูล Oracle ตั้งแต่ 11g ขึ้นไปลองศึกษาคำสั่งชื่อ Pivot ดูครับ น่าจะช่วยลดความยุ่งยากในขั้นตอนนี้ได้มาก ตัวอย่างข้อมูล แบบ Crosstab ที่เราจะส่งจากฝั่ง Server มาสร้างเป็น Object สำหรับสร้างกราฟอีกทีครับ

     

    crosstab-datatable

     

        อีกจุดที่มีความยุ่งยาก คือการแปลงจากรูปแบบข้อมูล Crosstab Datatable เป็น JSON ตัวช่วยของผมในเรื่องนี้คือ Library ที่ชื่อ Newtonsoft.Json สามารถดาวส์โหลดมาใช้งานผ่าน NuGet ได้เลยครับ จากนั้นก็เรียกใช้งาน ดังตัวอย่าง โดยตัวแปล data คือ Datatable ของเรา เมื่อได้ข้อมูล JSON แล้วให้ทำการสร้าง Web Service เพื่อให้สามารถดึงข้อมูลดังกล่าวจาก Javascript ได้

    JsonConvert.SerializeObject(data)

    ถัดจากนั้น ก็คือการนำ JSON นั้นไปสร้างเป็น Object ที่มีโครงสร้างตามที่ Chart.js ต้องการอีกที ในขั้นตอนนี้ผมลองหา Library ดูแล้วแต่ไม่เจอ ก็ได้พัฒนาเป็นชุดคำสั่ง helper เล็กๆ ซึ่งค่อนข้างจะจำเพาะกับลักษณะข้อมูล และรูปแบบการแสดงผลของเว็บไซด์ที่ผมพัฒนาอยู่ แต่สามารถนำไปปรับแก้ให้เหมาะสมได้ครับ ซึ่งในไฟล์นี้ หากใส่ parameter และเขียนโครงสร้าง html ตามตัวอย่าง เราจะเหลือโค้ดที่จะต้องเขียนเพียงไม่กี่บรรทัด ก็จะได้กราฟมาใช้งานใน 3 รูปแบบ คือ กราฟแท่ง กราฟเส้น และกราฟวงกลม ตามที่มี method ให้ครับ

     

    สำหรับการสร้างกราฟจะมีขั้นตอนเปลี่ยนไปดังนี้ครับ

    1. ทำการ include ไฟล์ Javascript โดยเพิ่มเติม chart-helper.js
    <script src="https://code.jquery.com/jquery-1.11.3.min.js" type="text/javascript"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js" type="text/javascript"></script>
    <script src="chart-helper.js" type="text/javascript"></script>
    1. ทำการ include ไฟล์ Style Sheet ดังนี้ bootstrap-grid.css และไฟล์ chart.css
    <link href="bootstrap-grid.css" rel="stylesheet" type="text/css" />
    <link href="chart.css" rel="stylesheet" type="text/css" />
    1. สร้าง HTML ตามโครงสร้าง โดยมีการใช้งาน class ในส่วน grid system ของ Bootstrap มาช่วยวางตำแหน่งซ้ายขวา ดังนี้
    <div class="row">
     <div class="col-xs-8">
     <canvas id="reportBar" width="600" height="300">
     </canvas>
     </div>
     <div class="col-xs-4">
     <ul id="chartLabelBar" class="chart-label-list">
     </ul>
     </div>
     </div>
     <div class="row">
     <div class="col-xs-8">
     <canvas id="reportLine" width="600" height="300">
     </canvas>
     </div>
     <div class="col-xs-4">
     <ul id="chartLabelLine" class="chart-label-list">
     </ul>
     </div>
     </div>
     <div class="row">
     <div class="col-xs-8">
     <canvas id="reportPie" width="600" height="300">
     </canvas>
     </div>
     <div class="col-xs-4">
     <ul id="chartLabelPie" class="chart-label-list">
     </ul>
     </div>
     </div>
    1. จากนั้นทำการเรียกใช้งาน Method ของ chart-helper.js ซึ่งประกอบไปด้วย CreateBarChart (สร้างกราฟแท่ง), CreateLineChart (สร้างกราฟเส้น), CreatePieChart (สร้างกราฟวงกลม) จะรับค่าเป็นข้อมูล JSON และ ID ของ HTML เพื่อนำไปสร้างกราฟโดยตัวอย่างการใช้งาน Method เหล่านี้ร่วมกับ Webservice (ทั้งนี้รูปแบบการเรียก Webservice ขึ้นอยู่กับวิธีการ Response ด้วย) มีดังนี้
    $.ajax({
     type: "POST",
     url: "DemoService.asmx/MethodName",
     data: { param:data1 }
     }).done(function (json) {
     CreateBarChart(json, "reportBar", "chartLabelBar");
     CreateLineChart(json, "reportLine", "chartLabelLine");
     CreatePieChart(json, "reportPie", "chartLabelPie");
     }).fail(function (jqXHR, textStatus) {
     alert(textStatus);
     });

    สามารถดาวโหลดไฟล์ตัวอย่างแบบเต็มได้ตามนี้ครับ chart-with-helper.html และกราฟที่ได้จะมีหน้าตาแบบนี้ ทั้งนี้ขึ้นอยู่กับข้อมูลของเราด้วยครับ

    bar line pie

     

  • ใช้ google script ทำ mail merge เนื้อหาเมลที่มี pre-filled form URL

    จากตอนที่แล้ว “ใช้ google script ทำ mail merge เนื้อหาเมลที่มี link” เรารู้วิธีใส่ link ไปในเนื้อหาเมล ในตอนนี้เราจะมาเปลี่ยน static link เป็น dynamic link (คือ link ที่มีการอ้างชื่อ cell จึงเป็น link ที่เปลี่ยนแปลงไปตามค่าที่อยู่ใน cell) จุดประสงค์ก็เพื่อส่ง link ให้ผู้ที่รับอีเมลกรอกข้อมูลลง google form ที่มีข้อมูลให้บางส่วนแล้ว (pre-filled form) ซึ่งเป็นข้อมูลของผู้รับอีเมลแต่ละคนที่แตกต่างกัน เช่น ให้มีฟิลด์ ชื่อ และ หน่วยงาน ไว้แล้ว เป็นต้น เมื่อเปิดฟอร์มจึงไม่ต้องกรอกชื่อ และ หน่วยงาน แต่ยังสามารถแก้ไขได้หากต้องการ แล้วให้กรอกข้อมูลเพิ่มในส่วนอื่น ๆ

    สมมติ
    1. เรามี google sheet ชื่อ members มี 4 คอลัมน์ อยู่แล้ว ดังนี้ รายการที่, ชื่อ, หน่วยงาน, อีเมล

    mmwp01

    2. เราต้องการสร้าง google form เพื่อสอบถาม ตอบรับร่วมงาน และ ประเภทอาหาร

    วิธีทำ ดังนี้
    1. สร้าง google form ขึ้นมา 1 อัน ตั้งชื่อว่า member-meeting1

    mmwp02

    2. สร้าง form field ดังนี้ ชื่อ, หน่วยงาน, ตอบรับร่วมงาน, ประเภทอาหาร

    3. เลือกเมนู Responses > เลือก Get pre-filled URL

    mmwp03

    4. กรอกข้อมูลชื่อตัวแปรลงในช่องข้อมูล เช่น ชื่อ ให้ใส่ f1, หน่วยงาน ให้ใส่ f2

    mmwp04

    5. กรอกเสร็จให้คลิก submit จะได้หน้าต่างแสดงเป็น URL และมีข้อความบอกให้เราคัดลอก (ctrl+c)

    mmwp05

    6. URL ที่คัดลอกนี้จะไปใส่ใน google sheet ชื่อ member ในคอลัมน์ใหม่ รวมเป็น 5 คอลัมน์ ดังนี้
    รายการที่, ชื่อ, หน่วยงาน, อีเมล, URL

    7. ที่ cell URL นี้ ให้ใส่ฟังก์ชั่น =HYPERLINK(“URL”,”URL”) และนำ URL ที่คัดลอกมาวางตรงคำว่า URL

    mmwp06

    8. ให้แทนที่ข้อความ ตรงที่มีคำว่า f1 ด้วย “&B2&”, แทนที่ f2 ด้วย “&C2&”

    mmwp07

    9. จากนั้นก็นำความรู้ในเรื่อง “ใช้ google script ทำ mail merge เนื้อหาเมลที่มี link” มาใช้ในการส่งอีเมลได้แล้ว
    9.1 เตรียมเนื้อหาจดหมายไว้ใน sheet ชื่อ Template
    mmwp08

    9.2 เตรียม range ของข้อมูล คีย์เองนะ

    mmwp09

    9.3 คัดลอก google script จากตอนที่แล้วมาใช้

    mmwp10

    9.4 สั่งให้ google script ชื่อ MailMergeWithLinkv2 ทำการส่งอีเมล

    mmwp11

    9.5 ตรวจสอบดูอีเมลที่ได้รับ

    mmwp12

    9.6 เมื่อคลิก link จากในเมล จะไปเปิด google form ขึ้นมา พร้อมข้อมูล 2 ฟิลด์แรก คือ ชื่อ และ หน่วยงาน ที่ดึงข้อมูลที่มีอยู่มาไว้ให้เลย จะได้ไม่ต้องคีย์บ่อย ๆ

    mmwp13

    9.7 ตรวจสอบข้อมูลที่กรอกผ่าน google form โดยที่เมนู Responses ใน form ให้เลือก Choose response destination และเลือก สร้างไฟล์ google spreadsheet ใหม่

    mmwp14

    จากนั้น จะได้ไฟล์

    mmwp15

    เปิดดู เห็นข้อมูลที่กรอกผ่าน google form มาเก็บไว้แล้ว

    mmwp16

     

    ความรู้นำมาจากเรื่องนี้:
    Pre-populate form answers
    https://support.google.com/docs/answer/160000?hl=en

  • ใช้ google script ทำ mail merge เนื้อหาเมลที่มี link

    ผมใช้ Yet another mail merge ซึ่งเป็น add-on เพื่อส่งอีเมลเรื่องเดียวกันไปยังเพื่อนๆจำนวนหนึ่ง ก็ใช้งานได้ดีมา 5 ครั้งแล้ว แต่พอครั้งหลังนี้ ผมต้องการส่งอีเมลที่ในเนื้อหามี link ให้ผู้ที่รับอีเมลสามารถคลิกเพื่อเปิดอ่านได้ แต่ลองหลายวิธีที่จะส่งด้วยวิธีที่เคยใช้ add-on ตัวนี้ก็จะแสดงเป็นข้อความ ไม่แสดงเป็น link ในอีเมล (อันนี้ต้องบอกก่อนว่า คาดว่าผู้ใช้ส่วนใหญ่ใช้โปรแกรมอีเมลที่มีการแสดงผลมากกว่าข้อความธรรมดา)

    ค้นหาดูก็พบว่า ต้องเปลี่ยนวิธีทำมาเป็นวิธีเขียน google script เพื่อส่ง mail merge แทน

    วิธีทำ ดังนี้
    1. สร้าง google sheet ตั้งชื่อ myusers
    1.1 sheet แรก ตั้งชื่อ Data ที่มีคอลัมน์ ดังนี้
    รายการที่, ชื่อ, คณะ, อีเมล, link1, link2

    mmwl01

    1.2 sheet สอง ตั้งชื่อ Template ที่มี 1 คอลัมน์ เพื่อเขียน subject และ ข้อความจดหมายที่มี link

    mmwl02

    1.3 sheet สาม ตั้งชื่อ Range ที่มี 3 คอลัมน์ ดังนี้
    header, data, template

    mmwl03

    2. ใส่ข้อมูลตามตัวอย่างรูปภาพ

    3. ที่ google sheet ให้คลิกที่ Tool > Script editor > เลือก Blank Project > ตั้งชื่อว่า myusers project

    mmwl04

    mmwl05

    4. แปะ google script ตามซอร์สโค้ดด้านล่างบทความนี้ และคลิก Save
    หมายเหตุ ซอร์สโค้ดนี้จะวางตำแหน่งอีเมลไว้ที่คอลัมน์ที่ 4

    mmwl06

    5. ปิดแท็บ google script (myusers project)

    6. ปิดแท็บ google sheet (myusers) แล้วเปิดใหม่

    7. เมื่อเปิดใหม่จะเห็นว่ามีเมนู Email และมี submenu ชื่อ MailMergeWithLinkv2

    mmwl07

    8. คลิกเมนู Email > MailMergeWithLinkv2
    จะมีการขอสิทธิในการรัน script ดังรูป

    mmwl08   mmwl09

    9. ไปตรวจสอบว่าอีเมลถูกส่งไปและมีเนื้อหาที่มี link ตามต้องการ

    mmwl10

    10. หากต้องการส่งอีกครั้งให้กับอีเมลที่ได้ส่งแล้ว ให้ดูที่คอลัมน์ อีเมล จะเห็นว่ามี Note เนื่องจากว่า google script นี้ได้เขียน Note ไว้ใน cell ใช้เป็นการป้องกันการส่งอีเมลซ้ำ

    mmwl11

    ให้คลิกขวาและเลือก Clear Note

    mmwl12

    ซอร์สโค้ดที่ใช้:

    function onOpen() {
      var submenu = [{name:"MailMergeWithLinkv2", functionName:"MailMergeWithLinkv2"}];
      SpreadsheetApp.getActiveSpreadsheet().addMenu('Email', submenu);  
    }
    
    function MailMergeWithLinkv2() {
      var ss = SpreadsheetApp.getActiveSpreadsheet(),
      DataSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Data")),
      TemplateSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Template")),
      RangeSheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Range")),
    
      header = RangeSheet.getRange(2, 1).getValue(),
      data = RangeSheet.getRange(2, 2).getValue(),
      template = RangeSheet.getRange(2, 3).getValue(),
    
      dataRows = DataSheet.getRange(data).getValues(),
      headerRow = DataSheet.getRange(header).getValues(),
      numColumns = DataSheet.getRange(header).getNumColumns(),
      templateRows= TemplateSheet.getRange(template).getValues();
    
      for (var i=0 ; i < dataRows.length ; i++) {
        var mailmessage = "";
        for (var k=0 ; k < templateRows.length ; k++) {
          if ( k == 0 ) {
            var subject = templateRows[0][0];
          } else {
            mailmessage += templateRows[k][0] + "<br>\n"; 
          }
        }
        for (var j=0 ; j < numColumns ; j++) { 
          mailmessage = mailmessage.replace('{' + headerRow[0][j] + '}', dataRows[i][j]); 
        }
        //Test output with logger. Uncomment the line below.
        //Logger.log(mailmessage);
        //
        //Send Email start here, starting row is 2.
        var sender = "Sawadee Krub";   //email sender name
        var emailaddress = DataSheet.getRange(2+i, 4).getValue(); //email in column 4
        var options = {}
        options.htmlBody = mailmessage;
        options.name = sender;
        //Not send email again if it was sent. Clear note then can send email again.
        if (DataSheet.getRange(2+i, 4).getNote()) {
        } else {
          MailApp.sendEmail(emailaddress, subject, '', options);
          DataSheet.getRange(2+i, 4).setNote("Email sent on " + new Date); 
        }
        //Email sent
      } 
    }

     

    ความรู้นำมาจากเรื่องนี้:
    1) Embedding a link in Mail Merge
    https://productforums.google.com/forum/#!topic/docs/WvW-lAr3pg8
    และ
    2) Google Apps Scripts Workshop – Level 1
    http://sysadmin.psu.ac.th/2015/05/06/gasws-1/

    ในตอนต่อไป จะนำเสนอวิธีสร้าง link ที่เป็น pre-filled form URL ของ google form

  • วิธีใช้ Google Sheets สร้าง Account ใหม่ลงใน Sub Organization ของ GAFE

    [บทความนี้ สำหรับผู้ที่มี GAFE Admin Privilege ขึ้นไป]

    ในการสร้างบัญชีผู้ใช้ใหม่บน GAFE นั้นทำได้หลายวิธี ได้แก่

    1. การสร้างทีละคนผ่าน Admin Console
    2. การสร้างทีละหลายๆคนด้วย CSV File
    3. การสร้างทีละหลายๆคนผ่าน Google Apps Directory Sync

    เมื่อต้องการสร้างผู้ใช้จำนวนมาก เช่น 5,500 คน โดยต้องจัดแบ่งผู้ใช้ แยกลงไปในแต่ละ Sub Organization วิธีที่ 1. ทำได้แต่เป็นงานที่หนักมาก วิธีที่ 2. ทำไม่ได้ เพราะการใช้ CSV File ผ่าน Admin Console นั้นจะสร้างผู้ใช้รวมกันที่ Root Organization ไม่สามารถแยกลงไปใน Sub Organization ได้ ส่วนวิธีที่ 3. นั้นทำได้ แต่ต้องเข้าใจกระบวนการทำงานของ LDAP พอสมควร

    ในบทความนี้ จะนำเสนอวิธีการที่ ทำได้ง่ายเหมือนการใช้ CSV แต่สามารถแยกลงไปใน Sub Organization ได้ ด้วย Google Sheets และ Google Apps Script ดังต่อไปนี้ (ขอยกตัวอย่างเพียง 5 Account เพื่อความสะดวก)

    1. สร้าง Google Sheets แล้วใส่ข้อมูล email, firstname, lastname, OU, password, status
    2. สร้าง Google Apps Scripts ใน Google Sheets นี้ ด้วยเมนู Tools > Script Editor … จากนั้นเลือก Blank Project แล้วกดปุ่ม Close
    3. ตั้งชื่อโปรเจค AddMultiAccountToSubOU แล้วใส่โค๊ดดังนี้
    4. ถ้าลอง Run เลย จะเจอ Error อย่างนี้
      คลิก Continue -> Accept -> Dismiss
      เพราะยังงไม่ได้ Enable API ไว้
    5. เนื่องจากการสร้าง Account ต้องใช้สิทธิ์ของ Admin ขึ้นไป และต้องใช้ Admin SDK Directory API ด้วย วิธีการคือใช้เมนู Resources -> Advanced Google Services แล้วเลือก Admin Directory API เป็น On
    6. จากนั้นคลิกที่ Google Developers Consol
      ที่ Admin SDK ให้เปลี่ยน ON
    7. เมื่อ Run ใหม่ ก็จะได้ผลใน Google Sheets ตามภาพ
    8. และจะสามารถสร้างผู้ใช้ได้ตาม Sub Organization ที่ต้องการ

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

  • วิธีการใช้ Google Sheets เป็นระบบเฝ้าระวังเว็บไซต์ (Website Monitoring) จากภายนอกองค์กร

    จาก “วิธีการใช้ Google Sheets เป็นฐานข้อมูล” ซึ่งได้กล่าวถึงพื้นฐานการพัฒนา Google Apps Script เพื่อใช้ต่อยอดความสามารถของ Google Sheets สามารถนำมาประยุกต์ใช้เพื่อเฝ้าระวังบริการเว็บไซต์จากภายนอกระบบเครือข่ายขององค์กรได้ (จาก Google Cloud Infrastructure เลยทีเดียว)

    ขั้นตอนในการทำ

    1. ในโปรเจค ProjectMyDB สร้างไฟล์ monitoring.gs ดังภาพ
    2. ประกอบด้วย 3 ฟังก์ชัน คือ
      function check_website(url) {  
        var response = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
        return response.getResponseCode();
      }
      
      function doLog(timestamp, responseCode, timeDiff) {
        var ss = SpreadsheetApp.openByUrl('https://docs.google.com/a/psu.ac.th/spreadsheets/d/1HJmyqiBYC_AEATmdUWakLgHFyYGqSqeqSA8xEw-8o-c/edit');
        SpreadsheetApp.setActiveSpreadsheet(ss);
        SpreadsheetApp.setActiveSheet(ss.getSheetByName("Log"));
        var activeSheet=ss.getActiveSheet();
        activeSheet.appendRow([timestamp, responseCode, timeDiff]);
      }
      
      function getTime() {
        var startTime = new Date() ;
        var responseCode=check_website("http://www.psu.ac.th");
        var endTime = new Date() ;
        var timeDiff = endTime-startTime;  
        doLog(Utilities.formatDate(new Date(), "GMT+7", "yyyyMMdd-HHmmss") , responseCode , timeDiff);
      }
    • check_website ใช้ UrlFetchApp เพื่อ url ของเว็บไซต์ แล้วรีเทิร์นผล Response Code ของ HTTP Protocol กลับไป
    • doLog ใช้สำหรับเพิ่มค่า timestamp, responseCode และ timeDiff (เวลาในการตอบสนอง) ลงใน Sheet “Log” ใน Google Sheets ที่กำหนดไว้
    • getTime ใช้คำนวนเวลาตั้งแต่เริ่มต้น แล้วเรียกใช้ฟังก์ชั่น check_website และ จับเวลาที่สิ้นสุด จากนั้นคำนวนเป็นเวลาในการตอบสนอง (timeDiff) แล้ว เรียกฟังก์ขัน doLog เพื่อเขียนข้อมูลต่อไป
    1. สร้าง Trigger ด้วยเมนู Resources > Current project’s triggers
    2. เลือกฟังก์ชัน getTime กำหนดเป็น Time-driven ทำงานในหน่วยนาที (Minute timmer) และ ทำงานทุกๆ 5 นาที แล้วกดปุ่ม Save
    3. ผลการทำงาน และการสร้าง Chart ประกอบทำให้สามารถเห็นแนวโน้มได้

    จากตัวอย่างข้างต้น ทำให้เห็นว่า การใช้ Google Apps Script ร่วมกับ Google Sheet สามารถสร้างระบบเฝ้าระวังเว็บไซต์จากภายนอกองค์กรได้อย่างง่ายๆ และไม่มีค่าใช้จ่าย ทำให้เห็นภาพการใช้งานจากภายนอกได้เป็นอย่างดี