บทช่วยสอน Angular 6: คุณสมบัติใหม่พร้อมพลังใหม่

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

Angular 6 ออกแล้ว! การเปลี่ยนแปลงที่โดดเด่นที่สุดคือ CLI และวิธีการฉีดบริการ หากคุณต้องการเขียนแอป Angular 6 แอปแรกหรือแอป Angular/Firebase ในบทช่วยสอนนี้ เราจะพูดถึงขั้นตอนพื้นฐานของการตั้งค่าเริ่มต้นและสร้างแอปไดอารี่ขนาดเล็ก

Angular 6: พื้นฐาน

หากคุณไม่เคยใช้ Angular มาก่อน ให้ฉันอธิบายสั้น ๆ เกี่ยวกับมันและวิธีการทำงาน

Angular เป็นเฟรมเวิร์ก JavaScript ที่ออกแบบมาเพื่อรองรับการสร้างแอปพลิเคชันหน้าเดียว (SPA) สำหรับทั้งเดสก์ท็อปและมือถือ

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

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

Angular ใช้ TypeScript ซึ่งเป็น superset แบบพิมพ์ของ JS และจะทำให้บางสิ่งง่ายขึ้น โดยเฉพาะอย่างยิ่งหากคุณมาจากพื้นหลังของภาษาที่พิมพ์

Angular 6: คุณสมบัติใหม่

สรุปโดยย่อของคุณสมบัติใหม่ใน Angular 6:

  • นโยบายการซิงโครไนซ์หมายเลขเวอร์ชันหลักสำหรับแพ็คเกจเฟรมเวิร์ก ( @angular/core , @angular/common , @angular/compiler ฯลฯ ), CLI, Material และ CDK สิ่งนี้จะช่วยทำให้ความเข้ากันได้ระหว่างกันชัดเจนขึ้นในอนาคต: คุณสามารถบอกได้จากภาพรวมอย่างรวดเร็วที่หมายเลขเวอร์ชันว่าแพ็คเกจหลักสามารถทำงานร่วมกันได้หรือไม่
  • คำสั่ง ng CLI ใหม่:
    • ng update เพื่ออัปเกรดเวอร์ชันแพ็คเกจอย่างชาญฉลาด อัปเดตเวอร์ชันการพึ่งพาและซิงค์ให้ตรงกัน (เช่นเมื่อรัน ng update @angular/core กรอบงานทั้งหมดจะได้รับการอัปเดตเช่นเดียวกับ RxJS) นอกจากนี้ยังจะเรียกใช้ แผนผังด้วย หากแพ็คเกจรวมไว้ (หากเวอร์ชันที่ใหม่กว่ารวมถึงการเปลี่ยนแปลงที่ขาดซึ่งจำเป็นต้องมีการเปลี่ยนแปลงในโค้ด แผนผังจะอัปเดตโค้ดของคุณให้กับคุณ)
    • ng add เพื่อเพิ่มแพ็คเกจใหม่ (และเรียกใช้สคริปต์ หากมี)
  • ขณะนี้บริการอ้างอิงโมดูลที่จะจัดหาให้ แทนที่จะอ้างอิงโมดูลที่อ้างอิงถึงบริการ ตามที่เคยมี

