Để xây dựng một Web App
thực sự thì hiển nhiên là chúng ta sẽ muốn hiển thị những nội dung khác nhau tương ứng với các Url
khác nhau, không chỉ đối với những liên kết tĩnh như trang chủ /
hay trang giới thiệu /about
mà còn những liên kết có chứa các tham số truy vấn ví dụ như /search?q=seiza
.
Để tạo ra logic điều hướng dựa trên các liên kết có chứa tham số truy vấn như vậy thì chúng ta cần học cách sử dụng thêm một số công cụ được cung cấp bởi package elm/url
mà chúng ta đã cài đặt trước đó. Và ở đây, chúng ta sẽ tiếp tục xem xét ví dụ được Elm
đẳng tải trong loạt bài viết hướng dẫn trên trang web chính thức của họ.
Ví dụ 1
Giả sử chúng ta đang có một website
và các path
được liệt kê dưới đây đều hợp lệ.
/topic/architecture
/topic/painting
/topic/sculpture
/blog/42
/blog/123
/blog/451
/user/tom
/user/sue
/user/sue/comment/11
/user/sue/comment/51
Như vậy là chúng ta đang có các trang hạng mục topic
, các trang bài viết blog
, các trang thông tin người dùng user
, và phương thức để tìm kiếm bình luận của người dùng. Và bây giờ chúng ta có code ví dụ sử dụng module Url.Parser
để viết một chương trình phân tích đường dẫn Url
như sau:
type Route = Topic String | Blog Int | User String | Comment String Int routeParser : Parser (Route -> a) a
routeParser = oneOf [ map Topic (s "topic" </> string) , map Blog (s "blog" </> int) , map User (s "user" </> string) , map Comment (s "user" </> string </> s "comment" </> int) ]
Chúng ta đang có hàm routeParser
không có tham số đầu vào và sẽ trả về một trình khởi tạo Parser
với thông tin định kiểu cụ thể là Parser (Route -> a) a
. Tất cả các hàm hỗ trợ s
, </>
, string
, int
, đều được import
từ module Url.Parser
và được thiết kế để có cú pháp sử dụng ở bề mặt code tương ứng với định dạng của path
mà chúng ta cần tách lấy các tham số truy vấn.
Ok, như vậy là với cú pháp biểu thị dạng đường dẫn path
cần tách lấy các tham số như trên thì chúng ta có:
- Các chuỗi tĩnh trong
path
được mô tả bởi các lời gọi hàms
- Các lời gọi hàm
</>
tương ứng với các dấu xổ nghiêng/
trongpath
- Và các hàm
string
,int
, mô tả vị trí tách lấy các tham số truy vấn và kiểu dữ liệu trả về
Và đây là kết quả hoạt động của trình Parser
được trả về bởi hàm routeParser
.
-- /topic/pottery ==> Just (Topic "pottery")
-- /topic/collage ==> Just (Topic "collage")
-- /topic/ ==> Nothing -- /blog/42 ==> Just (Blog 42)
-- /blog/123 ==> Just (Blog 123)
-- /blog/mosaic ==> Nothing -- /user/tom/ ==> Just (User "tom")
-- /user/sue/ ==> Just (User "sue")
-- /user/ ==> Nothing -- /user/bob/comment/42 ==> Just (Comment "bob" 42)
-- /user/sam/comment/35 ==> Just (Comment "sam" 35)
-- /user/sam/comment/ ==> Nothing
Việc đọc code định nghĩa của các hàm đã sử dụng trong module Url.Parser
cũng quan trọng nhưng không hẳn là cần thiết ở thời điểm khởi đầu, bởi chúng ta đã nhìn thấy cú pháp sử dụng ở dạng mô tả trực quan rất declarative
, dễ hiểu và dễ áp dụng theo mà không cần phải đọc hiểu trình tự hoạt động cụ thể của các lời gọi hàm ở đây.
Ví dụ 2
Bây giờ là một trường hợp ví dụ khác khi chúng ta đang có một trang blog cá nhân với các đường dẫn hợp lệ như sau:
/blog/12/the-history-of-chairs
/blog/13/the-endless-september
/blog/14/whale-facts
/blog/
/blog?q=whales
/blog?q=seiza
Trong trường hợp này, chúng ta đang có các trang bài viết /blog/number/
và các trang kết quả tìm kiếm /blog?q=...
với tham số truy vấn ở khóa q=
. Để tách lấy tham số các thám số truy vấn tùy chọn ở vị trí khóa q=
thì chúng ta cần sử dụng thêm module Url.Parser.Query
.
import Url.Parser exposing (Parser, (</>), (<?>), int, map, oneOf, s, string)
import Url.Parser.Query as Query type Route = BlogPost Int String | BlogQuery (Maybe String) routeParser : Parser (Route -> a) a
routeParser = oneOf [ map BlogPost (s "blog" </> int </> string) , map BlogQuery (s "blog" <?> Query.string "q") ]
Cú pháp áp dụng trong trường hợp này cũng hoàn toàn dễ nhìn thấy dạng của path
được mô tả trong code. Và đây là kết quả hoạt động của trình Parser
được trả về bởi hàm routeParser
.
`/blog/12/the-history-of-chairs` ==> Just (BlogPost 12 "the-history-of-chairs")
`/blog/13/the-endless-september` ==> Just (BlogPost 13 "the-endless-september")
`/blog/14/whale-facts` ==> Just (BlogPost 14 "whale-facts")
`/blog/` ==> Just (BlogQuery Nothing)
`/blog?q=whales` ==> Just (BlogQuery (Just "whales"))
`/blog?q=seiza` ==> Just (BlogQuery (Just "seiza"))
Ví dụ 3
Và ví dụ cuối cùng là chúng ta có một website dạng trang tài liệu tổng hợp với các đường dẫn hợp lệ như sau:
/Basics
/Maybe
/List
/List#map
/List#filter
/List#foldl
Trong trường hợp này, chúng ta đang có các đường dẫn chứa các tên định danh id
của một phần tử HTML
nào đó. Và để tách lấy các id
này thì chúng ta sẽ cần sử dụng thêm hàm fragment
trong module Url.Parser
.
type alias Docs = (String, Maybe String) docsParser : Parser (Docs -> a) a
docsParser = map Tuple.pair (string </> fragment identity)
Như vậy là chúng ta có các lời gọi hàm </> fragment identity
để bắt đầu tách lấy #id
ở đoạn cuối cùng của path
, có phần hơi đặc biệt. Tuy nhiên chúng ta cũng có thể đọc theo cách đơn giản, </> fragment
là ký hiệu #
, và identity
là vị trí của chuỗi id
cần tách lấy trong path
. Và đây là kết quả hoạt động tương ứng.
-- /Basics ==> Just ("Basics", Nothing)
-- /Maybe ==> Just ("Maybe", Nothing)
-- /List ==> Just ("List", Nothing)
-- /List#map ==> Just ("List", Just ("map"))
-- /List#filter ==> Just ("List", Just ("filter"))
-- /List#foldl ==> Just ("List", Just ("foldl"))
Như vậy là chúng ta cũng đã biết thêm cách sử dụng module Url
để tách lấy các tham số truy vấn trong path
để có thể sử dụng cho logic xử lý trong hàm update
của Browse.application
.
Sau đó thì update
sẽ tạo ra một bản ghi model
mới tương ứng với thông tin truy vấn được để view
có thể điều chỉnh giao diện hiển thị của trang đơn cho phù hợp với yêu cầu của người dùng. Phần còn lại của câu chuyện lúc này là chúng ta chưa có cách thức để thay đổi nội dung của phần tử <head>
bởi Elm
không có module
nào hỗ trợ.
(chưa đăng tải) [Declarative Programming + Elm] Bài 17 - JavaScript Inter-Operation