การพัฒนาแอปพลิเคชันด้วยกรอบการพัฒนาแอปพลิเคชันอย่างรวดเร็ว AllcountJS

เผยแพร่แล้ว: 2022-03-11

แนวคิดของ Rapid Application Development (RAD) ถือกำเนิดขึ้นเพื่อตอบสนองต่อแบบจำลองการพัฒนาน้ำตกแบบดั้งเดิม RAD มีหลายรูปแบบ ตัวอย่างเช่น การพัฒนาแบบ Agile และกระบวนการรวมที่เป็นหนึ่งอย่างมีเหตุผล อย่างไรก็ตาม โมเดลดังกล่าวทั้งหมดมีสิ่งหนึ่งที่เหมือนกัน นั่นคือ เป้าหมายในการสร้างมูลค่าทางธุรกิจสูงสุดโดยใช้เวลาในการพัฒนาน้อยที่สุดผ่านการสร้างต้นแบบและการพัฒนาซ้ำ เพื่อให้บรรลุสิ่งนี้ โมเดล Rapid Application Development อาศัยเครื่องมือที่ช่วยให้กระบวนการง่ายขึ้น ในบทความนี้ เราจะมาสำรวจเครื่องมือดังกล่าว และวิธีการใช้เครื่องมือดังกล่าวเพื่อมุ่งเน้นที่มูลค่าทางธุรกิจและการเพิ่มประสิทธิภาพของกระบวนการพัฒนา

AllcountJS เป็นเฟรมเวิร์กโอเพ่นซอร์สที่เกิดขึ้นใหม่ซึ่งสร้างขึ้นโดยคำนึงถึงการพัฒนาแอปพลิเคชันอย่างรวดเร็ว มันขึ้นอยู่กับแนวคิดของการพัฒนาแอปพลิเคชันที่เปิดเผยโดยใช้รหัสการกำหนดค่าเหมือน JSON ที่อธิบายโครงสร้างและพฤติกรรมของแอปพลิเคชัน เฟรมเวิร์กนี้สร้างขึ้นบน Node.js, Express, MongoDB และอาศัย AngularJS และ Twitter Bootstrap เป็นหลัก แม้ว่าจะใช้รูปแบบการประกาศ แต่เฟรมเวิร์กยังอนุญาตให้ปรับแต่งเพิ่มเติมผ่านการเข้าถึงโดยตรงไปยัง API เมื่อจำเป็น

AllcountJS เป็น RAD Framework ของคุณ

ทำไม AllcountJS เป็นเฟรมเวิร์ก RAD ของคุณ

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

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

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

เริ่มต้น

เพื่อแสดงความสามารถบางอย่างของเฟรมเวิร์ก RAD AllcountJS เราจะสร้างแอปพลิเคชันอย่างง่ายสำหรับ Toptal ซึ่งเราจะเรียกว่า Toptal Community หากคุณติดตามบล็อกของเรา คุณอาจทราบแล้วว่าแอปพลิเคชันที่คล้ายกันนี้สร้างขึ้นโดยใช้ Hoodie ซึ่งเป็นส่วนหนึ่งของโพสต์บล็อกก่อนหน้าของเรา แอปพลิเคชันนี้จะช่วยให้สมาชิกในชุมชนสามารถลงทะเบียน สร้างกิจกรรม และสมัครเข้าร่วมได้

ในการตั้งค่าสภาพแวดล้อม คุณควรติดตั้ง Node.js, MongoDB และ Git จากนั้น ติดตั้ง AllcountJS CLI โดยเรียกใช้คำสั่ง "npm install" และดำเนินการโครงการ init:

 npm install -g allcountjs-cli allcountjs init toptal-community-allcount cd toptal-community-allcount npm install

AllcountJS CLI จะขอให้คุณป้อนข้อมูลบางอย่างเกี่ยวกับโครงการของคุณเพื่อเติม package.json ล่วงหน้า

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

