มาทำ Infinite Scroll จาก Firebase Firestore ใน Angular กัน + Virtual scroll

Siripra Kingchan
incubate.co.th
Published in
4 min readSep 2, 2020

--

หลายคนที่เข้ามาในบทความนี้ อาจจะประสบปัญหาในการดึงข้อมูลจาก Firebase Firestore มาแสดงผลหรือต้องการหาวิธีที่จะดึงข้อมูลจาก Firestore ออกมาใช้ใน angular เนื่องจากได้ศึกษา ทดลอง แก้ไขด้วยตัวเองมาแล้วจึงอยากจะนำวิธีมาแบ่งปันแก่ทุกคนค่า

และ Angular Material ก็มีของเล่นที่น่าสนใจคือ Virtual scroll จึงนำมาเป็นของแถมให้ทุกคนได้รู้จักและใช้กันค่า

มาเริ่มกันเลยยยยยยยย~~~~

ขั้นตอนแรก สร้างโปรเจ็ค Angular

1. ติดตั้ง the Angular CLI แบบ globally

npm install @angular/cli -g

2. สร้าง Angular Application

ng new infinite-scroll

หลังใช้คำสั่ง จะมีคำถามว่าจะเพิ่ม Angular routing หรือไม่ และใช้ style sheet แบบไหน

เมื่อใช้คำสั่ง ng new my-app

ซึ่งในโปรเจกต์ตัวอย่าง จะเพิ่ม routing และใช้ style sheet แบบ Less

3. หลัง Angular CLI สร้างโปรเจกต์เรียบร้อย ดูซิว่าใช้ได้จริงไหม?

cd my-app 
ng serve

ไปที่ http://localhost:4200/

มาแล้วววววว หน้าเว็บของโปรเจกต์ที่สร้างขึ้น

ขั้นตอนที่ 2 สร้าง Cloud Firestore 🔥

ก่อนที่จะดึงข้อมูลมา เราจะต้องมี Cloud Firestore ของตัวเองกันก่อนนะคะ😊

สร้างโปรเจกต์ใน Firebase

ไปที่ https://console.firebase.google.com เพื่อสร้างโปรเจกต์ใหม่

click เพื่อสร้างโปรเจกต์

เจอกับหน้าสร้างโปรเจกต์ กรอกชื่อที่ต้องการเลย

กรอกชื่อโปรเจกต์ที่ต้องการ

เปิดใช้ Google Analytics (เปิดหรือไม่เปิดก็ได้ค่า)

หากเปิด Google Analytics จะมีให้สร้างบัญชี

ตามตัวอย่าง เลือกเป็น Default Account for firebase
ได้โปรเจกต์มาใช้แล้วววว 😍😍

สร้าง Database ประเภท Cloud Firestore

โดยไปที่หน้า database และกดที่ สร้างฐานข้อมูล

click ที่ปุ่ม สร้างฐานข้อมูล

เลือกโหมดทดสอบ โดยเราสามารถแก้ไข Firestore rule ได้ในภายหลัง

เลือกตำแหน่งที่ตั้งตามต้องการ

ในตัวอย่างเลือก asia-east2 ที่ตั้งอยู่ในประเทศฮ่องกง

เชื่อมต่อ Angular โปรเจกต์กับ Firestore

ในการเชื่อมต่อกับ Firestore จำเป็นต้องติดตั้ง firebase และ@angular/fire เพื่อที่จะใช้ AngularFireModule และ AngularFirestoreModule โดยใช้คำสั่ง

npm i --save firebase @angular/fire

กลับไปที่ Firebase เพื่อเชื่อมโปรเจกต์ของเรากับ Firebase

ในโปรเจกต์ Angular ของเราจะเลือกประเภท เว็บ ดังรูปด้านบน
กรอกชื่อ เว็บแอป ที่ต้องการ
นำข้อมูลส่วนในกรอบไปประกาศไว้ที่ไฟล์ environment.ts
ตัวอย่าง การประกาศค่า firebase config ในไฟล์ environment

เข้าไปที่ไฟล์ app.module.ts เพื่อเรียกใช้ Firebase ใน Angular

