Project

General

Profile

การสร้าง Aimagin Connect components

Aimagin Connect test site: http://bd.aimagin.com:10080/

ขอให้ติดต่อ เพื่อขอรับ username และ password เพื่อทดสอบระบบ ของคุณเอง

หรือใช้ Organization ID: demo, Username: demo, Password: demo ก็ได้ แต่ ไม่แนะนำ เนื่องจาก username และ password นี้ อาจถูก log out เอง หากมี user คนอื่น log in เข้ามาด้วย Username เดียวกัน

Aimagin Connect คือ Framework ของบริษัท เอมเมจิน สำหรับสร้าง Web application แบบ ลากวาง

Component หรือ Widget คือ Javascript code ที่เขียนเพื่อให้เป็น object ที่ผู้ใช้สามารถสร้าง Web application ได้โดยไม่ต้องเขียน code

Component จะมีความซับซ้อน ได้มาก เช่น ผูกกับ database ได้ ผูกกับสิทธิการเข้าถึงข้อมูลได้ ฯลฯ

การสร้าง Component

ในไฟล์ package.js จะประกอบไปด้วยตัวแปรหลัก 2 ตัวแปร คือ
1. ID [string] ใช้นิยาม ID ของ package
2. PACKAGE [object] Component ต่างๆ จะถูกนิยามไว้ในตัวแปรนี้

ในตัวแปร PACKAGE จะมีชนิดของ Component 3 ประเภท ดังนี้
1. Package folder คือ folder หลักที่ใช้เก็บ component folder และ component object อื่นๆ ของ package นี้ ซึ่งชื่อ field ใน PACKAGE จะเป็น ID
2. Component folder คือ folder ที่ใช้เก็บ Component object หรือ Component folder อื่นๆ
3. Component object คือ Component หลักที่จะใช้เป็นองค์ประกอบในการสร้าง web app

1. Package folder
เป็น object ประกอบด้วย field ต่างๆ ดังนี้
1.1. name [string] คือ ชื่อของ Package folder
1.2. text [string] เป็น help text ที่จะขึ้นเมื่อ hover ที่ Package folder
1.3. children [array of string] ประกอบไปด้วย ชื่อของ component folder/object ย่อย
1.4. object [object] ทำหน้าที่ใช้นิยาม global function ของ package นี้ โดย component ต่างๆ สามารถเห็นและเรียกใช้ได้
ตัวอย่าง

{
"name":"Package folder", text:"Package folder", chilren:["folder-1", "folder-2", "component-1"],
"object":{
  "function-1":function(e) {
  /*
   ใน e จะมี
    e.id = id ของ element
  */
  }
  "function-2":function(e) {
    return "value";
  }
}
}

2. Component folder
เป็น object ประกอบด้วย field ต่างๆ ดังนี้
2.1. name [string] คือ ชื่อของ folder
2.2. text [string] เป็น help text ที่จะขึ้นเมื่อ hover ที่ Component
2.3. children [array of string] ประกอบไปด้วย ชื่อของ component folder/object ย่อย
ตัวอย่าง

{
"name":"Folder", text:"Folder", chilren:["folder-1.1", "folder-1.2", "component-1"]
}

