Album details
It's time to read album's details from the database.
Start by adjusting the details in View module:
let details (album : Db.AlbumDetails) = [ h2 album.Title p [ imgSrc album.AlbumArtUrl ] divId "album-details" [ for (caption,t) in ["Genre:",album.Genre;"Artist:",album.Artist;"Price:",formatDec album.Price] -> p [ em caption text t ] ] ]
Full name: CDocument.details
Above snippet requires defining a few more helper functions in View:
let imgSrc src = imgAttr [ "src", src ] let em s = tag "em" [] (text s) let formatDec (d : Decimal) = d.ToString(Globalization.CultureInfo.InvariantCulture)
Full name: CDocument.imgSrc
Full name: CDocument.em
Full name: CDocument.formatDec
as well as opening the System namespace at the top of the file.
Note: It's a good habit to open the
Systemnamespace every single time - in practice it usually turns out to be helpful.
In the details function we used list comprehension syntax with an inline list of tuples (["Genre:",album.Genre;...).
This is just to save us some time from typing the p element three times for all those properties.
You're welcome to change the implementation so that it doesn't use this shortcut if you like.
The AlbumDetails database view turns out to be handy now, because we can use all the attributes we need in a single step (no explicit joins required).
To read the album's details in App module we can do following:
let details id = match Db.getAlbumDetails id (Db.getContext()) with | Some album -> html (View.details album) | None -> never
Full name: CDocument.details
pathScan Path.Store.details details
A few remarks regarding above snippet:
detailstakesidas parameter and returns WebPartPath.Store.detailsof type IntPath guarantees type safetyDb.getAlbumDetailscan returnNoneif no album with given id is found- If an album is found, html WebPart with the
View.detailscontainer is returned - If no album is found,
NoneWebPart is returned with help ofnever.
No pipe operator was used this time, but as an exercise you can think of how you could apply it to the details WebPart.
Before testing the app, add the "placeholder.gif" image asset.
You can download it from here.
Don't forget to set "Copy To Output Directory", as well as add new file extension to the pathRegex in App module.
You might have noticed, that when you try to access a missing resource (for example entering album details url with arbitrary album id) then no response is sent.
In order to fix that, let's add a "Page Not Found" handler to our main choose WebPart as a last resort:
let webPart = choose [ path Path.home >=> html View.home path Path.Store.overview >=> overview path Path.Store.browse >=> browse pathScan Path.Store.details details pathRegex "(.*)\.(css|png|gif)" >=> Files.browseHome html View.notFound ]
Full name: CDocument.webPart
the View.notFound can then look like:
let notFound = [ h2 "Page not found" p [ text "Could not find the requested resource" ] p [ text "Back to " aHref Path.home (text "Home") ] ]
Full name: CDocument.notFound
GitHub commit: b9039a2f8faad3dd9ddceb458c64abed86b07e05
Files changed:
- App.fs (modified)
- SuaveMusicStore.fsproj (modified)
- View.fs (modified)
- placeholder.gif (added)