Xây dựng web app thời tiết đẹp với Angular 6 (2018) – Phần 2: Phát triển

6
2119

Nếu chưa xem phần 1 thì bạn nên xem nhé. Vì phần 1 rất ngắn và có nhiều thông tin hữu ích, có nó bạn sẽ dễ nhai phần 2 hơn.

Click để xem: Xây dựng web app thời tiết đẹp với Angular 6 từ A đến Z (2018) – Phần I: Thiết kế

Trước khi bắt đầu phần 2 này, mình có 1 giao kèo nhỏ với các bạn. Để trở nên thông minh hơn, hãy học cách làm biếng ở đúng nơi quy định. Bạn cần làm siêng đoạn này bởi là lập trình viên bạn cần: nhìn nhận và lặp lại vấn đề, tìm mọi cách khác nhau để thử nghiệm 1 vấn đề, nếu sai, hãy thử lại.

Vì vậy, đừng chỉ sao chép, dán vô Editor, đọc mà không nghĩ, hay mở trình duyệt test chạy demo mà méo cần biết lý do tại sao nó như vậy => bạn đang tự hại chính bạn.

Lý do là: bạn bỏ thời gian ra đọc bài viết, tuy mình có giải thích từng phần nếu đoạn đó có gì hay nhưng bạn không thử nghiệm thì bạn đang lãng phí thời gian khi xem đấy. Hãy thử nhập bất cứ gì, code thêm gì đó, hoặc siêng hơn gõ lại mọi thứ theo cách riêng của bạn.

Hướng dẫn này chỉ lối chứ không định hình cách bạn suy nghĩ, tự tay làm, tự tay hiểu và kết thúc theo cách bạn muốn. Mọi thứ sẽ đi xa bài viết này nhưng bạn có được nhiều hơn điều bạn muốn. Bạn muốn thử? Vậy mở Editor yêu thích lên và thử ngay cùng mình nhé!

Mình sẽ giả dụ bạn đã biết Angular là gì, Firebase ra sao,… Nếu bạn chưa biết? Đừng lo, vì hướng dẫn này dành cho mọi người, mình sẽ giải thích chi tiết hết sức ngay cả những bạn mới bắt đầu cũng có thể có thể nắm được.

Biết đâu, qua bài viết này bạn thực hành và có ý tưởng mới thì sao? Triển ngay bạn nhé :).

Bắt đầu mọi thứ bằng việc cài đặt NodeJS, Git và Angular CLI.

NodeJS: https://nodejs.org/en/
Git: https://git-scm.com/

Sau khi cài đặt Git, mở Git CLI hoặc Powershell lên: gõ 2 dòng này để cài đặt TyperScript và Angular CLI trên toàn cục(-g là global tức project nào gọi và xài ở đâu cũng được, không bị giới hạn trong project đó)

npm i -g typescript
npm i -g @angular/cli

sau khi chạy xong, tiếp theo bạn chỉ cần thêm dòng dưới để tạo ra 1 ứng dụng bằng Angular CLI và đừng quên thêm --routing phía sau để tạo điểm bắt đầu tốt cho phân trang và route. Route là cách bạn tạo ra những URL tùy biến, rất dễ dàng.

ng new Minimus --routing

Rất đơn giản phải không? Một khi trình cài đặt hoàn tất, bạn đã có được 1 dự án Angular cơ bản đi kèm tất cả thư viện(qua npm) cần thiết rồi đó.
Một chút cho các bạn mới: npm là công cụ quản lý gói dùng cho Node.js. Để dễ hình dung, mình sẽ ví dụ trong C++, bởi là sinh viên bạn đã kinh qua môn này nên nhớ dai, bạn dùng:

#include <isostream>

Đây là thư viện dùng để xử lý chuỗi, các hàm nhập vào và xuất ra. Không có nó bạn không dùng được cin, cout,…

Tương tự, npm giống như thư viện số, nơi lưu trữ rất nhiều cuốn sách như stdio.h, conio.h,… Tùy mỗi quyển sách sẽ cho ta nhiều quyền năng khác nhau, các quyền năng này được hiện thực hóa thông qua các hàm – giúp ta thao tác và xử lý vấn đề mình cần giải quyết.

Bạn thấy đó, cùng với sự phát triển chóng mặt thì những công cụ mạnh mẽ như npm ra đời giúp cộng đồng mã nguồn mở trở nên mạnh mẽ hơn. Bạn có nhiều quyền năng hơn, tự do hơn và đau não hơn khi có quá nhiều thứ để học.