ตัวอย่างเช่น ความหมายของการเปลี่ยนแปลงครั้งล่าสุดนี้ โดยที่โค้ดของคุณเคยมีลักษณะดังนี้:

 @NgModule({ // ... providers: [MyService] })

…ด้วยการเปลี่ยนแปลงเฉพาะใน Angular 6 จะมีลักษณะดังนี้:

 @Injectabe({ providedIn: 'root', })

สิ่งเหล่านี้เรียกว่า ผู้ให้บริการ tree-shakeable และอนุญาตให้คอมไพเลอร์ลบบริการที่ไม่อ้างอิงซึ่งส่งผลให้มีบันเดิลขนาดเล็กลง

เชิงมุม 6 CLI

อินเทอร์เฟซบรรทัดคำสั่ง ng เป็นส่วนสำคัญของ Angular และช่วยให้คุณเคลื่อนที่เร็วขึ้นเมื่อเขียนโค้ดแอปของคุณ

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

การสร้างโปรเจ็กต์ Angular 6

โอเค คุยกันพอแล้ว มาทำให้มือของเราสกปรกและเริ่มเขียนโค้ดกันเถอะ

ในการเริ่มต้น คุณจะต้องติดตั้ง Node.js และ npm ในเครื่องของคุณ

ตอนนี้ ไปข้างหน้าและติดตั้ง CLI:

 npm install -g @angular/cli

สิ่งนี้จะติดตั้งคำสั่ง ng CLI ทั่วโลก เนื่องจากสวิตช์ -g

เมื่อเราได้สิ่งนั้นแล้ว เราจะได้โครงเริ่มต้นสำหรับแอปของเราด้วย ng new :

 ng new my-memories --style=scss

สิ่งนี้จะสร้างโฟลเดอร์ my-memories สร้างไฟล์ที่จำเป็นทั้งหมดเพื่อให้การตั้งค่าเริ่มต้นของคุณพร้อมที่จะเริ่มต้น และติดตั้งแพ็คเกจที่จำเป็นทั้งหมด --style=scss เป็นทางเลือก และจะตั้งค่าคอมไพเลอร์เพื่อคอมไพล์ไฟล์ SCSS เป็น CSS ซึ่งเราต้องการในภายหลัง

เมื่อการติดตั้งเสร็จสมบูรณ์ คุณสามารถ cd my-memories และเรียกใช้ ng serve การดำเนินการนี้จะเริ่มต้นกระบวนการสร้างและเว็บเซิร์ฟเวอร์ในเครื่องที่ให้บริการแอปของคุณที่ http://localhost:4200

แอพ Angular 6 ทันทีหลังจากนั่งร้าน

สิ่งที่เกิดขึ้นเบื้องหลังคือ CLI ทรานสไพล์ .ts (ไฟล์ TypeScript) ทั้งหมดไปยัง vanilla JS รวบรวมการพึ่งพาที่จำเป็นทั้งหมดจากโฟลเดอร์แพ็คเกจ node_modules และส่งออกผลลัพธ์เป็นชุดของไฟล์ที่ให้บริการผ่านเว็บเซิร์ฟเวอร์ในเครื่อง ที่ทำงานบนพอร์ต 4200

ไฟล์โครงการ

หากคุณไม่คุ้นเคยกับโครงสร้างโฟลเดอร์โปรเจ็กต์ของ Angular สิ่งสำคัญที่สุดที่คุณจำเป็นต้องรู้คือโค้ดทั้งหมดที่เกี่ยวข้องกับแอปจะอยู่ภายในโฟลเดอร์ src โดยปกติ คุณจะสร้างโมดูลและคำสั่งทั้งหมดในโฟลเดอร์นั้นตามสถาปัตยกรรมของแอป (เช่น ผู้ใช้ รถเข็น สินค้า)

โครงสร้างโฟลเดอร์โปรเจ็กต์ Angular 6

ติดตั้งเบื้องต้น

เอาล่ะ จนถึงตอนนี้ เรามีการตั้งค่าเริ่มต้นสำหรับแอปของเราแล้ว มาเริ่มทำการเปลี่ยนแปลงกัน

ก่อนที่เราจะเริ่มต้น เรามาเจาะลึกลงไปในโฟลเดอร์ src กันก่อน หน้าแรกคือ index.html :

 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>MyMemories</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> </body> </html>

ที่นี่เราเห็น HTML พื้นฐานและแท็ก <app-root> นี่คือองค์ประกอบเชิงมุม และโดยที่ Angular 6 แทรกโค้ดส่วนประกอบของเรา

เราจะพบไฟล์ app/app.component.ts ซึ่งมีตัวเลือก app-root เพื่อให้ตรงกับสิ่งที่อยู่ในไฟล์ index.html

องค์ประกอบเป็นคลาส TypeScript ที่ตกแต่งแล้ว และในกรณีนี้ มีคุณสมบัติ title มัณฑนากร @Component บอกให้ Angular รวมพฤติกรรมขององค์ประกอบในคลาส นอกจากตัวเลือกแล้ว ยังระบุไฟล์ HTML ที่จะแสดงผลและสไตล์ชีตที่จะใช้

 import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'app'; }

หากเราดูที่ app.component.html เราจะเห็นการเชื่อมโยงการแก้ไข {{title}} นี่คือที่มาของการรวมเวทย์มนตร์ทั้งหมดและ Angular จะแสดงค่าของคุณสมบัติชื่อคลาสและอัปเดตทุกครั้งที่มีการเปลี่ยนแปลง

 <!--The content below is only a placeholder and can be replaced.--> <div> <h1> Welcome to {{ title }}! </h1> <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="> </div> <h2>Here are some links to help you start: </h2> <ul> <li> <h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2> </li> </ul>

ไปข้างหน้าและอัปเดต title จากชั้นเรียนเป็น 'My Memories!' .

 ... export class AppComponent { title = 'My Memories!'; } ...

เราจะเห็นกระบวนการคอมไพเลอร์ในการเปลี่ยนแปลงและการรีเฟรชเบราว์เซอร์เพื่อแสดงชื่อที่อัปเดตของเรา

ซึ่งหมายความว่าการ ng serve ของ Angular 6 จะคอยดูการเปลี่ยนแปลงไฟล์ของเราและแสดงผลทุกครั้งที่มีการเปลี่ยนแปลงในไฟล์ใดๆ

เพื่อให้การเข้ารหัสเป็นมิตรมากขึ้นและหลีกเลี่ยงการรีเฟรชหน้าเต็มทุกครั้งที่เราทำการเปลี่ยนแปลง เราสามารถใช้ประโยชน์จาก webpack Hot Module Replacement (HMR) ซึ่งเพิ่งอัปเดตส่วน JS/CSS ที่เปลี่ยนแทนที่จะสร้างการรีเฟรชแบบเต็มเป็น แสดงการเปลี่ยนแปลงของคุณ

การกำหนดค่า HMR

อันดับแรก เราต้องตั้งค่าสภาพแวดล้อม

สร้างไฟล์ src/environments/environment.hmr.ts ด้วยเนื้อหาต่อไปนี้:

 export const environment = { production: false, hmr: true };

อัปเดต src/environments/environment.prod.ts และเพิ่ม hmr: false flag ให้กับสภาพแวดล้อม:

 export const environment = { production: true, hmr: false };

จากนั้นอัปเดต src/environments/environment.ts และเพิ่ม hmr: false flag ให้กับสภาพแวดล้อมที่นั่นด้วย:

 export const environment = { production: false, hmr: false };

ถัดไปในไฟล์ angular.json ให้อัปเดตส่วนนี้:

 "projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements":[ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.hmr.ts" } ] }, // ...

และภายใต้ projects ต์ → my-memoriesarchitectserveconfigurations :

 "projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...

ตอนนี้อัปเดต tsconfig.app.json เพื่อรวม types ที่จำเป็น (เช่น type) โดยเพิ่มสิ่งนี้ภายใต้ compilerOptions :

 "compilerOptions": { // ... "types": [ "node" ]

ต่อไป เราจะติดตั้งโมดูล @angularclass/hmr เป็นการพึ่งพาการพัฒนา:

 npm install --save-dev @angularclass/hmr

จากนั้นกำหนดค่าโดยสร้างไฟล์ src/hmr.ts :

 import { NgModuleRef, ApplicationRef } from '@angular/core'; import { createNewHosts } from '@angularclass/hmr'; export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => { let ngModule: NgModuleRef<any>; module.hot.accept(); bootstrap().then(mod => ngModule = mod); module.hot.dispose(() => { const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); const elements = appRef.components.map(c => c.location.nativeElement); const makeVisible = createNewHosts(elements); ngModule.destroy(); makeVisible(); }); };

ถัดไป ให้อัปเดต src/main.ts เพื่อใช้ฟังก์ชันข้างต้น:

 import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import { hmrBootstrap } from './hmr'; if (environment.production) { enableProdMode(); } const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule); if (environment.hmr) { if (module[ 'hot' ]) { hmrBootstrap(module, bootstrap); } else { console.error('HMR is not enabled for webpack-dev-server!'); console.log('Are you using the --hmr flag for ng serve?'); } } else { bootstrap().catch(err => console.log(err)); }

สิ่งที่เราทำที่นี่คือการทำให้ bootstrap เรียกใช้ฟังก์ชันที่ไม่ระบุตัวตน และถามต่อไปว่าแฟล็ก environment.hmr นั้นจริงหรือไม่ หากเป็นเช่นนั้น เราจะเรียกฟังก์ชันที่กำหนดไว้ก่อนหน้านี้จาก hmr.ts ซึ่งเปิดใช้งานการเปลี่ยนโมดูลแบบลัด มิฉะนั้นเราจะบูตสแตรปเหมือนที่เคยทำ

ตอนนี้ เมื่อเราเรียก ng serve --hmr --configuration=hmr เราจะเรียกใช้การกำหนดค่า hmr และเมื่อเราทำการเปลี่ยนแปลงไฟล์ เราจะได้รับการอัปเดตโดยไม่ต้องรีเฟรชแบบเต็ม สิ่งแรก --hmr ใช้สำหรับ webpack และ --configuration=hmr สำหรับ Angular เพื่อใช้สภาพแวดล้อม hmr

เว็บแอปโปรเกรสซีฟ (PWA)

ในการเพิ่มการรองรับ Angular 6 PWA และเปิดใช้งานการโหลดออฟไลน์สำหรับแอป เราสามารถใช้หนึ่งในคำสั่ง CLI ใหม่ ng add :

 ng add @angular/[email protected]

โปรดทราบว่าฉันกำลังเพิ่มเวอร์ชัน เนื่องจากเวอร์ชันล่าสุดในขณะที่เขียนบทช่วยสอนนี้เกิดข้อผิดพลาด (คุณสามารถลองโดยไม่ใช้และตรวจสอบว่าเหมาะกับคุณหรือไม่โดยใช้เพียง ng add @angular/pwa )

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

  • การอ้างอิงถึง manifest.json ในไฟล์ angular.json เพื่อให้รวมอยู่ในเอาต์พุตบิลด์ เช่นเดียวกับ "serviceWorker": true ในบิลด์ที่ใช้งานจริง
  • ไฟล์ ngsw-config.json ที่มีการตั้งค่าเริ่มต้นเพื่อแคชไฟล์ทั้งหมดที่จำเป็นสำหรับการเรียกใช้แอป
  • เมตาแท็ก manifest.json ในไฟล์ index.html
  • ไฟล์ manifest.json เอง โดยมีการกำหนดค่าพื้นฐานสำหรับแอป
  • พนักงานบริการโหลดในโมดูลแอป ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) (โปรดทราบว่าพนักงานบริการจะเปิดใช้งานในสภาพแวดล้อมที่ใช้งานจริงเท่านั้น)

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