3. Component object
เป็น object ประกอบด้วย field ต่างๆ ดังนี้
3.1. name [string] คือ ชื่อของ Component object
3.2. text [string] เป็น help text ที่จะขึ้นเมื่อ hover ที่ Component
3.3. children [boolean] ใช้บอกว่า component นี้สามารถมีลูกเป็น component อื่นได้หรือไม่ โดย
true = มีลูกได้, false = มีลูกไม่ได้
3.4. parameter [array of object] ประกอบไปด้วย parameter ของ component เพื่อให้ผู้ใช้ตั้งค่าได้
มีสมาชิก 2 แบบ คือ
3.4.1. group [object] ลักษณะเหมือนกับ folder ใช้เก็บ group/parameter ย่อยอื่นๆ
โดยจะประกอบไปด้วย
3.4.1.1. name [string] ชื่อของ group
3.4.1.2. text [string] แสดงเมื่อมีการ hover ที่ group
3.4.1.3. children [array of object] ที่ใช้เก็บ group/parameter ย่อยอื่นๆ
3.4.2. parameter [object] เป็น parameter ที่ให้ผู้ใช้ตั้งค่าได้
โดยมี field ต่างๆ ดังนี้
3.4.2.1. name [string] ชื่อของ parameter
3.4.2.2. text [string] แสดงเมื่อมีการ hover ที่ parameter
3.4.2.3. input [object] ใช้บอกชนิด input ของ parameter นี้ จะประกอบไปด้วย field
3.4.2.3.1 value [string/array/object] เป็น value เริ่มต้นของ parameter
3.4.2.3.2 type [object] บอกชนิดของ input
3.4.2.3.2.1 type: “0”
เป็น input แบบ text field ธรรมดา
3.4.2.3.2.2 type: “1”
เป็น input แบบ drop down ใช้คู่กับ option ใน 3.4.2.3.3 โดย value ใน 3.4.2.3.1 จะเป็น string ของ value ใน 3.4.2.3.3
3.4.2.3.2.3 type: “2”
เป็น input แบบ checkbox โดยเป็น drop down ใช้คู่กับ option ใน 3.4.2.3.3 โดย value ใน 3.4.2.3.1 จะเป็น array ของ value ใน 3.4.2.3.3
3.4.2.3.2.4 type: “3”
เป็น input แบบ Color palette เลือกสี โดย value ที่ได้จากอยู่ในรูปแบบ rgab(r,g,b,a) และ value สามารถใส่เป็น rgb, rgba, hex ได้
3.4.2.3.2.4 type: “4”
เป็น input แบบ Checkbox เป็นสถานะ true หรือ false คือ checked กับ unchecked
3.4.2.3.2.5 type: “custom”
เป็น input แบบ custom โดยให้ผู้สร้างออกแบบ input เอง โดยเมื่อผู้ใช้กดปุ่ม edit ที่ property จะมี pop up ขึ้นมาบนหน้าจอ พร้อมปุ่ม save และ cancel โดยเมื่อ pop up ปรากฎขึ้น ฟังก์ชั่น open ในข้อ 3.4.2.3.4 จะถูกเรียกเพื่อให้ผู้สร้างได้ออกแบบ input และเมื่อผู้ใช้กดปุ่ม save ฟังก์ชั่น save ในข้อ 3.4.2.3.5 จะถูกเรียกเพื่อให้ผู้สร้างได้ประมวลผล และ return value ใน 3.4.2.3.3 ซึ่ง value จะเป็น object
3.4.2.3.3 option [array of object] เป็น array บอกตัวเลือกของ input กรณี type = “1” หรือ “2” โดย option จะประกอบไปด้วย field
3.4.2.3.3.1 text [string] เป็นชื่อของ option
3.4.2.3.3.2 value [string] เป็นค่าของ option เมื่อถูกเลือก จะถูกส่งเข้าไปใน setParameter ในข้อ 3.4.2.4 เมื่อสร้าง component
3.4.2.3.4 open [function/string] ฟังก์ชั่นนี้จะถูกเรียกเมื่อผู้ใช้เปิดหน้าต่างขึ้นมา กรณี type = "custom"

"open":function(e) {
  /*
    ใน e จะประกอบไปด้วย
    e.container เป็น container หลัก สำหรับให้ผู้สร้างได้สร้าง input
    e.value เป็น value ของ parameter นี้
    e.object = object ของ package folder เป็น function เพื่อไว้ใช้งาน

  */
}

หรือ ฟังก์ชั่นนี้สามารถอ้างอิงเป็น string ได้ โดยใช้ชื่อ field ที่นิยามไว้ใน object ข้อ 1.4