Giải thích xong phần npm thì việc chuẩn bị và tạo project đã xong, chúng ta sẽ khởi động máy chủ và mở ứng dụng của chúng ta trong trình duyệt bằng lệnh sau đây (hậu tố -o giúp mở một tab trình duyệt mới một cách tự động với URL trỏ đến ứng dụng của bạn)

ng serve -o

A. Template và Styling (mẫu và kiểu)

Bây giờ cùng trở lại dự án mà chúng ta vừa hoàn thành phần thiết lập cơ bản của ứng dụng. Bây giờ chúng ta cùng nhau viết mã HTML và CSS để định hình ứng dụng sẽ trông như thế nào nhé! Dùng trình code ưa thích ưa thích của bạn – với mình là combo Visual Code (project) + Sublime Text (file đơn) để bắt đầu. Yolo nào mấy chế!!!

* App Component – hiểu đại khái là thành phần ứng dụng trong Angular:

Tất cả mọi thứ xoay quanh Angular đều xoay quanh khái niệm Component, đây là 1 khái niệm mới với những bạn lần đầu tiếp cận Angular. Nếu mới bắt đầu, hãy tìm hiểu Component tại đây >>>.
Chúng ta sẽ sử dụng component gốc: app.component như component navbar. Navbar sẽ hiện hoặc ẩn tùy thuộc vào điều kiện khi người dùng có đăng nhập hay không (sẽ hiện thực hóa thông qua chức năng Authentication trong phần III với Angularfire của loạt bài này)

Mình từng nghĩ tới việc việc dùng 1 vài component bên ngoài Angular để làm mọi thứ geek hơn… Nhưng KHÔNG, mình muốn giữ ứng dụng càng nhẹ càng tốt nên sẽ không sử dụng bất cứ thư viện bên thứ ba nào trừ khi nó thật sự cần thiết như: Angularfire Lite.

Đầu tiên, hãy mở file app.component.html và xóa tất cả HTML được tạo tự động bởi CLI, thêm ít mã để file HTML của bạn trông giống vầy:

* Mẹo cho các bác tiều phu chăm đốn củi:

Emmet (1 plugin cool ngầu giúp bạn type HTML nhanh như điện), chắc nhiều bạn hay xài mà không biết, trên Sublime Text sau khi cài plugin Emmet, thử gõ Emmet code bên dưới và nhấn Tab để thấy điều kỳ diệu.

Emmet code:
ul>li.item$*5
HTML code tạo ra bởi Emmet code:
<ul>
<li class="item1"></li>
<li class="item2"></li>
<li class="item3"></li>
<li class="item4"></li>
<li class="item5"></li>
</ul>

Nếu bạn chưa biết, nên xem qua cheat sheet dưới link này. Cheat Sheet này chứa rất nhiều example và trick ảo diệu vô cùng:

Link: https://docs.emmet.io/cheat-sheet/

* SVG icons

để lấy svg icon và logo, mình có tổng hợp rất nhiều gist mình đã tạo trên Github của mềnh (so deep quá) để bạn có thể sử dụng chúng (copy và paste):

* CSS mớ component gốc cho sexy xíu.

đã tới lúc trang điểm cho thanh navbar rồi. Nhiệm vụ của bạn? Copy và dán thôi, CSS đừng dại mà gõ từng dòng. Bạn sẽ thấy em nó đã lung linh hơn rồi đấy. Sao không thể hiện mình bằng việc tạo ra CSS riêng hoặc thêm thắt theo ý bạn?

Ngu dốt là khi copy code mà không hiểu mình copy cái gì.

– Khuyết danh.

Câu này hơi nặng nhưng mong anh em thông cảm, hàng nặng thì nhớ lâu thôi.

Giải thích chút về mớ CSS trên:

* Layout:

display: grid;
grid-template-columns: auto;
grid-template-rows: 0.5fr auto;

ở 3 hàng này, cơ bản mình đang sử dụng CSS Grid Layout để chia trang ra thành 2 dòng (rows), dòng trên cùng nhỏ xíu để hiển thị thanh navbar, dòng dưới siêu bự để hiển thị router – nội dung chính của trang. Nếu mơ hồ, nhìn ảnh dưới:

* sidenav – thanh trượt nội dung bên trái khi bấm nút hamburger

.side-menu__conatiner {
position: fixed;
left: 0;
top: 0 }

đặt sidnav lên đầu, bên trái của viewport.

.side-menu__container::before {...}

được dùng để làm mờ background với màu xanh dương khi sidebar trượt vào.

will-change: opacity;