ขั้นตอนที่ 3 สร้าง Scrollable Directive

เพื่อตรวจสอบตำแหน่งของ scrollPosition ด้วยคำสั่ง

ng g directive scrollable

เราใช้ directive เพื่อบอกว่า ตอนนี้ scrollbar อนู่ที่ตำแหน่งบนสุด หรือ ล่างสุดของหน้าเว็บ ซึ่งได้การใช้ @Output และ EventEmitter จากฟังก์ชั่นที่จากขึ้นมา

จากโค้ด ค่า top และ bottom จะถูกคำนวณจากค่าของ scrollbar ใน DOM

เรียกใช้ Directive ใน component

เรียกใช้ directive ผ่านฟังก์ชั่น scrollHandler

เรียกใช้ directive ใน tag ที่จะตรวจสอบตำแหน่งของ scrollbar

ใส่ข้อความใน div เพื่อสังเกตการทำงานของ directive
กำหนด style ให้ class ex1 ของ div ซึ่งกำหนด overflow ให้มี scroll bar ทั้งแนวตั้งและแนวนอน

ได้ scrollableDirective ที่ทำงานได้อย่างสมบูรณ์ 🎆

เมื่อ scrollbar อยู่ด้านบนจะแสดง log ว่า top อยู่ด้านล่างจะแสดง log ว่า bottom

ขั้นตอนที่ 4 สร้าง Service เพื่อใช้แสดงผลข้อมูลจาก Firestore 🔥

สร้าง Service เพื่อใช้ดึงข้อมูลจาก Firestore มาแสดงผล ด้วยคำสั่ง

ng g service pagination

สร้าง interface query เพื่อใช้ในการดึงข้อมูล

เรามาทำความรู้จักกันคร่าว ๆ กับฟังก์ชั่นต่าง ๆ ใน service กันก่อนนะคะ

  • mapAndUpdate() เมื่อมีการร้องขอข้อมูลเกิดขึ้น จะนำข้อมูลที่ได้มาไปเก็บไว้ และตรวจสอบว่าข้อมูลที่ดึงมาครบรึยัง โดยเก็บข้อมูลตัวล่าสุดไว้ที่ตัวแปร latestEntry
  • init() ใช้คำสั่งในการดึงข้อมูลจาก collection ใน Firestore โดยจะเก็บข้อมูลไว้ใน Observable ชื่อ data ซึ่งคอยรับข้อมูลชุดถัดไปผ่านคำสั่ง scan ใน RxJS โดยข้อมูลที่ถูกดึงมาใหม่จะถูกเชื่อมเข้ากับชุดข้อมูลเริ่มต้น
  • more() ฟังก์ชั่นเพื่อดึงข้อมูลในแต่ละรอบ โดยจะนำตำแหน่งล่าสุดของข้อมูลใส่ใน startAfter เพื่อดึงข้อมูลตัวถัดไปออกมา

ขั้นตอนที่ 5 สร้าง component Loading

สร้าง component Loading เพื่อแสดงผลให้แก่ผู้ใช้เห็นในระหว่างที่รอการดึงข้อมูล

ng g component loading-spinner

สำหรับการแสดงผล Loading สามารถเลือกตัว demo ได้จาก spinkit โดย copy โค้ดในส่วน html และ style ไปไว้ใน loading-spinner component

สำหรับตัวอย่าง จะใช้ loading แบบจุดสามจุด
เพิ่ม style ใน loading-spinner เพื่อเพิ่มความสวยงามและการเคลื่อนไหว

ขั้นตอนที่ 6 สร้าง infinite scroll ที่สมบูรณ์ 😎

เรียกใช้ service ใน component เพื่อดึงข้อมูลมาแสดงผล

  1. ใช้ init(path, field, opts?) เพื่อดึงข้อมูลมาแสดงผล