{
  "save": "function-2" 
}
3.4.2.3.5 save [function/string] ฟังก์ชั่นนี้จะถูกเรียกใช้เมื่อผู้ใช้กดปุ่ม save กรณี type = "custom"
"save":function(e) {
  /*
    ใน e จะประกอบไปด้วย
    e.container เป็น container หลัก ที่ได้สร้าง input ไว้
    e.value เป็น value ของ parameter นี้ ที่มีการตั้งค่าไว้ล่าสุด
    e.default เป็น default value ของ parameter นี้
    e.object = object ของ package folder เป็น function เพื่อไว้ใช้งาน

  */
  return {};
}

หรือ ฟังก์ชั่นนี้สามารถอ้างอิงเป็น string ได้ โดยใช้ชื่อ field ที่นิยามไว้ใน object ข้อ 1.4
{
  "open": "function-2" 
}
3.4.2.4. setParameter [function/string] ฟังก์ชั่นนี้จะถูกเรียกใช้เมื่อมีการตั้งค่า parameter โดยจะถูกเรียกเมื่อมีการสร้าง web page และเมื่อมีการเปลี่ยนแปลงจาก callback
"setParameter":function(e) {
  /*
   ใน e จะมี
    e.id = id ของ element
    e.key = ชื่อของ parameter
    e.value = เป็น value ที่ถูกตั้งค่า
    e.previousValue เป็น value ก่อนที่จะถูกเปลี่ยนแปลง
    e.object = object ของ package folder เป็น function เพื่อไว้ใช้งาน
  */
}

หรือ ฟังก์ชั่นนี้สามารถอ้างอิงเป็น string ได้ โดยใช้ชื่อ field ที่นิยามไว้ใน object ข้อ 1.4

{
  "setParameter": "function-1" 
}

3.4.2.5. getParameter [function/string] ฟังก์ชั่นนี้จะถูกเรียกใช้เมื่อมีการถามค่า parameter โดยต้องมีการ return value กลับไป  ปกติจะถูกเรียกถามจาก callback
{
  "getParameter":function(e) {
    /*
     ใน e จะมี
      e.id = id ของ element
      e.key = ชื่อของ parameter
      e.object = object ของ package folder เป็น function เพื่อไว้ใช้งาน
    */
    return "value";
  }
}

หรือ ฟังก์ชั่นนี้สามารถอ้างอิงเป็น string ได้ โดยใช้ชื่อ field ที่นิยามไว้ใน object ข้อ 1.4

{
  "getParameter": "function-2" 
}

3.5. callback [array of object] ประกอบไปด้วย callback ของ component เพื่อให้ผู้ใช้ตั้งค่าได้
มีสมาชิก 2 แบบ คือ
3.5.1. group [object] ลักษณะเหมือนกับ folder ใช้เก็บ group/callback ย่อยอื่นๆ
โดยจะประกอบไปด้วย
3.5.1.1. name [string] ชื่อของ group
3.5.1.2. text [string] แสดงเมื่อมีการ hover ที่ group
3.5.1.3. children [array of object] ที่ใช้เก็บ group/callback ย่อยอื่นๆ
3.5.2. callback [object] เป็น callback ที่ให้ผู้ใช้ตั้งค่าได้
โดยมี field ต่างๆ ดังนี้
3.5.2.1. name [string] ชื่อของ callback
3.5.2.2. text [string] แสดงเมื่อมีการ hover ที่ callback
3.5.2.4. setCallback [function/string] ฟังก์ชั่นนี้จะถูกเรียกใช้เมื่อมีการตั้งค่า parameter โดยจะถูกเรียกเมื่อมีการสร้าง web page และเมื่อมีการเปลี่ยนแปลงจาก callback

"setCallback":function(e) {
  /*
   ใน e จะมี
    e.id = id ของ element
    e.key = ชื่อของ callback
    e.value = เป็น value ที่ถูกตั้งค่า
    e.object = object ของ package folder เป็น function เพื่อไว้ใช้งาน
  */

}

หรือ ฟังก์ชั่นนี้สามารถอ้างอิงเป็น string ได้ โดยใช้ชื่อ field ที่นิยามไว้ใน function ข้อ 1.4

{
  "setCallback": "function-3" 
}