được dùng để thông báo cho trình duyệt biết trước khi toàn bộ background bị làm mờ để web app có thể đạt hiệu suất tốt hơn khi render.

Ví dụ thực tế về will-change: Trong bộ môn chạy tiếp sức, đường dài nên cần đồng đội, và “tín gậy” là tấm vé để đồng đội đi tiếp.

Khi bạn chạy gần tới đích và chuẩn bị đưa “tín gậy” cho thằng bạn, lúc này bạn hú lên: “ê, tao sắp tới”, thằng bạn sẽ hiểu và đưa tay chờ sẵn, chực có gậy là chạy ngay.
Thằng bạn chờ gậy là trình duyệt, đang chờ gậy tức chờ sự kiện background làm mờ thay đổi hoàn toàn. Trong lúc này nó sẽ chuẩn bị sức, căng não các kiểu (dọn tài nguyên) để đón nhận “tín gậy” và chạy (ok, opacity đã hoàn hảo, xử lý tiếp thôi).

Tại sao điều này quan trọng? Nó là 1 phần trong việc tăng trải nghiệm người dùng và cả hiệu năng khiến người dùng cảm thấy “mượt – ngon” hơn khi web app phản hồi tốt. Bạn có thể đọc thêm tại đây:
https://developer.mozilla.org/en-US/docs/Web/CSS/will-change

.slide-menu { transform: translateX(-103%); }

được dùng để gửi menu về 1 nơi xa, nơi người dùng không nhìn thấy: cụ thể là qua trái. Khi người dùng click vào dấu 3 gạch ngang(gọi là nút hambuger), đơn giản ta thêm 1 lớp .slide-menu-active để hiện lại menu, lúc đó menu sẽ trượt từ trái sang khi người dùng nhấn nút hambuger.

.slide-menu-active { transform: none; }

* nút chuyển đổi

một mẹo nhỏ trong việc xây dựng UI mà mình muốn đề cập đến là cách thiết kế nút chuyển đổi chủ đề sáng / tối.

Cơ bản thì mình đặt lại hết css property của nút checkbox thành none hết để loại bỏ hết style được áp dụng mặc định (đừng đặt display: none nhé, mình chỉ loại bỏ những property của nút này để nó trở thành 1 cô gái thơ ngây chưa makeup thôi). Sau đó mình sử dụng 2 class khác nhau cho nền của nút chuyển đổi kèm với vòng tròn để thay đổi màu sắc và vị trí của vòng tròn tùy thuộc vào biến có kiểu dữ liệu boolean(true/false) được lưu trữ trên component sử dụng ngClass (nhấn để tìm hiểu về ngClass – 1 Directive attribute rất hay của Angular >>>) cho phép bạn chuyển đổi các lớp css so easy.

* Home Component

đây là Home Component, là nơi chúng ta hiển thị nội dung chính gồm các thẻ thời thiết khác nhau của từng thành phố ưa thích, đây cũng là nơi người dùng có thể nhấp vào nút thêm thành phố và bla bla => thành phố mới được bổ sung vào Home Component. Đầu tiên chúng ta cần tạo component này bằng cách dùng CLI, sử dụng lệnh sau:

ng g c home

mã HTML được tạo tự động không có gì hơn ngoài container và 2 component khác. Giờ là lúc bạn có thể thêm thắt các component khác với mã HTML, bạn sẽ dễ dàng thấy được nội dung hiển thị ngoài web app của mình. Mình sẽ thêm 1 vài thẻ nhé.

Component thẻ thời tiết.

Đoạn code dưới sử dụng ngSwitch (1 directive attribute trong Angular) cho phép kiểm tra thời tiết và những thay đổi xung quanh nó:

markup chút cho đẹp gái nè:

DarkMode:

Trong đoạn mã CSS trên, bạn có thể thấy hầu hết các element giao diện người dùng mình đều thêm 2 class.

Tại sao?

Vì mình muốn thêm lớp CSS mở rộng cho chế độ xem tối (dark theme) với hậu tố: -dark để chúng ta có thể dễ dàng chuyển đổi sau đó sử dụng lại ngClass directive dựa trên “trạng thái” nút đổi chủ đề.

Component thẻ “Thêm thành phố”

Mình đã thêm 1 div để bọc ngClass directive giúp dễ dàng thay đổi trạng thái khi người dùng chuyển sang Dark Mode và mình cũng thêm một router có tên routerLink trên Angular để điều hướng người dùng đến trang thêm thành phố khi thẻ này được nhấp.