init(path: string, field: string, opts: {
limit: number,
reverse?: boolean,
prepend?: boolean
})
  • path — ชื่อของ collection ที่ใช้
  • field — ชื่อข้อมูลที่ใช้เรียงข้อมูล
  • limit — จำนวน doc ที่จะดึงมาในแต่ละครั้ง
  • reverse — สลับการเรียงลำดับ มากไปน้อย หรือ น้อยไปมาก
  • prepend — เพิ่ม doc ตัวที่ดึงมาใหม่ที่ด้านบนของชุดข้อมูล

2. หลังดึงข้อมูลเริ่มต้น ใช้คำสั่ง more() เพื่อดึงข้อมูลที่เหลือมา โดยเรียกใช้คำสั่งเมื่อ scrollbar อยู่ตำแหน่งล่างสุด

ดึงข้อมูล collection cats ใน firestore มาแสดงผล โดยเรียงลำดับตาม name

service จะมี Observables 3 ตัว ที่เราจะนำมาใช้ใน HTML

  • data - Array ของข้อมูลที่ดึงมาจาก Firestore
  • loading - จะเป็น true เมื่อกำลังดึงข้อมูลจาก Firestore
  • done - จะเป็น true เมื่อข้อมูลถูกดึงออกมาครบแล้ว

ตามโค้ดด้านล่างในส่วนของ app.component.html หากข้อมูลยังโหลดไม่เสร็จ จะแสดง app-loading-spinner หากโหลดเสร็จจึงจะแสดงผลข้อมูลที่ดึงมาได้

ตัวอย่าง infinite scroll โดยเพิ่มข้อมูลที่ด้านล่าง

สำเร็จแล้ววววววว!!! มากันที่โบนัส

Virtual scroll คือ…..

การแสดงผลเฉพาะรายการข้อมูลส่วนพอดีกับขนาดหน้าจอที่ผู้ใช้เห็น เนื่องจากการโหลดข้อมูลมาครั้งละจำนวนมากหลายร้อยข้อมูล จะส่งผลให้ browser ทำงานช้า

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

หากต้องการศึกษารายละเอียดเพิ่มเติม สามารถอ่านได้ที่

มาเริ่มใช้ Virtual scroll กันเลย!!

ติดตั้ง @angular/cdk เพื่อใช้งาน Angular CDK scrolling

npm install @angular/cdk --save

เรียกใช้ CdkScrollableModule และ ScrollingModule ใน app.module.ts

สำเร็จแล้วววว การแสดงข้อมูลผ่าน virtual scroll แบบ infinite scroll

สำเร็จไปเรียบร้อยกับการแสดงผลที่หนึ่งวิธีผ่าน Virtual scroll ซึ่งจะทำให้หน้าเว็บของเรานั้นแสดงผลได้เร็วยิ่งขึ้น

แต่เท่านี้ยังไม่พอ!!! Service เมื่อเราสร้างครั้งแรกจะเป็นแบบ Singleton (Service ที่ได้จะเป็น Instance ตัวเดิม) ซึ่งหากเราต้องการเรียกใช้หลาย ๆ Component และไม่มีปัญหาเรื่อง Instance จะต้องประกาศเป็น Factory providers ด้วยวิธีต่อไปนี้…

สร้าง factory function

เรียกใช้ CatListServiceProvider ใน app.component.ts

ำเร็จแล้ววววว🎆🎆 หากจะเรียกใช้ Service นี้ใน Component อื่น สามารถสร้าง Factory Function ใหม่ และเพิ่ม Provider ตัวที่สร้างขึ้นมา ใน Component ที่เรียกใช้งาน ตามตัวอย่างข้างบนได้เลยค่า👍

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

🔅🔅🔅หมายเหตุ🔅🔅🔅

✔หากใส่ providedInroot ใน Service แต่ยังเรียกใช้ Factory Provider แยกแต่ละ component จะได้ Service ที่เป็น FACTORY
❗❗ แต่ถ้าลบ providedInroot ออก และไม่เรียกใช้ Factory Provider จะได้ Service ที่เป็น SINGLETON

//code ส่วน providedIn root ใน Service
@Injectable({
providedIn: ‘root’,
})

💖source code :

--

--

Siripra Kingchan
incubate.co.th

กำลังศึกษาปริญญาโท และทำวิจัยเกี่ยวกับ AI ด้าน image processing