3.6. write_head_init [function] เป็น function ที่จะถูกเรียกใช้เพื่อสร้าง component โดยต้องมีการ return เป็น string และ string จะถูกนำไปเขียนไว้ในส่วน <head> ใช้สำหรับกรณีมี js/css พิเศษเพื่อ initialize ถ้ามี component ชนิดเดียวกันหลายตัว write_head_init จะถูกเรียกใช้เพียงครั้งเดียว
3.7. write_body_start [function] เป็น function ที่จะถูกเรียกใช้เพื่อสร้าง component โดยต้องมีการ return เป็น string และ string จะถูกนำไปเขียนไว้ในส่วน <body> เป็นการเปิด tag ถ้า component นี้มีลูก tag ของลูกก็จะถูกเขียนต่อไปอีก
3.8. write_body_end [function] เป็น function ที่จะถูกเรียกใช้เพื่อสร้าง component โดยต้องมีการ return เป็น string และ string จะถูกนำไปเขียนไว้ในส่วน <body> เป็นการปิด tag โดยถ้า component นี้มีลูก write_body_start และ write_body_end ของลูกจะถูกเรียกใช้ก่อน เมื่อหมดแล้วจึงปิด tag ของ parent
3.9. write_body_init [function] เป็น function ที่จะถูกเรียกใช้เพื่อสร้าง component โดยต้องมีการ return เป็น string และ string จะถูกนำไปเขียนไว้ในส่วนท้าย <body> ใช้สำหรับกรณีมี js/css พิเศษเพื่อ initialize ถ้ามี component ชนิดเดียวกันหลายตัว write_body_init จะถูกเรียกใช้เพียงครั้งเดียว
3.10. add_body_script [function] เป็น function โดย function นี้จะถูกแปลงเป็น string และใส่ไว้ในภายใน tag <script> ก่อน </body> โดยฟังก์ชั่นนี้ไม่มีการ return ใช้สำหรับควบคุมเปลี่ยนแปลงโครงสร้าง web app ซึ่งเป็น function เดียวที่จะถูก execute โดยตรงเมื่อ load web page
3.11. permission เป็น array ของ json ประกอบด้วย id, name ใช้นิยาม permission ของ component ซึ่งจะมี API เรียกถามว่า user มีสิทธิ์อะไรบ้างตาม permission id ที่นิยามไว้ และผู้สร้าง component จัดสร้าง component ให้ตรงตามนิยาม

*function ใน ข้อ 3.6-3.10 จะมี parameter เป็น object มี field ที่สำคัญ คือ
id เป็น id ของ component เพื่อใช้อ้างอิง
property.parameter เป็น object ของ parameter โดยอ้างอิงชื่อ parameter จะได้ value

function(e) {
// e.id
// e.property.parameter
}

ตำแหน่งการเขียน string ใน HTML สำหรับ function ใน 3.6-3.10

<!DOCTYPE html>
<html>
<head>
<!-- string ที่ return มาจากการเรียกใช้ write_head_init จะถูกนำมาวางที่นี่ -->
</head>
<body>

    <!-- string ที่ return มาจากการเรียกใช้ write_body_start จะถูกนำมาวางที่นี่ เพื่อเปิด tag -->
    <!-- string ที่ return มาจากการเรียกใช้ write_body_end จะถูกนำมาวางที่นี่ เพื่อปิด tag -->

    <!-- string ที่ return มาจากการเรียกใช้ write_body_init จะถูกนำมาวางที่นี่ -->
<script>
    /* add_body_script จะถูกนำมาวางไว้ที่นี่ และถูกเรียกใช้เมื่อ load หน้า page */
    (function(e) {
        /* เนื้อหาใน add_body_script */    
    })();
</script>
</body>
</html>

ตัวอย่างโครงสร้าง package file เป็นไฟล์นามสกุล js