Phần này code CSS rất đơn giản vì nó tương tự với cách style main card. Ông này cũng dùng Grid Layout để tạo 2 rows bằng nhau cho mỗi không gian hiện nội dung. Đừng quên thêm thuộc tính light drop shadow – tức đổ bóng giúp thẻ trông nổi hơn.

Component thông tin chi tiết – Details Component

Tại đây mình sẽ dùng API của 1 dịch vụ thời tiết để lấy và hiển thị dữ liệu. Dựa vào dữ liệu từ dịch vụ này chúng ta sẽ hiển thị được ngày, nhiệt độ và điều kiện thời tiết trong 1 biến toàn cục weather từ class WeatherService. Dưới đây là cách để thực hiện:

Rõ ràng có rất nhiều thứ cần lọc và chỉnh sửa khi lấy dữ liệu thô từ dịch vụ thời tiết bất kỳ. Để dữ liệu phù hợp với ứng dụng web này, chúng ta cần chuyển 1 số logic sang để code sang dịch vụ WeatherService.

Đừng quên rằng unsubscribe 1 component nếu bạn đã subscribe khi em nó render xong. Bởi 1 vòng đời của ngOnDesstroy – 1 Lifecycle Hook trong Component cần được unsubscrible để tránh rò rỉ bộ nhớ (memory leaks). Ứng dụng nhỏ thì sẽ không có gì lớn nhưng nếu một ứng dụng phức tạp nó thì nó là một thảm họa nếu chúng ta không quản lý tốt chúng.

Trong Details Component có rất nhiều svgs khiến file HTML của chúng ta trở nên dài vì vậy mình tách riêng ra 1 file HTML đã thêm tất cả code svg icon vào đây để tránh làm rối đội hình.

với chế độ ban đêm “Dark Mode”, mình đã “trang điểm” em nó như này:

B. Services

Việc xây dựng ứng dụng ngày nay phụ thuộc khá nhiều vào API.

API là các hàm được các dịch vụ phát triển để giúp ứng dụng dễ dàng giao tiếp thông qua các phương thức: GET, POST, DELETE, PUT,… để lấy, đẩy, xóa,… dữ liệu. Nói chung, nó là cánh cổng có điều kiện giúp dân chúng không phải buồn phiền khi làm app, web app,…

Ví dụ: bạn cần gửi 1 danh sách chữ trong văn bản lên FPT Text Speech với hi vọng nhận về 1 file audio để đọc thành tiếng Việt những từ đó.

Các bạn lập trình viên tại FPT sẽ viết 1 API, cho phép bạn dùng phương phức POST để gửi dữ liệu body kèm các đối số api_key, voice, speed,… đặt ở thẻ HEADER. Các bạn đã hiểu cách mà API hoạt động chưa nhỉ? Giờ mình sẽ giải thích tại sao lại dùng API?

  • Cho phép phát triển theo dạng module, giảm sự phụ thuộc.
  • Thường request sẽ trả về định dạng JSON, vô cùng nhẹ và mềm dẻo. Đây chính là dữ liệu hiển thị cho bạn. Tùy vào phương thức PUT, DELETE,.. mà bạn có thể “truy vấn” và cập nhật lên database của serve hoặc lấy dữ liệu qua phương thức GET dựa vào các đối số với mỗi value khác biệt.
  • Bảo trì, cập nhật dễ dàng. Thay vì phát hành bản cập nhật, bạn có thể thay đổi cấu trúc services của bạn trên server.

API còn rất nhiều lợi ích đấy, bạn hãy tìm hiểu thêm nhé. Khá dài dòng về API bởi đa số website lớn hiện nay đều cung cấp API hoàn toàn miễn phí. Cho phép bạn sử dụng dữ liệu, tùy vào ứng dụng của bạn để khai thác mang lại nhiều hiệu quả.

Danh sách rất nhiều API free cho anh em test:

https://github.com/toddmotto/public-apis

Xong phần API, trở lại vấn đề chính. Mình muốn táchriêng phần logic từ việc nhận dữ liệu thông qua API của 1 nhà cung cấp dịch vụ thời tiết và chuyển nó thành 1 services riêng biệt. Nơi mà mình có thể dùng nó xuyên suốt ứng dụng. Và 1 lần nữa, mình sẽ sử dụng CLI để tạo ra 1 services cho web app này.

* Dịch vụ thời tiết – Weather service.

ng g s weather

dịch vụ này sử dụng API của OpenWeatherMap để lấy thông tin thời tiết và thực hiện 1 số thay đổi dữ liệu lấy được trước khi hiện ra cho người dùng cuối xem.