การเพิ่มไลบรารี Material Angular 6 UI

จนถึงตอนนี้ เรามีการตั้งค่าเริ่มต้น และเราพร้อมที่จะเริ่มสร้างแอปของเรา เพื่อใช้ประโยชน์จากส่วนประกอบที่สร้างไว้แล้ว เราสามารถใช้ Material เวอร์ชัน Angular 6 ได้

ในการติดตั้งแพ็คเกจ material ในแอปของเรา เราจะใช้ ng add อีกครั้ง:

 ng add @angular/material

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

  • index.html รวมแบบอักษร Roboto และไอคอนวัสดุ
  • BrowserAnimationsModule ถูกเพิ่มใน AppModule ของเรา
  • angular.json มีธีม indigo-pink รวมอยู่ด้วยแล้วสำหรับเรา

ระบุตัวเลือกธีม Angular 6 ที่สร้างไว้ล่วงหน้าของคุณ

คุณจะต้องเริ่ม ng serve ใหม่เพื่อรับธีมหรือคุณสามารถเลือกธีมอื่นที่สร้างไว้ล่วงหน้าได้

ที่เกี่ยวข้อง: สร้างเว็บแอปล้ำสมัยด้วยวัสดุเชิงมุม

เค้าโครงพื้นฐาน

เพื่อให้มีเลย์เอาต์ sidenav เริ่มต้น เราจะใช้แผนผังที่มาพร้อมกับ Material แต่ไม่เป็นไร ถ้าคุณต้องการใช้เลย์เอาต์อื่น

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

 ng generate @angular/material:material-nav --name=my-nav