ID = "_MY_ID";
PACKAGE = {
  "_MY_ID":{
    "name": "My package", "text": "My package", "children": ["_folder_1", "_folder_1"], 
    "object": {
      "function_1":function(e) {

      }, 
      "function_2":function(e) {

      }
    }
  },
  "_folder_1":{
    "name": "Folder-1", "text": "Folder 1", "children": ["_component_1_1", "_component_1_2"]
  },
  "_folder_2":{
    "name": ""Folder-2", "text": "Folder 2", "children": ["_component_2_1", "_component_2_2"]
  },
  "_component_1_1":{
    "name": "Component 1.1", "text": "Component 1.1", "children": true, 
    "parameter":[
      {"name": "property-group-1", "text": "property-group-1", "children": [
        {"name": "property-1-1", "text": "property-1-1" 
        }
      ]}, 
      {"name": "property-2", "text": "property-2", 
        "input":{"type": "custom", "value":{}, "open": function(e) {}, "save":function(e) {}}
      }
    ], 
    "callback":[], 
    "write_head_init":function(e) { return "<script></script>";}, 
    "write_body_start":function(e){ return "<div>";}, 
    "write_body_end":function(e){ return "</div>";}, 
    "write_body_init":function(e) { return "<script></script>";}, 
    "add_body_script":function(e){}
  },
  "_component_1_2":{
    "name": "Component 1.1", "text": "Component 1.2", "children": true, 
    "parameter":[], "callback":[], 
    "write_head_init":function(e) { return "<script></script>";}, 
    "write_body_start":function(e){ return "<div>";}, 
    "write_body_end":function(e){ return "</div>";}, 
    "write_body_init":function(e) { return "<script></script>";}, 
    "add_body_script":function(e){}
  },
  "_component_2_1":{
    "name": "Component 2.1", "text": "Component 2.1", "children": false, 
    "parameter":[], "callback":[], 
    "write_head_init":function(e) { return "<script></script>";}, 
    "write_body_start":function(e){ return "<div>";}, 
    "write_body_end":function(e){ return "</div>";}, 
    "write_body_init":function(e) { return "<script></script>";}, 
    "add_body_script":function(e){}
  },
  "_component_2_2":{
    "name": "Component 2.2", "text": "Component 2.2", "children": false, 
    "parameter":[], "callback":[], 
    "write_head_init":function(e) { return "<script></script>";}, 
    "write_body_start":function(e){ return "<div>";}, 
    "write_body_end":function(e){ return "</div>";}, 
    "write_body_init":function(e) { return "<script></script>";}, 
    "add_body_script":function(e){}
  },
  "_component_3":{
    "name": "Component 3", "text": "Component 3", "children": true, 
    "parameter":[], "callback":[], 
    "write_head_init":function(e) { return "<script></script>";}, 
    "write_body_start":function(e){ return "<div>";}, 
    "write_body_end":function(e){ return "</div>";}, 
    "write_body_init":function(e) { return "<script></script>";}, 
    "add_body_script":function(e){}
  }
};

โครงสร้างใน Package นี้จะประกอบไปด้วย
My package
Folder-1
Component 1.1
Component 1.2
Folder-2
Component 2.1
Component 2.2
Component 3

Package folder คือ My package โดยมี ID=”_MY_ID” เป็น ID หลักของ package นี้
มี package function คือ function_1 และ function_2
Component folder คือ Folder-1, Folder-2
Component object คือ
Component 1.1 มีลูกได้
Component 1.2 มีลูกได้
Component 2.1 มีลูกไม่ได้
Component 2.2 มีลูกไม่ได้
Component 3 มีลูกได้

ตัวอย่าง built-in package ดูได้จากไฟล์ buitin-component-example.js
ตัวอย่าง package ดูได้จากไฟล์ component.js
โดยใช้ปุ่ม import ในการ import package เข้าไปเพื่อใช้งาน

Library ที่สามารถใช้ได้
1. bootstrap 4.3.1
2. d3.js 5.12.0
3. fontawesome 5.11.2 Free เฉพาะ icon แบบ regular และ solid รายละเอียดดูได้จาก https://fontawesome.com/icons?d=gallery&s=regular,solid&m=free
4. jquery 3.4.1
5. plotly.js 1.50.1