ภายในไดเร็กทอรี app-config ที่สร้างขึ้นใหม่นี้ เราจะแทนที่เนื้อหาของไฟล์ main.js JavaScript ด้วยข้อมูลโค้ดต่อไปนี้:

 A.app({ appName: "Toptal Community", onlyAuthenticated: true, allowSignUp: true, appIcon: "rocket", menuItems: [{ name: "Events", entityTypeId: "Event", icon: "calendar" }, { name: "My Events", entityTypeId: "MyEvent", icon: "calendar" }], entities: function(Fields) { return { Event: { title: "Events", fields: { eventName: Fields.text("Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required(), appliedUsers: Fields.relation("Applied users", "AppliedUser", "event") }, referenceName: "eventName", sorting: [['date', -1], ['time', -1]], actions: [{ id: "apply", name: "Apply", actionTarget: 'single-item', perform: function (User, Actions, Crud) { return Crud.actionContextCrud().readEntity(Actions.selectedEntityId()).then(function (eventToApply) { var userEventCrud = Crud.crudForEntityType('UserEvent'); return userEventCrud.find({filtering: {"user": User.id, "event": eventToApply.id}}).then(function (events) { if (events.length) { return Actions.modalResult("Can't apply to event", "You've already applied to this event"); } else { return userEventCrud.createEntity({ user: {id: User.id}, event: {id: eventToApply.id}, date: eventToApply.date, time: eventToApply.time }).then(function () { return Actions.navigateToEntityTypeResult("MyEvent") }); } }); }) } }] }, UserEvent: { fields: { user: Fields.fixedReference("User", "OnlyNameUser").required(), event: Fields.fixedReference("Event", "Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required() }, filtering: function (User) { return {"user.id": User.id} }, sorting: [['date', -1], ['time', -1]], views: { MyEvent: { title: "My Events", showInGrid: ['event', 'date', 'time'], permissions: { write: [], delete: null } }, AppliedUser: { permissions: { write: [] }, showInGrid: ['user'] } } }, User: { views: { OnlyNameUser: { permissions: { read: null, write: ['admin'] } }, fields: { username: Fields.text("User name") } } } } } });

แม้ว่า AllcountJS จะทำงานกับที่เก็บ Git แต่เพื่อความง่าย เราจะไม่ใช้ในบทช่วยสอนนี้ ในการรันแอปพลิเคชัน Toptal Community สิ่งที่เราต้องทำคือเรียกใช้คำสั่ง AllcountJS CLI run ในไดเร็กทอรี toptal-community-allcount

 allcountjs run

เป็นที่น่าสังเกตว่า MongoDB ควรทำงานเมื่อดำเนินการคำสั่งนี้ หากทุกอย่างเป็นไปด้วยดี แอปพลิเคชันควรเริ่มทำงานที่ http://localhost:9080

ในการเข้าสู่ระบบ โปรดใช้ชื่อผู้ใช้ “admin” และรหัสผ่าน “admin”

น้อยกว่า 100 เส้น

คุณอาจสังเกตเห็นว่าแอปพลิเคชันที่กำหนดใน main.js ใช้โค้ดเพียง 91 บรรทัด บรรทัดเหล่านี้รวมถึงการประกาศพฤติกรรมทั้งหมดที่คุณอาจสังเกตเห็นเมื่อคุณไปที่ http://localhost:9080 ดังนั้นสิ่งที่เกิดขึ้นภายใต้ประทุน? ให้เราพิจารณาแต่ละแง่มุมของแอปพลิเคชันให้ละเอียดยิ่งขึ้น และดูว่ารหัสเกี่ยวข้องกับพวกเขาอย่างไร

เข้าสู่ระบบและลงทะเบียน

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

เข้าสู่ระบบและลงทะเบียน

หน้านี้แสดงขึ้นเนื่องจากไฟล์ main.js ประกาศว่าเฉพาะผู้ใช้ที่ตรวจสอบสิทธิ์แล้วเท่านั้นที่สามารถใช้แอปพลิเคชันนี้ได้ นอกจากนี้ยังช่วยให้ผู้ใช้สามารถสมัครจากหน้านี้ได้ สองบรรทัดต่อไปนี้มีความจำเป็นสำหรับสิ่งนี้:

 A.app({ ..., onlyAuthenticated: true, allowSignUp: true, ... })

ยินดีต้อนรับเพจ

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

ตัวอย่างหน้ายินดีต้อนรับ

พร้อมกับการกำหนดค่าที่เกี่ยวข้องอื่นๆ อีกสองสามรายการ เมนูถูกกำหนดไว้ในไฟล์ main.js ดังนี้:

 A.app({ ..., appName: "Toptal Community", appIcon: "rocket", menuItems: [{ name: "Events", entityTypeId: "Event", icon: "calendar" }, { name: "My Events", entityTypeId: "MyEvent", icon: "calendar" }], ... });

AllcountJS ใช้ไอคอน Font Awesome ดังนั้นชื่อไอคอนทั้งหมดที่อ้างอิงในการกำหนดค่าจะถูกจับคู่กับชื่อไอคอน Font Awesome

เรียกดูและแก้ไขเหตุการณ์

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

 A.app({ ..., entities: function(Fields) { return { Event: { title: "Events", fields: { eventName: Fields.text("Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required(), appliedUsers: Fields.relation("Applied users", "AppliedUser", "event") }, referenceName: "eventName", sorting: [['date', -1], ['time', -1]], ... } } } });

ตัวอย่างนี้แสดงวิธีกำหนดค่าคำอธิบายเอนทิตีใน AllcountJS สังเกตว่าเราใช้ฟังก์ชันเพื่อกำหนดเอนทิตีอย่างไร ทุกคุณสมบัติของการกำหนดค่า AllcountJS สามารถเป็นฟังก์ชันได้ ฟังก์ชันเหล่านี้สามารถร้องขอให้มีการพึ่งพาเพื่อแก้ไขผ่านชื่ออาร์กิวเมนต์ ก่อนเรียกใช้ฟังก์ชัน จะมีการแทรกการพึ่งพาที่เหมาะสม ในที่นี้ “ฟิลด์” เป็นหนึ่งใน API การกำหนดค่า AllcountJS ที่ใช้เพื่ออธิบายฟิลด์เอนทิตี คุณสมบัติ “เอนทิตี” ประกอบด้วยคู่ของชื่อ-ค่า โดยที่ชื่อเป็นตัวระบุประเภทเอนทิตี และค่าคือคำอธิบาย ในตัวอย่างนี้มีการอธิบายประเภทเอนทิตีสำหรับเหตุการณ์ โดยที่ชื่อคือ "เหตุการณ์" การกำหนดค่าอื่นๆ เช่น การเรียงลำดับเริ่มต้น ชื่ออ้างอิง และอื่นๆ ในทำนองเดียวกัน อาจกำหนดไว้ที่นี่ด้วย Default-sort-order ถูกกำหนดผ่านอาร์เรย์ของชื่อฟิลด์และทิศทาง ในขณะที่ชื่ออ้างอิงถูกกำหนดผ่านสตริง (อ่านเพิ่มเติมที่นี่)

ฟังก์ชัน allcountJS

ประเภทของเอนทิตีเฉพาะนี้ถูกกำหนดให้มีสี่ฟิลด์: “eventName,” “date,” “time” และ “appliedUsers” ซึ่งสามรายการแรกจะคงอยู่ในฐานข้อมูล ฟิลด์เหล่านี้เป็นฟิลด์บังคับ ตามที่ระบุโดยการใช้ “required()” ค่าในฟิลด์เหล่านี้ที่มีกฎดังกล่าวจะได้รับการตรวจสอบก่อนที่จะส่งแบบฟอร์มที่ส่วนหน้าตามที่แสดงในภาพหน้าจอด้านล่าง AllcountJS รวมการตรวจสอบทั้งฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์เพื่อมอบประสบการณ์การใช้งานที่ดีที่สุด ฟิลด์ที่สี่คือความสัมพันธ์ที่มีรายชื่อผู้ใช้ที่สมัครเข้าร่วมกิจกรรม โดยปกติ ฟิลด์นี้จะไม่คงอยู่ในฐานข้อมูล และเติมข้อมูลโดยการเลือกเฉพาะเอนทิตี AppliedUser ที่เกี่ยวข้องกับเหตุการณ์

กฎการพัฒนา allcountjs

การสมัครเข้าร่วมกิจกรรม

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

 actions: [{ id: "apply", name: "Apply", actionTarget: 'single-item', perform: function (User, Actions, Crud) { return Crud.actionContextCrud().readEntity(Actions.selectedEntityId()).then(function (eventToApply) { var userEventCrud = Crud.crudForEntityType('UserEvent'); return userEventCrud.find({filtering: {"user": User.id, "event": eventToApply.id}}).then(function (events) { if (events.length) { return Actions.modalResult("Can't apply to event", "You've already applied to this event"); } else { return userEventCrud.createEntity({ user: {id: User.id}, event: {id: eventToApply.id}, date: eventToApply.date, time: eventToApply.time }).then(function () { return Actions.navigateToEntityTypeResult("MyEvent") }); } }); }) } }]

คุณสมบัติ "การดำเนินการ" ของประเภทเอนทิตีใด ๆ ใช้อาร์เรย์ของออบเจ็กต์ที่อธิบายพฤติกรรมของการกระทำแบบกำหนดเองแต่ละรายการ แต่ละอ็อบเจ็กต์มีคุณสมบัติ "id" ซึ่งกำหนดตัวระบุเฉพาะสำหรับการดำเนินการ คุณสมบัติ "name" กำหนดชื่อที่แสดง และคุณสมบัติ "actionTarget" ใช้เพื่อกำหนดบริบทการดำเนินการ การตั้งค่า "actionTarget" เป็น "single-item" บ่งชี้ว่าควรทำการดำเนินการกับเหตุการณ์เฉพาะ ฟังก์ชันที่กำหนดภายใต้คุณสมบัติ "ดำเนินการ" คือตรรกะที่ดำเนินการเมื่อดำเนินการนี้ โดยทั่วไปเมื่อผู้ใช้คลิกที่ปุ่มที่เกี่ยวข้อง

ฟังก์ชันนี้อาจร้องขอการพึ่งพาได้ ตัวอย่างเช่น ในตัวอย่างนี้ ฟังก์ชันขึ้นอยู่กับ "ผู้ใช้" "การดำเนินการ" และ "Crud" เมื่อมีการดำเนินการ สามารถรับการอ้างอิงถึงผู้ใช้ที่เรียกใช้การดำเนินการนี้ได้โดยกำหนดให้มีการพึ่งพา "ผู้ใช้" มีการขอการพึ่งพา "Crud" ซึ่งอนุญาตให้จัดการสถานะฐานข้อมูลสำหรับเอนทิตีเหล่านี้ด้วย สองวิธีที่ส่งคืนอินสแตนซ์ของวัตถุ Crud คือ: วิธี “actionContextCrud()” - ส่งคืน CRUD สำหรับประเภทเอนทิตี "เหตุการณ์" เนื่องจากการกระทำ "ใช้" เป็นของในขณะที่วิธีการ "crudForEntityType()" - ส่งกลับ CRUD สำหรับประเภทเอนทิตีใดๆ ที่ระบุโดยรหัสประเภท

การพึ่งพา CRUD

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

การดำเนินการของการกระทำ

กำหนดการผู้ใช้ของกิจกรรมประยุกต์

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

 UserEvent: { fields: { user: Fields.fixedReference("User", "OnlyNameUser").required(), event: Fields.fixedReference("Event", "Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required() }, filtering: function (User) { return {"user.id": User.id} }, sorting: [['date', -1], ['time', -1]], views: { MyEvent: { title: "My Events", showInGrid: ['event', 'date', 'time'], permissions: { write: [], delete: null } }, AppliedUser: { permissions: { write: [] }, showInGrid: ['user'] } } },

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

คุณสมบัติที่น่าสนใจอีกประการหนึ่งคือ “วิว” “มุมมอง” เป็นประเภทเอนทิตีปกติ แต่คอลเล็กชัน MongoDB จะเหมือนกับประเภทเอนทิตีหลัก ทำให้สามารถสร้างมุมมองที่แตกต่างกันสำหรับข้อมูลเดียวกันในฐานข้อมูลได้ อันที่จริง เราใช้คุณลักษณะนี้เพื่อสร้างมุมมองที่แตกต่างกันสองแบบสำหรับ “UserEvent:” “MyEvent” และ “AppliedUser” เนื่องจากต้นแบบของมุมมองย่อยถูกตั้งค่าเป็นชนิดเอนทิตีหลัก คุณสมบัติที่ไม่ถูกแทนที่จึง "สืบทอด" จากประเภทหลัก

มุมมอง

รายชื่อผู้เข้าร่วมกิจกรรม

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

 AppliedUser: { permissions: { write: [] }, showInGrid: ['user'] } // ... appliedUsers: Fields.relation("Applied users", "AppliedUser", "event")

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

ผู้ใช้สำหรับประเภท myevent

การขยายการใช้งานเริ่มต้น

Backdraw ทั่วไปของเฟรมเวิร์ก RAD คือการขาดความยืดหยุ่น เมื่อคุณสร้างแอปและต้องปรับแต่งแอปแล้ว คุณอาจพบกับอุปสรรคสำคัญ AllcountJS ได้รับการพัฒนาโดยคำนึงถึงความสามารถในการขยาย และอนุญาตให้เปลี่ยนโครงสร้างภายในทั้งหมดได้

เพื่อให้บรรลุ AllcountJS ใช้การพึ่งพาการฉีด (DI) ของตัวเอง DI ช่วยให้นักพัฒนาสามารถแทนที่พฤติกรรมเริ่มต้นของกรอบงานผ่านจุดขยาย และในขณะเดียวกันก็อนุญาตผ่านการนำการใช้งานที่มีอยู่มาใช้ซ้ำ หลายแง่มุมของส่วนขยายเฟรมเวิร์ก RAD ได้อธิบายไว้ในเอกสารประกอบ ในส่วนนี้ เราจะสำรวจว่าเราอาจขยายสององค์ประกอบในเฟรมเวิร์ก ลอจิกฝั่งเซิร์ฟเวอร์ และมุมมองได้อย่างไร

ต่อด้วยตัวอย่าง Toptal Community ของเรา ให้เรารวมแหล่งข้อมูลภายนอกเพื่อรวมข้อมูลเหตุการณ์ ลองนึกภาพว่ามีโพสต์ Toptal Blog ที่พูดคุยเกี่ยวกับแผนงานกิจกรรมในวันก่อนแต่ละงาน ด้วย Node.js คุณควรแยกวิเคราะห์ฟีด RSS ของบล็อกและดึงข้อมูลดังกล่าว ในการดำเนินการนี้ เราจำเป็นต้องมีการพึ่งพา npm เพิ่มเติม เช่น "request" "xml2js" (เพื่อโหลด Toptal Blog RSS feed) "q" (เพื่อใช้คำมั่นสัญญา) และ "moment" (เพื่อแยกวิเคราะห์วันที่) สามารถติดตั้งการพึ่งพาเหล่านี้ได้โดยการเรียกใช้ชุดคำสั่งต่อไปนี้:

 npm install xml2js npm install request npm install q npm install moment

มาสร้างไฟล์ JavaScript อื่น ตั้งชื่อว่า "toptal-community.js" ในไดเร็กทอรี toptal-community-allcount และเติมข้อมูลต่อไปนี้:

 var request = require('request'); var Q = require('q'); var xml2js = require('xml2js'); var moment = require('moment'); var injection = require('allcountjs'); injection.bindFactory('port', 9080); injection.bindFactory('dbUrl', 'mongodb://localhost:27017/toptal-community'); injection.bindFactory('gitRepoUrl', 'app-config'); injection.bindFactory('DiscussionEventsImport', function (Crud) { return { importEvents: function () { return Q.nfcall(request, "https://www.toptal.com/blog.rss").then(function (responseAndBody) { var body = responseAndBody[1]; return Q.nfcall(xml2js.parseString, body).then (function (feed) { var events = feed.rss.channel[0].item.map(function (item) { return { eventName: "Discussion of " + item.title, date: moment(item.pubDate, "DD MMM YYYY").add(1, 'day').toDate(), time: "12:00" }}); var crud = Crud.crudForEntityType('Event'); return Q.all(events.map(function (event) { return crud.find({query: {eventName: event.eventName}}).then(function (createdEvent) { if (!createdEvent[0]) { return crud.createEntity(event); } }); } )); }); }) } }; }); var server = injection.inject('allcountServerStartup'); server.startup(function (errors) { if (errors) { throw new Error(errors.join('\n')); } });

ในไฟล์นี้ เรากำลังกำหนดการอ้างอิงที่เรียกว่า "DiscussionEventsImport" ซึ่งเราสามารถใช้ในไฟล์ main.js ของเราโดยเพิ่มการดำเนินการนำเข้าในประเภทเอนทิตี "เหตุการณ์"

 { id: "import-blog-events", name: "Import Blog Events", actionTarget: "all-items", perform: function (DiscussionEventsImport, Actions) { return DiscussionEventsImport.importEvents().then(function () { return Actions.refreshResult() }); } }

เนื่องจากเป็นสิ่งสำคัญที่จะรีสตาร์ทเซิร์ฟเวอร์หลังจากทำการเปลี่ยนแปลงบางอย่างกับไฟล์ JavaScript คุณอาจฆ่าอินสแตนซ์ก่อนหน้าและเริ่มต้นใหม่อีกครั้งโดยดำเนินการคำสั่งเดิมเหมือนเมื่อก่อน:

 node toptal-community.js

หากทุกอย่างถูกต้อง คุณจะเห็นภาพหน้าจอด้านล่างหลังจากเรียกใช้การดำเนินการ "นำเข้ากิจกรรมบล็อก"

นำเข้ากิจกรรมบล็อกการกระทำ

จนถึงตอนนี้ก็ดี แต่อย่าให้เราหยุดเพียงแค่นี้ มุมมองเริ่มต้นใช้งานได้ แต่บางครั้งอาจน่าเบื่อ ให้เราปรับแต่งเล็กน้อย

คุณชอบการ์ดไหม ทุกคนชอบการ์ด! ในการสร้างมุมมองการ์ด ให้ใส่ข้อมูลต่อไปนี้ในไฟล์ชื่อ events.jade ภายในไดเร็กทอรี app-config:

 extends main include mixins block vars - var hasToolbar = true block content .refresh-form-controller(ng-app='allcount', ng-controller='EntityViewController') +defaultToolbar() .container.screen-container(ng-cloak) +defaultList() .row: .col-lg-4.col-md-6.col-xs-12(ng-repeat="item in items") .panel.panel-default .panel-heading h3 {{item.date | date}} {{item.time}} div button.btn.btn-default.btn-xs(ng-if="!isInEditMode", lc-tooltip="View", ng-click="navigate(item.id)"): i.glyphicon.glyphicon-chevron-right |   button.btn.btn-danger.btn-xs(ng-if="isInEditMode", lc-tooltip="Delete", ng-click="deleteEntity(item)"): i.glyphicon.glyphicon-trash .panel-body h3 {{item.eventName}} +noEntries() +defaultEditAndCreateForms() block js +entityJs()

หลังจากนั้น เพียงอ้างอิงจากเอนทิตี "เหตุการณ์" ใน main.js เป็น "customView: "events" เรียกใช้แอปของคุณและคุณควรเห็นอินเทอร์เฟซแบบการ์ดแทนที่จะเป็นแบบตารางเริ่มต้น

เอนทิตีเหตุการณ์ใน main.js

บทสรุป

ทุกวันนี้ ขั้นตอนการพัฒนาของเว็บแอปพลิเคชันนั้นคล้ายคลึงกันในเทคโนโลยีเว็บจำนวนมาก ซึ่งการดำเนินการบางอย่างซ้ำแล้วซ้ำเล่า คุ้มจริงหรือ? อาจถึงเวลาต้องคิดใหม่วิธีการพัฒนาเว็บแอปพลิเคชันของคุณ

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