สิ่งนี้จะสร้างส่วนประกอบ sidenav พร้อมการตั้งค่าขั้นต่ำที่พร้อมเริ่มต้น ไม่ดีเหรอ?

มันยังรวมโมดูลที่จำเป็นทั้งหมดใน app.module.ts ของเราด้วย

องค์ประกอบ "my-nav" Angular 6 ที่สร้างขึ้นใหม่

เนื่องจากเราใช้ SCSS เราจึงต้องเปลี่ยนชื่อไฟล์ my- my-nav.component.css เป็น my-nav.component.scss และใน my-nav.component.ts ให้อัปเดต styleUrls อ้างอิงที่เกี่ยวข้องเพื่อใช้ชื่อใหม่

ตอนนี้เพื่อใช้ประโยชน์จากองค์ประกอบใหม่ ไปที่ app.component.html และลบรหัสเริ่มต้นทั้งหมด เหลือเพียง:

 <app-my-nav></app-my-nav>

เมื่อเรากลับไปที่เบราว์เซอร์ นี่คือสิ่งที่เราจะเห็น:

เลย์เอาต์สี่บานหน้าต่างพร้อมเมนูที่มุมบนซ้าย ความทรงจำของฉันอยู่ข้างๆ และลิงก์ตัวเลขสามลิงก์ภายใต้เมนู บานหน้าต่างที่สี่ว่างเปล่า

