คอลเลกชั่น

4

แปลไปแล้ว

ในบทนี้ คุณจะได้

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

    ตอนนี้ก็ถึงเวลาที่จะเข้าไปดูในรายละเอียดว่ามันทำงานอย่างไร และทำความเข้าใจการทำงานของ คอลเลกชั่น ใน Meteor ซึ่ีงเป็นเทคโนโลยีหลักที่ช่วยให้การทำงานนี้เกิดขึ้นได้

    คอลเลกชั่นเป็นโครงสร้างข้อมูลแบบพิเศษที่ช่วยให้เราจัดเก็บข้อมูลลงฐานข้อมูล MongoDB บนเซิร์ฟเวอร์ และซิงโครไนซ์ข้อมูลแบบเรียลไทม์ระหว่างเซิร์ฟเวอร์กับเบราว์เซอร์ของผู้ใช้แต่ละคนที่เชื่อมต่อเข้ามา

    สิ่งที่เราต้องการทำก็คือ จัดเก็บข่าวที่โพสต์ลงฐานข้อมูล และแชร์การใช้งานระหว่างผู้ใช้ภายในแอพ ดังนั้นเราจึงเริ่มต้นด้วยการสร้างคอลเลกชั่นชื่อ Posts ขึ้นเพื่อใช้เก็บข้อมูลนี้

    เนื่องจากเรามักใช้คอลเลกชั่นเป็นศูนย์กลางของแอพ ดังนั้นเราจึงควรวางคอลเลกชั่นไว้ในโฟลเดอร์ lib เพื่อให้แน่ใจว่ามันถูกสร้างขึ้นตอนที่แอพเริ่มทำงานเสมอ โดยในแอพของเรานั้น ให้คุณสร้างโฟลเดอร์ย่อย collections/ ใน lib และสร้างไฟล์ posts.js ไว้ข้างใน ด้วยโค้ดต่อไปนี้ :

    Posts = new Mongo.Collection('posts');
    
    lib/collections/posts.js

    ใช้ Var หรือไม่ใช้ Var กันแน่

    ใน Meteor นั้น คำสั่ง var จะจำกัดการใช้งานของอ็อบเจกต์ไว้เฉพาะในไฟล์ที่เรียกใช้เท่านั้น ด้วยเหตุนี้เราจึงสร้างคอลเลกชั่น Posts โดยไม่มีคำสั่ง var นำหน้า เพื่อให้เราเรียกใช้มันได้จากทุกๆ ที่ในแอพนั่นเอง

    การเก็บข้อมูล

    เว็บแอพมีวิธีจัดเก็บข้อมูลพื้นฐานอยู่ 3 รูปแบบ ดังนี้

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

    • เก็บในที่เก็บข้อมูลของเบราว์เซอร์ : เบราว์เซอร์นั้นสามารถที่จะเก็บข้อมูลให้นานขึ้นได้ด้วยการใช้คุกกี้ หรือที่เก็บข้อมูลส่วนตัว (Local Storage) แม้ว่าข้อมูลที่เก็บไว้นี้จะคงอยู่ในทุกๆ session ของเบราว์เซอร์ มันก็เข้าถึงได้จากผู้ใช้ปัจจุบันเท่านั้น (จากทุกๆ แท็บที่เปิดใช้) และก็ไม่ง่ายที่จะแชร์ข้อมูลนี้ให้ผู้ใช้คนอื่น

    • เก็บลงฐานข้อมูลบนเซิร์ฟเวอร์ : การเก็บลงฐานข้อมูลเป็นทางเลือกที่ดีที่สุด ถ้าคุณต้องการจัดเก็บข้อมูลแบบถาวร และให้ผู้ใช้หลายคนเข้าถึงข้อมูลได้ (แอพของ Meteor จะใช้ MongoDB เป็นฐานข้อมูลตั้งต้น)

    Meteor นั้นใช้การเก็บข้อมูลทั้ง 3 แบบ และในบางครั้งยังทำการซิงโครไนซ์ข้อมูลจากที่หนึ่งไปอีกที่หนึ่งให้ด้วย (เดี๋ยวเราจะได้ดูตัวอย่างกัน) จากที่กล่าวมาจะเห็นได้ว่า ฐานข้อมูลยังคงเป็นแหล่งข้อมูล “หลัก” ที่ใช้เก็บข้อมูลของระบบกันโดยทั่วไป

    ไคลเอนต์และเซิร์ฟเวอร์

    โค้ดที่อยู่นอกโฟลเดอร์ client และ server จะทำงานทั้งในฝั่งไคลเอนต์และฝั่งเซิร์ฟเวอร์ ดังนั้นคอลเลกชั่น Posts จึงถูกเรียกใช้งานได้จากทั้งสองฝั่ง อย่างไรก็ตาม การทำงานของคอลเลกชั่นในแต่ละฝั่งนั้นจะมีความแตกต่างกันอยู่พอสมควร

    ในฝั่งเซิร์ฟเวอร์ หน้าที่ของคอลเลกชั่น คือ ติดต่อกับฐานข้อมูล MongoDB อ่านและเขียนข้อมูลที่มีการเปลี่ยนแปลง หรือเปรียบได้กับไลบรารีของระบบฐานข้อมูลทั่วไปนั่นเอง

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

    คอนโซล กับ คอนโซล กับ คอนโซล

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

    โปรแกรมเทอร์มินอล

    The Terminal
    The Terminal
    • เรียกใช้ได้จากระบบปฏิบัติการ
    • โค้ดที่เซิร์ฟเวอร์ เมื่อใช้คำสั่ง console.log() จะแสดงผลออกที่นี่
    • พร้อมท์คำสั่ง : $
    • รู้จักกันในชื่อ : โปรแกรมเชลล์ หรือ แบชเชลล์ (Bash)

    คอนโซลของเบราว์เซอร์

    The Browser Console
    The Browser Console
    • เรียกใช้ได้จากในเบราว์เซอร์ รันคำสั่งจาวาสคริปต์ได้
    • โค้ดที่ไคลเอนต์ เมื่อใช้คำสั่ง console.log() จะแสดงผลออกที่นี่
    • พร้อมท์คำสั่ง :
    • รู้จักกันในชื่อ : คอนโซลจาวาสคริปต์ คอนโซลนักพัฒนา (DevTools Console)

    โปรแกรมเชลล์ของ Meteor

    The Meteor Shell
    The Meteor Shell
    • เรียกใช้ได้จากโปรแกรมเทอร์มินอล ด้วยคำสั่ง meteor shell
    • ช่วยให้คุณเข้าถึงโค้ดฝั่งเซิร์ฟเวอร์ของแอพคุณได้โดยตรง
    • พร้อมท์คำสั่ง : >

    โปรแกรมเชลล์ของ Mongo

    The Mongo Shell
    The Mongo Shell
    • เรียกใช้ได้จากโปรแกรมเทอร์มินอล ด้วยคำสั่ง meteor mongo
    • ช่วยให้คุณเข้าถึงฐานข้อมูลของแอพคุณโดยตรง
    • พร้อมท์คำสั่ง : >
    • รู้จักกันในชื่อ : คอนโซล Mongo

    จำไว้ว่า คุณไม่จำเป็นต้องป้อนอักษรพร้อมท์ ($, , หรือ >) รวมไปกับคำสั่ง และบรรทัดที่ไม่มีพร้อมท์คำสั่งนำหน้า ก็เป็นการแสดงผลลัพธ์ที่ได้จากคำสั่งก่อนหน้านั้น

    คอลเลกชั่นที่เซิร์ฟเวอร์

    ย้อนกลับไปตรงที่เราบอกว่า คอลเลกชั่นที่เซิร์ฟเวอร์ทำหน้าที่เป็นเหมือนกับไลบรารี่ของฐานข้อมูล Mongo นั่นก็คือ ในโค้ดฝั่งเซิร์ฟเวอร์นั้น คุณสามารถที่จะเขียนคำสั่ง เช่น Posts.insert() หรือ Posts.update() เพื่อทำการแก้ไขเปลี่ยนแปลงคอลเลกชั่น posts ที่เก็บไว้ใน Mongo ได้โดยตรง

    เพื่อให้คุณเห็นข้อมูลในตัว Mongo ให้คุณเปิดโปรแกรมเทอร์มินอลขึ้นอีกตัว (พร้อมๆ กับตัวแรกที่คุณเปิดและรันคำสั่ง meteor ไว้แล้ว) แล้วไปที่โฟลเดอร์ของแอพคุณ จากนั้นให้รันคำสั่ง meteor mongo เพื่อเรียกใช้งานโปรแกรมเชลล์ของ Mongo ซึ่งคุณสามารถป้อนคำสั่งของ Mongo ได้ (คุณสามารถออกจากโปรแกรมด้วยปุ่ม ctrl+c) เช่น ลองเพิ่มโพสต์ข่าวเข้าไปใหม่ ด้วยคำสั่งนี้

    meteor mongo
    
    > db.posts.insert({title: "A new post"});
    
    > db.posts.find();
    { "_id": ObjectId(".."), "title" : "A new post"};
    
    
    The Mongo Shell

    เรียกใช้ Mongo จาก Meteor.com

    คุณควรรู้ว่า หลังจากที่คุณส่งแอพขึ้นไปรันที่ *.meteor.com แล้ว คุณยังสามารถเรียกใช้โปรแกรมเชลล์ของ Mongo เพื่อเข้าถึงฐานข้อมูลของแอพคุณที่รันอยู่ได้ ด้วยคำสั่ง meteor mongo myApp

    และคุณก็ยังสามารถเรียกดูล็อกของแอพคุณได้ ด้วยคำสั่ง meteor logs myApp

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

    คอลเลกชั่นที่ไคลเอนต์

    การใช้คอลเลกชั่นที่ฝั่งไคลเอนต์มีอะไรที่มากกว่านั้น เมื่อคุณกำหนดให้ Posts = new Mongo.Collection('posts'); ที่ไคลเอนต์ ก็เท่ากับคุณได้สร้าง แคชข้อมูลในเบราว์เซอร์ จากข้อมูลจริงในคอลเลกชั่นของฐานข้อมูล Mongo โดย “แคช” ในความหมายของเราก็คือ คอลเลกชั่นของชุดข้อมูลย่อย ที่คุณสามารถเรียกมาใช้งานได้อย่างรวดเร็ว

    เรื่องสำคัญที่ควรรู้เพื่อให้เข้าใจพื้นฐานการทำงานของ Meteor ก็คือ คอลเลกชั่นที่ไคลเอนต์ประกอบด้วยชุดข้อมูลย่อยของเอกสารที่เก็บไว้ในคอลเลกชั่นของ Mongo (เหตุผลก็คือ เราไม่ต้องการส่งข้อมูลทั้งหมดจากฐานข้อมูลไปไว้ที่ไคลเอนต์)

    และเอกสารในชุดข้อมูลย่อยนี้ จะถูกเก็บไว้ในหน่วยความจำของเบราว์เซอร์ เพื่อให้เราเรียกใช้งานได้ทันที ไม่ต้องรอข้อมูลจากเซิร์ฟเวอร์ หรือรอฐานข้อมูลดึงข้อมูลมาให้อีก เมื่อคุณเรียกคำสั่ง Posts.find() ที่ไคลเอนต์ ข้อมูลที่เตรียมไว้ล่วงหน้าก็พร้อมใช้งานแล้ว

    รู้จัก MiniMongo

    เราเรียกโค้ดของ Meteor ที่จัดการฐานข้อมูล Mongo ในฝั่งไคลเอนต์ ว่า MiniMongo ซึ่งมันยังไม่สมบูรณ์แบบเท่าไหร่ โดยคุณอาจพบว่าไม่สามารถใช้คุณสมบัติบางอย่างของ Mongo กับ MiniMongo ได้ แต่คุณก็ไม่ต้องกังวล เพราะในหนังสือเล่มนี้เราใช้งานเฉพาะคุณสมบัติที่ทำงานได้ทั้งบน Mongo และ MiniMongo เท่านั้น

    การสื่อสารระหว่างไคลเอนต์กับเซิร์ฟเวอร์

    หัวใจของเรื่องทั้งหมด ก็คือ คอลเลกชั่นที่ไคลเอนต์ทำการซิงโครไนซ์ข้อมูลกับคอลเลกชั่นชื่อเดียวกัน (ในแอพเราคือ posts) บนเซิร์ฟเวอร์ได้อย่างไร

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

    เริ่มจากเปิดเบราว์เซอร์ขึ้นสองหน้าต่าง แล้วเปิดใช้คอนโซลของเบราว์เซอร์ทั้งสองตัว จากนั้นให้เปิดเชลล์ของ Mongo จากคอมมานด์ไลน์

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

    > db.posts.find();
    {title: "A new post", _id: ObjectId("..")};
    
    ในเชลล์ของ Mongo
     Posts.findOne();
    {title: "A new post", _id: LocalCollection._ObjectID};
    
    ในคอนโซลของเบราว์เซอร์ตัวแรก

    ลองโพสต์ข่าวเข้าไปใหม่ โดยป้อนคำสั่งต่อไปนี้ลงในคอนโซลของเบราว์เซอร์

     Posts.find().count();
    1
     Posts.insert({title: "A second post"});
    'xxx'
     Posts.find().count();
    2
    
    ในคอนโซลของเบราว์เซอร์ตัวแรก

    เป็นไปตามคาด ข่าวใหม่ที่เพิ่งโพสต์ได้ถูกสร้างเข้าไปในคอลเลกชั่นที่ไคลเอนต์แล้ว ตอนนี้ลองเช็คดูที่ Mongo ว่าเป็นยังไง

    ❯ db.posts.find();
    {title: "A new post", _id: ObjectId("..")};
    {title: "A second post", _id: 'yyy'};
    
    ในเชลล์ของ Mongo

    จากที่เห็น ข่าวที่เพิ่งโพสต์นี้ถูกส่งกลับไปเก็บที่ฐานข้อมูล Mongo ด้วย โดยที่เราไม่ต้องเขียนโค้ดจัดการตรงนี้แม้แต่บรรทัดเดียว (อันที่จริงเราเขียนไปแล้ว หนึ่ง บรรทัด: new Mongo.Collection('posts'))

    ยิ่งไปกว่านั้น! ถ้าเราป้อนคำสั่งต่อไปนี้ในคอนโซลของเบราว์เซอร์ตัวที่สอง

     Posts.find().count();
    2
    
    ในคอนโซลของเบราว์เซอร์ตัวที่สอง

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

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

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

    สร้างข้อมูลลงในฐานข้อมูล

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

    สิ่งแรกที่เราจะทำคือ ใส่ข้อมูลลงในฐานข้อมูล โดยเราจะใช้ไฟล์ที่มีชุดข้อมูลตัวอย่างโหลดข้อมูลเข้าไปในคอลเลกชั่น Posts เมื่อเซิร์ฟเวอร์เริ่มทำงาน

    ก่อนอื่นเราต้องทำให้แน่ใจว่าไม่มีอะไรในฐานข้อมูล ด้วยการเรียกใช้คำสั่ง meteor reset เพื่อลบฐานข้อมูลของคุณและรีเซ็ทแอพใหม่ ซึ่งคุณต้องระมัดระวังการใช้คำสั่งนี้ให้มาก หากคุณกำลังพัฒนาแอพจริงๆ อยู่

    ปิดการทำงานของเซิร์ฟเวอร์ Meteor (ด้วยปุ่ม ctrl-c) และรันคำสั่งต่อไปนี้ ในคอมมานด์ไลน์

    meteor reset
    

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

    ถึงเวลารันแอพเราอีกครั้งได้แล้ว

    meteor
    

    เมื่อฐานข้อมูลว่างแล้ว ตอนนี้เราก็จะใส่โค้ดที่จะทำการโหลดข่าวสามข่าวเข้าไปในคอลเลกชั่น ในตอนที่เซิร์ฟเวอร์เริ่มทำงาน โดยกำหนดเงื่อนไขว่า ให้โหลดเมื่อคอลเลกชั่น Posts ว่างอยู่เท่านั้น

    if (Posts.find().count() === 0) {
      Posts.insert({
        title: 'Introducing Telescope',
        url: 'http://sachagreif.com/introducing-telescope/'
      });
    
      Posts.insert({
        title: 'Meteor',
        url: 'http://meteor.com'
      });
    
      Posts.insert({
        title: 'The Meteor Book',
        url: 'http://themeteorbook.com'
      });
    }
    
    server/fixtures.js

    คอมมิท 4-2

    Added data to the posts collection.

    ที่เราวางไฟล์นี้ไว้ในโฟลเดอร์ server/ ก็เพราะไม่ต้องการให้เบราว์เซอร์โหลดไปใช้ โดยโค้ดชุดนี้จะทำงานทันทีเมื่อเซิร์ฟเวอร์เริ่มทำงาน และรันคำสั่ง insert เพื่อเพิ่มข่าวทั้งสามเข้าไปที่คอลเลกชั่น Posts ในฐานข้อมูล

    ตอนนี้คุณก็รันเซิร์ฟเวอร์อีกครั้งด้วยคำสั่ง meteor ข่าวทั้งสามก็จะเข้าไปอยู่ในฐานข้อมูล

    ข้อมูลแบบไดนามิก

    ถ้าเราเปิดคอนโซลของเบราว์เซอร์ เราจะเห็นข่าวใหม่ทั้งสามถูกโหลดเข้ามาใน MiniMongo ด้วยคำสั่งนี้

     Posts.find().fetch();
    
    Browser console

    การจะเปลี่ยนข้อมูลข่าวเหล่านี้ให้เป็น HTML ได้นั้น เราจำเป็นต้องใช้ตัวช่วยเทมเพลท

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

    ด้วยการลบโค้ดส่วนของ postsData ออกไป แล้วก็แก้ไข posts_list.js ให้เป็นตามนี้

    Template.postsList.helpers({
      posts: function() {
        return Posts.find();
      }
    });
    
    client/views/posts/posts_list.js

    คอมมิท 4-3

    Wired collection into `postsList` template.

    ค้นหาแล้วดึงมาใช้

    ใน Meteor คำสั่ง find() จะคืนค่าเคอร์เซอร์ ของแหล่งข้อมูลแบบรีแอคทีฟ (reactive data source) กลับมา เมื่อเราต้องการใช้ข้อมูลนั้น ก็ใช้คำสั่ง fetch() กับเคอร์เซอร์ เพื่อแปลงมันให้เป็นอาร์เรย์อีกที

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

    แทนที่เราจะส่งข้อมูลข่าวให้ตัวช่วยเทมเพลท posts ด้วยข้อมูลนิ่งๆ จากอาร์เรย์ เราก็จะส่งค่าเคอร์เซอร์ที่ได้มาไปให้แทน (เหตุที่หน้าจอดูไม่ต่างไปจากเดิม ก็เพราะเรายังคงใช้ข้อมูลเหมือนเดิมอยู่)

    Using live data
    Using live data

    การทำงานทั้งหมดเกิดขึ้นเมื่อคอลเลกชั่นที่เซิร์ฟเวอร์ดึงข้อมูลข่าวมาจาก Mongo และส่งมันต่อให้กับคอลเลกชั่นที่ไคลเอนต์ จากนั้นตัวช่วยของ Spacebars ก็จะส่งต่อข้อมูลนี้ไปให้กับเทมเพลท บล็อกตัวช่วย {{#each}} ในเทมเพลท ก็จะทำงานซ้ำๆ เท่ากับจำนวนข่าวใน Posts และแสดงข้อมูลออกมาที่หน้าจอ

    ตอนนี้เรามาลองโพสต์ข่าวใหม่เข้าไปด้วยคอนโซลของเบราว์เซอร์ ดังนี้

     Posts.insert({
      title: 'Meteor Docs',
      author: 'Tom Coleman',
      url: 'http://docs.meteor.com'
    });
    
    Browser console

    เมื่อดูที่เบราว์เซอร์ คุณก็ควรจะเห็นแบบนี้

    Adding posts via the console
    Adding posts via the console

    สิ่งที่คุณเห็นเป็นครั้งแรกนี้ คือ การทำงานแบบรีแอคทีฟ ซึ่งเกิดจากที่เราบอกให้ Spacebars ทำงานซ้ำๆ ตามจำนวนของข้อมูลในเคอร์เซอร์ที่ได้จากคำสั่ง Posts.find() เมื่อใดก็ตามที่มีการเปลี่ยนแปลงเกิดขึ้นที่เคอร์เซอร์ตัวนี้ ให้ทำการปรับหน้า HTML ด้วยวิธีที่ง่ายที่สุด เพื่อแสดงข้อมูลที่ถูกต้องออกทางหน้าจอทันที

    มาสำรวจการเปลี่ยนแปลงของ DOM กัน

    ในกรณีนี้, วิธีที่ง่ายที่สุดที่ Spacebars จะเปลี่ยนแปลง DOM ก็คือ การเพิ่มแท็ก <div class="post">...</div> เข้าไป ถ้าคุณอยากรู้ว่าเกิดอะไรขึ้นจริงๆ ให้เปิดตัวสำรวจ DOM ที่เบราว์เซอร์ และคลิ๊กเลือกที่ <div> ของข่าวไว้ตัวนึง

    จากนั้นก็โพสต์ข่าวใหม่เพิ่มเข้าไปด้วยคอนโซลของเบราว์เซอร์ เมื่อคุณเปิดกลับไปที่แท็บของตัวสำรวจ DOM อีกครั้ง คุณจะเห็นว่ามี <div> ใหม่เกิดขึ้นตรงกับข่าวใหม่นั้น โดยข่าวตัวที่คุณคลิ๊กเลือกไว้ตอนแรกก็ยังถูกเลือกอยู่ ที่คุณเห็นอยู่นี้ก็คือ วิธีที่ Spacebars ใช้ปรับหน้า HTML ด้วยการเพิ่มแท็กเข้าไปใหม่โดยไม่ยุ่งกับแท็กเดิม

    เชื่อมต่อกับคอลเลกชั่น : การเผยแพร่และบอกรับข้อมูล

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

    เริ่มโดยเปิดโปรแกรมเทอร์มินอล และพิมพ์ :

    meteor remove autopublish
    

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

    ในท้ายที่สุดแล้ว เราควรต้องดึงแค่รายการข่าวที่ผู้ใช้ต้องการเห็นมาเท่านั้น (อย่างเช่น แสดงเฉพาะหน้าที่เลือก) แต่ในตอนนี้เราแค่กำหนดให้คอลเลกชั่น Posts ส่งค่าข้อมูลทั้งหมดที่มีมาให้ก็พอ

    ที่เราต้องทำคือ สร้างฟังก์ชัน publish() ที่จะส่งคืนค่าเคอร์เซอร์ของทุกรายการข่าวที่โพสต์ไว้กลับไป ดังนี้

    Meteor.publish('posts', function() {
      return Posts.find();
    });
    
    server/publications.js

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

    Meteor.subscribe('posts');
    
    client/main.js

    คอมมิท 4-4

    Removed `autopublish` and set up a basic publication.

    ถ้าเราดูที่เบราว์เซอร์อีกครั้ง จะเห็นว่ารายการข่าวของเรากลับมาแล้ว!

    บทสรุป

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