API không có sẵn dữ liệu về nhiệt độ tối đa & tối thiểu. Và do nó miễn phí nên cũng hạn chế khi chỉ cho phép lấy kết quả dự báo chỉ 3 giờ mỗi 5 ngày. Vì vậy, mình phải xem xét và trích xuất gần đúng giá trị lớn nhất và nhỏ nhất của nhiệt độ trong 3 giờ đó.

và đây là đoạn mã trong weather.service.ts để làm điều đó:

như bạn thấy, tất cả các hàm đều trả về 1 Subject – nơi ta dùng để truyền dữ liệu đã tiền xử lý này cho bất cứ Component nào dùng nó. Do API của ông OpenWeatherMap này miễn phí nên cá nhân thấy như sịp, mình có thể làm tốt hơn bằng cách chuyển đổi mớ REST API ngu học này thành 1 GraphQL ngon lành hơn nhiều, hãy chú ý theo dõi:

giải thích nhanh nghĩa vụ của tất cả function trong dịch vụ này:

  • getWeatherState: trạng thái thời tiết hiện tại, ví dụ: có mây – trời trong xanh…
  • getCurrentTemp: nhiệt độ hiện tại (số)
  • getMinTemp: nhiệt độ tối thiểu (dựa trong khoảng thời gian 3 giờ)
  • getCurrentHum: giá trị độ ẩm hiện tại (số)
  • getCurrentWind: tốc độ gió hiện tại (số)
  • getForecast: lấy dữ liệu thời tiết trong 5 ngày sắp tới
  • getCityWeatherByName: trả về toàn bộ dữ liệu thời tiết từ API của thành phố được cung cấp dưới dạng chuỗi (VD: qatar, japan, france,…)
  • getCitiesWeathersByNames: trả về toàn bộ dữ liệu thời tiết từ API của thành phố được cung cấp dưới dạng mảng

UI service

đây là 1 dịch vụ nhỏ mà chúng ta sẽ sử dụng để chia sẻ trạng thái của UI như: chế độ chủ đề được chọn (sáng hay tối đèn).

C. Routing

Bạn còn nhớ lúc tạo ứng dụng Angular với câu lệnh này không?

ng new Minimus --routing

Lúc đó mô-đun routing cũng đã được tạo ra cùng với app. Nhưng đó là mặc định, chúng ta cần thực hiện 1 số thay đổi với file routing.module.ts để Angular biết các route khác nhau (URLs) và các component liên quan (pages).

Tổng kết

Chúng ta đã đi nhiều bước ngắn để có được con đường dài như hôm nay. Mình tin kiến thức của nhiều anh em cũng dài lên từng ấy con đường, sẽ có nhiều anh em bước xa hơn khi anh em không chỉ đọc, thực hành mà còn biến tấu theo cách của anh em. Giờ là lúc cùng nhìn lại con đường này nhé.

Live Demo: https://minimus-app.firebaseapp.com/

Giờ là lúc check những mục chúng ta đã hoàn thành trong danh sách công việc cần làm được đề cập ở phần I:

  • Xây dựng trên phiên bản mới nhất, xịn nhất của Angular 6. 
  • 2 chế độ: chế độ sáng trăng và khi trời tối (Dark & Light Mode). 
  • CSS thời @ – Grid Layout & Flex Box. 
  • Thiết kế vừa tối giản mà lại đẹp. 

Ở các đầu mục tiếp theo của loạt bài này, chúng ta sẽ làm việc với các phần còn lại.

Để không bỏ sót hãy ghé thăm sharengay thường xuyên để cập nhật nhé!!!

Nguồn: Build A Real World Beautiful Web APP with Angular 6… từ Medium

Xây dựng web app thời tiết đẹp với Angular 6 (2018) – Phần 2: Phát triển
5 (100%) 3 votes

6
Bình luận bài viết

avatar
3 Comment threads
3 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
vu100136VănBà NaNguyen Long Recent comment authors
mới nhất cũ nhất like nhiều nhất
vu100136 | <span class="wpdiscuz-comment-count">1 comments</span>
Khách
vu100136 | 1 comments

Bao h co phan 3 zay ban

Văn | <span class="wpdiscuz-comment-count">2 comments</span>
Khách
Văn | 2 comments

rất hay, tks nhìu nhìu

Nguyen Long | <span class="wpdiscuz-comment-count">6 comments</span>
Khách
Nguyen Long | 6 comments

Good job. Bai viet dai vl. Nhung nhieu thong tin rat hay, cam on bac