มาอัปเดตลิงก์ให้มีเพียงสองตัวเลือกที่เราต้องการ

ขั้นแรก มาสร้างส่วนประกอบใหม่สองส่วน:

 ng gc AddMemory ng generate @angular/material:material-table --name=view-memories

(อันที่สองคือแผนผังวัสดุที่ใช้สร้างตาราง)

ต่อไป ใน my-nav เราจะอัปเดตเพื่อตั้งค่าลิงก์และรวม <router-outlet> เพื่อแสดงองค์ประกอบเนื้อหาของเรา:

 <mat-sidenav-container class="sidenav-container"> <mat-sidenav #drawer class="sidenav" fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'" [mode]="(isHandset$ | async) ? 'over' : 'side'" [opened]="!(isHandset$ | async)"> <mat-toolbar color="primary">Menu</mat-toolbar> <mat-nav-list> <a mat-list-item [routerLink]="['/add-memory']">Add Memory</a> <a mat-list-item [routerLink]="['/view-memories']">View My Memories</a> </mat-nav-list> </mat-sidenav> <mat-sidenav-content> <mat-toolbar color="primary"> <button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()" *ngIf="isHandset$ | async"> <mat-icon aria-label="Side nav toggle icon">menu</mat-icon> </button> <span>my-memories</span> </mat-toolbar> <router-outlet></router-outlet> </mat-sidenav-content> </mat-sidenav-container>

นอกจากนี้ ใน app.component.html เราจำเป็นต้องอัปเดตเพื่อให้มี <router-outlet> หลัก (เช่น remove <my-nav> ):

 <router-outlet></router-outlet>

ถัดไป ใน AppModule เราจะรวมเส้นทาง:

 import { RouterModule, Routes } from '@angular/router'; // ... imports: [ // ... RouterModule.forRoot([ { path: '', component: MyNavComponent, children: [ { path: 'add-memory', component: AddMemoryComponent }, { path: 'view-memories', component: ViewMemoriesComponent } ] }, ]), ]

โปรดทราบว่าเรากำลังตั้งค่า MyNavComponent เป็นพาเรนต์และสององค์ประกอบที่เราสร้างเป็นเด็ก นี่เป็นเพราะเราได้รวม <router-outlet> ไว้ใน MyNavComponent และเมื่อใดก็ตามที่เราพบหนึ่งในสองเส้นทางนั้น เราจะแสดงองค์ประกอบย่อยที่วาง <router-outlet>

หลังจากนี้ เมื่อเราให้บริการแอป เราควรเห็น:

ลิงก์ทางซ้ายมือถูกแทนที่ด้วย Add Memory และ View My Memories โดยเลือกอันหลัง บานหน้าต่างว่างตอนนี้มีตารางที่มีหมายเลขประจำตัวและชื่อ

สร้างแอพ (ไดอารี่ความทรงจำ)

เอาล่ะ เรามาสร้างแบบฟอร์มบันทึกความทรงจำใหม่ๆ ลงในไดอารี่กันเถอะ

เราจะต้องนำเข้าโมดูลวัสดุและโมดูลแบบฟอร์มไปยัง app.module.ts ของเรา:

 import { FormsModule } from '@angular/forms'; import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material'; // ... Imports:[ // ... MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, FormsModule, MatNativeDateModule, // ... ]

จากนั้นใน add-memory.component.html เราจะเพิ่มแบบฟอร์ม:

 <form #form="ngForm" (ngSubmit)="onSubmit()"> <mat-card class="memory-card"> <mat-card-title> Add a memory </mat-card-title> <mat-card-content> <mat-form-field> <input disabled matInput placeholder="Select the date..." [(ngModel)]="memory.date" name="date" [matDatepicker]="date"> <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle> <mat-datepicker disabled="false" #date></mat-datepicker> </mat-form-field> <mat-form-field> <textarea placeholder="Enter your memory..." rows="3" maxlength="300" matInput [(ngModel)]="memory.text" name="memory"></textarea> </mat-form-field> </mat-card-content> <mat-card-actions> <button mat-button type="submit">Save me!</button> </mat-card-actions> </mat-card> </form> <pre> {{ memory | json }} </pre>