API
  • ไม่มีใน Aimagin Connect test site ต้อง log-in เข้าระบบ
    1. API ที่ใช้สำหรับอ่านค่าจาก database
    1.1 เรียกถาม Table ทั้งหมดที่สร้างขึ้น
    AmgCnt.SQLite.read.getTables(function(table) {
    /*
      table = [{name:"table name 1", column:[{name:"column name 1", type:""}, {name:"column name 2", type:""}, ...]}, ...]
    */
    });
    

1.2. อ่านค่าจาก table แบบ all ได้กลับมาเป็น array ของ rows ทั้งหมดที่ query เจอ

AmgCnt.SQLite.read.all({sql:"query string", params:[]}, function(res) {
/*
  res.err = ถ้ามี error จากการ query จะไม่เป็น null
  res.errMsg = ถ้ามี error จากการ query จะมีค่า error message
  res.rows = array ของ json ที่เก็บ fields ที่ query มาได้ ถ้า error จะเป็น undefined
*/
});
AmgCnt.SQLite.read.get({sql:"SELECT datetime, p0, p1 FROM GW_TEST WHERE p0 >= ?", params:[10]}, function(res) {
/*
  เป็นการดึง row แรกที่พบเมื่อ p0 >= 10
  res.row จะมีหน้าตาเช่น [{datetime:"2019-07-01T00:00:00+07:00", p0:53.128, p1:55.953}, {datetime:"2019-07-01T00:01:00+07:00", p0:29.611, p1:65.341}, {datetime:"2019-07-01T00:02:00+07:00", p0:64.068, p1:85.574}...]
*/
});

1.3. อ่านค่าจาก table แบบ get ได้กลับมาเป็น row แรกที่ query เจอ

AmgCnt.SQLite.read.get({sql:"query string", params:[]}, function(res) {
/*
  res.err = ถ้ามี error จากการ query จะไม่เป็น null
  res.errMsg = ถ้ามี error จากการ query จะมีค่า error message
  res.row = json ที่เก็บ fields ที่ query มาได้ ถ้า error จะเป็น undefined
*/
});
/*Example */
AmgCnt.SQLite.read.get({sql:"SELECT datetime, p0, p1 FROM GW_TEST WHERE p0 >= ?", params:[10]}, function(res) {
/*
  เป็นการดึง row แรกที่พบเมื่อ p0 >= 10
  res.row จะมีหน้าตาเช่น {datetime:"2019-07-01T00:00:00+07:00", p0:53.128, p1:55.953}
*/
});

*all กับ get ดูเพื่มเติมได้ที่ https://www.sqlitetutorial.net/sqlite-nodejs/query/

2. API สำหรับ insert row

AmgCnt.SQLite.create.run({sql:"INSERT INTO table_name (c1, c2, c3)  VALUES (1, 2, 3), (4, 5, 6)", params:[]}, (res)=>{

});

3. API สำหรับ update row

AmgCnt.SQLite.update.run({sql:"UPDATE table_name SET c1='a', c2=1, c3='123 456 789' WHERE c1='z'", params:[]}, (res)=>{

});

2. User และ Permission
2.1 AmgCnt.User.getUser() ใช้สำหรับ get detail ของ user จะได้ json กลับมามี {email, firstname, lastname, department, mobile}
2.2 AmgCnt.User.getPermission(id) ใช้สำหรับถาม permission ของ component โดยส่งค่า id ของ component เข้าไปใน function จะได้ json กลับมาโดยมีสมาชิกเป็น permission id ตามที่นิยามไว้ใน field permission ใน component ถ้า permission ไหนเปิดใช้งานจะเป็น true เช่น {"permission-code-1":true, "permission-code-1":false}
2.3 AmgCnt.User.getDatabasePermission() ใช้สำหรับถาม database permission ของ user โดยจะได้ json กลับมาประกอบไปด้วย crud ถ้า มีสิทธิ์ c:insert, r:query, u:update, d:delete field c, r, u, d จะมีค่าเป็น true
2.1, 2.2, 2.3 ใช้ได้ใน add_body_script เนื่องจาก add_body_script จะถูกเรียกใช้ในขั้นตอนการ initialize web app

3. ตัวอย่าง (ใน attachment)
3.1 Bar chart widget
3.2 Form widget