ที่นี่เราใช้ mat-card และเพิ่มสองช่อง date และ textarea

โปรดทราบว่าเรากำลังใช้ [(ngModel)] คำสั่งเชิงมุมนี้จะผูกนิพจน์ memory.date และคุณสมบัติ memory ในคลาสเข้าด้วยกัน ดังที่เราจะเห็นในภายหลัง ( [(ngModel)] คือ syntax sugar—ชอร์ตคัทเพื่อดำเนินการเชื่อมโยงข้อมูลแบบสองทางจากคลาสไปยังมุมมองและจากมุมมองไปยังคลาส ซึ่งหมายความว่าเมื่อคุณป้อนข้อความในมุมมอง memory.date จะสะท้อนถึงการเปลี่ยนแปลงเหล่านั้น ในอินสแตนซ์ของคลาส และหากคุณทำการเปลี่ยนแปลง memory.date ในอินสแตนซ์ของคลาส มุมมองจะสะท้อนถึงการเปลี่ยนแปลง)

ใน add-memory.component.ts โค้ดจะมีลักษณะดังนี้:

 import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-add-memory', templateUrl: './add-memory.component.html', styleUrls: ['./add-memory.component.scss'] }) export class AddMemoryComponent implements OnInit { memory: any = {}; constructor() { } ngOnInit() { } onSubmit() { console.log(this.memory); } }

ที่นี่ เรากำลังเริ่มต้นคุณสมบัติ memory ที่ผูกไว้ผ่าน ngModel เมื่อคอมโพเนนต์ AddMemoryComponent ได้รับการสร้างอินสแตนซ์ memory จะเป็นอ็อบเจ็กต์ว่าง จากนั้นเมื่อคำสั่ง ngModel ทำงาน จะสามารถกำหนดค่าอินพุตให้กับ memory.date และ memory.text หากเราไม่ทำเช่นนี้ เราจะได้รับข้อผิดพลาด Cannot set property 'date/text' of undefined

ในขณะเดียวกัน add-memory.component.scss จำเป็นต้องมี:

 .memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto; } .mat-form-field { width: 100%; }

เนื่องจากเรามี <pre> {{ memory | json }} </pre> <pre> {{ memory | json }} </pre> เราจะเห็นสถานะปัจจุบันของ memory ในมุมมอง ถ้าเราไปที่เบราว์เซอร์ ผลลัพธ์ที่ได้คือ:

ต้นแบบแอปไดอารี่ "my-memories" แสดงการแทนค่าภายในของการป้อนข้อมูลของผู้ใช้ (วันที่และข้อความ)

ในมุมมอง เราผูกแบบฟอร์มผ่าน (ngSubmit)="onSubmit()" กับฟังก์ชัน onSubmit ในคลาส

 onSubmit() { console.log(this.memory); }

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

การแทนค่าภายในของอินพุตของผู้ใช้ในบันทึกคอนโซล

บทช่วยสอนเชิงมุม 6: การเชื่อมต่อกับ Firebase

สิ่งที่เราจะทำต่อไปคือเชื่อมต่อโปรเจ็กต์ของเรากับ Firebase เพื่อบันทึกความทรงจำของเรา

อันดับแรก เราจะไปที่คอนโซล Firebase และสร้างโครงการที่นั่น

การเพิ่มโปรเจ็กต์ Firebase

ประการที่สอง เราจะติดตั้งแพ็คเกจ firebase และ angularfire2 :

 npm install firebase angularfire2 --save

จากนั้นในแต่ละไฟล์ทั้งสามนี้:

  1. /src/environments/environment.ts
  2. /src/environments/environment.hmr.ts
  3. /src/environments/environment.prod.ts

…เราจะเพิ่มการกำหนดค่า Firebase ของเรา:

 export const environment = { // ... firebase: { apiKey: '<your-key>', authDomain: '<your-project-authdomain>', databaseURL: '<your-database-URL>', projectId: '<your-project-id>', storageBucket: '<your-storage-bucket>', messagingSenderId: '<your-messaging-sender-id>' } };

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

หลังจากนั้น เราจะรวมโมดูล Firebase ไว้ใน app.module.ts ของเรา:

 import { AngularFireModule } from 'angularfire2'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { environment } from '../environments/environment'; // ... Imports:[ // ... AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ... ]

และใน add-memory.component.ts เราแทรกฐานข้อมูลในตัวสร้างและบันทึกค่าจากแบบฟอร์มไปยังฐานข้อมูล เมื่อการผลักดันสัญญาจาก Firebase สำเร็จ เราจะบันทึกความสำเร็จในคอนโซลและรีเซ็ตโมเดล:

 import { AngularFireDatabase } from 'angularfire2/database'; // ... constructor(private db: AngularFireDatabase) { } // ... onSubmit() { this.memory.date = new Date(this.memory.date).valueOf(); this.db.list('memories').push(this.memory) .then(_ => { this.memory = {} console.log('success') }) } 

อนุญาตให้อ่านและเขียนฐานข้อมูล Firebase ของคุณ

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

นอกจากนี้ หากต้องการรับการเปลี่ยนแปลงสภาพแวดล้อม คุณจะต้องเริ่มกระบวนการ ng serve ใหม่

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

เพิ่มหน่วยความจำทดสอบลงในฐานข้อมูล Firebase ของแอปไดอารี่แล้ว

มาดูกันว่าเราจะสามารถดึงความทรงจำของเราและแสดงในตารางวัสดุได้อย่างไร

ย้อนกลับไปเมื่อเราสร้างตารางโดยใช้ ng generate @angular/material:material-table --name=view-memories', we automatically got a file view-memories/view-memories-datasource.ts` โดยอัตโนมัติ ไฟล์นี้มีข้อมูลปลอม เราจึงต้องเปลี่ยนเพื่อเริ่มดึงข้อมูลจาก Firebase

ใน view-memories-datasource.ts เราจะลบ EXAMPLE_DATA และตั้งค่าอาร์เรย์ว่าง:

 export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem[] = []; // ...

และใน getSortedData เราจะอัปเดตชื่อฟิลด์:

 private getSortedData(data: ViewMemoriesItem[]) { if (!this.sort.active || this.sort.direction === '') { return data; } return data.sort((a, b) => { const isAsc = this.sort.direction === 'asc'; switch (this.sort.active) { case 'text': return compare(a.name, b.name, isAsc); case 'date': return compare(+a.id, +b.id, isAsc); default: return 0; } }); }

ใน view-memories.component.html เราจะอัปเดตชื่อคอลัมน์เป็น date และ text จากโมเดลหน่วยความจำของเรา โปรดทราบว่าเนื่องจากเราบันทึกวันที่ในรูปแบบมิลลิวินาที ที่นี่เราใช้ท่อวันที่เพื่อแปลงค่าสำหรับการแสดงในรูปแบบวันที่ที่เป็นมิตรต่อมนุษย์มากขึ้น สุดท้ายนี้ เรากำลังลบ [length]="dataSource.data.length" ออกจากตัวแบ่งหน้า เนื่องจากเราจะโหลดข้อมูลแบบอะซิงโครนัสจาก Firebase:

 <div class="mat-elevation-z8"> <table mat-table #table [dataSource]="dataSource" matSort aria-label="Elements"> <!-- Id Column --> <ng-container matColumnDef="date"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Date</th> <td mat-cell *matCellDef="let row">{{row.date | date:'short'}}</td> </ng-container> <!-- Name Column --> <ng-container matColumnDef="text"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Text</th> <td mat-cell *matCellDef="let row">{{row.text}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator #paginator [pageIndex]="0" [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]"> </mat-paginator> </div>

เปลี่ยน view-memories.component.css เป็น view-memories.component.scss และตั้งค่าสไตล์ตาราง:

 table{ width: 100%; }

ใน view-memories.component.ts เราจะเปลี่ยน styleUrls เพื่อสะท้อนการเปลี่ยนชื่อด้านบนเป็น . ./view-memories.component.scss นอกจากนี้ เราจะอัปเด displayedColumns อาร์เรย์ displayColumns ให้เป็น ['date', 'text'] และตั้งค่าแหล่งข้อมูลตารางเพื่อรับข้อมูลจาก Firebase

สิ่งที่เกิดขึ้นที่นี่คือ เรากำลังสมัครรับรายการความทรงจำ และเมื่อเราได้รับข้อมูล เราจะสร้างอินสแตนซ์ ViewMemoriesDataSource และตั้งค่าคุณสมบัติข้อมูลด้วยข้อมูลจาก Firebase

 this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; });

Firebase ส่งคืนอาร์เรย์ Observable สไตล์ ReactiveX

โปรดทราบว่าเรากำลัง this.db.list<ViewMemoriesItem>('memories') —ค่าที่ดึงมาจากพาธ 'memories' ไปยัง ViewMemoriesItem สิ่งนี้ได้รับการดูแลโดยห้องสมุด angularfire2

เรายังรวมการเรียก unsubscribe ไว้ภายในเบ็ด onDestroy ของวงจรชีวิตองค์ประกอบเชิงมุมด้วย

 import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { MatPaginator, MatSort } from '@angular/material'; import { ViewMemoriesDataSource, ViewMemoriesItem } from './view-memories-datasource'; import { AngularFireDatabase } from 'angularfire2/database'; import { Subscription } from 'rxjs'; import { map, first } from 'rxjs/operators'; @Component({ selector: 'app-view-memories', templateUrl: './view-memories.component.html', styleUrls: ['./view-memories.component.scss'] }) export class ViewMemoriesComponent implements OnInit, OnDestroy{ @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; dataSource: ViewMemoriesDataSource; /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = ['date', 'text']; subscription: Subscription; constructor(private db: AngularFireDatabase) { } ngOnInit() { this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; }); } ngOnDestroy(): void { this.subscription.unsubscribe(); } }
ที่เกี่ยวข้อง: การ สร้างแอปพลิเคชันมือถือหลายแพลตฟอร์มแบบเรียลไทม์: ตัวอย่างการใช้ Ionic Framework และ Firebase

การปรับใช้กับโฮสติ้งของ Firebase

ในการทำให้แอปของเราใช้งานได้ มาปรับใช้กับ Firebase Hosting กัน สำหรับสิ่งนั้น เราจะติดตั้ง Firebase CLI ซึ่งจะทำให้คำสั่ง firebase ใช้งานได้:

 npm install -g firebase-tools

ตอนนี้เราสามารถใช้ Firebase CLI เพื่อเข้าสู่ระบบ:

 firebase login

การดำเนินการนี้จะแจ้งให้คุณเลือกบัญชี Google ของคุณ

ต่อไป เราจะเริ่มต้นโครงการและกำหนดค่าโฮสติ้งของ Firebase:

 firebase init

เราจะเลือกตัวเลือกการโฮสต์

ต่อไป เมื่อถูกถามถึงเส้นทาง เราจะตั้งค่าเป็น dist/my-memories เมื่อเราถูกถามว่าต้องกำหนดค่าให้เป็นแอปหน้าเดียวหรือไม่ (เช่น เขียน URL ใหม่ทั้งหมดไปที่ /index.html ) เราจะตอบว่า "ใช่"

สุดท้าย เราจะตี “ไฟล์ dist/my-memories/index.html มีอยู่แล้ว เขียนทับ?” ที่นี่เราจะพูดว่า "ไม่"

สิ่งนี้จะสร้างไฟล์กำหนดค่า Firebase .firebaserc และ firebase.json ด้วยการกำหนดค่าที่ให้มา

ขั้นตอนสุดท้ายคือการเรียกใช้:

 ng build --prod firebase deploy

และด้วยเหตุนี้ เราจะเผยแพร่แอปไปยัง Firebase ซึ่งมี URL ให้เรานำทางไป เช่น https://my-memories-b4c52.firebaseapp.com/view-memories ซึ่งคุณสามารถดูที่เผยแพร่ของฉัน การสาธิต.


ว้าว คุณผ่านบทช่วยสอนแล้ว! ฉันหวังว่าคุณจะสนุกกับมัน คุณสามารถตรวจสอบรหัสเต็มได้ที่ GitHub

หนึ่งขั้นในเวลา

Angular เป็นเฟรมเวิร์กที่ทรงพลังมากสำหรับการสร้างเว็บแอป เผยแพร่มานานแล้วและได้พิสูจน์ตัวเองแล้วสำหรับแอปขนาดเล็ก เรียบง่าย และแอปขนาดใหญ่และซับซ้อน—Angular 6 ก็ไม่มีข้อยกเว้นในที่นี้

นับจากนี้เป็นต้นไป Angular วางแผนที่จะปรับปรุงและปฏิบัติตามกระบวนทัศน์ของเว็บใหม่ๆ เช่น ส่วนประกอบของเว็บ (Angular Elements) หากคุณสนใจที่จะสร้างแอปไฮบริด คุณสามารถตรวจสอบ Ionic ซึ่งใช้ Angular เป็นเฟรมเวิร์กพื้นฐาน

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

ที่เกี่ยวข้อง: Perks ทั้งหมดไม่ยุ่งยาก: บทช่วยสอน Angular 9