In mvc-movie-giraffe I have a line like this in a view to generate a link to an edit page:
a [ _href ("/Movies/Edit/" + (string elt.Id)) ] [ encodedText "Edit" ]
Then where I setup the routes, I have the following:
routef "/Movies/Edit/%i" edit_handler
It would be nice to factor out that string "/Movies/Edit/".
So I added it to a Urls module along with some others:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
For the href value:
a [ _href ("/Movies/Edit/" + (string elt.Id)) ] [ encodedText "Edit" ]
we can do this instead:
a [ _href (sprintf (Printf.StringFormat<int->string>(Urls.movies_edit)) elt.Id) ] [ encodedText "Edit" ]
and for the route case:
routef "/Movies/Edit/%i" edit_handler
we can do this:
routef (PrintfFormat<obj, obj, obj, obj, int>(Urls.movies_edit)) edit_handler
And this does appear to work!
My question is, is there a better way? Perhaps something more concise? The above is a bit syntax heavy. Or is there already some established best practice around this?
I looked through the Giraffe samples and didn't notice anything like this technique being used.
Update - Approach #2
Here's one approach. Basically, factor out those longer expressions as well:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
let movies_edit_href = sprintf (Printf.StringFormat<int->string>(movies_edit))
let movies_edit_route = PrintfFormat<obj, obj, obj, obj, int>(movies_edit)
And then reference them in views:
a [ _href (Urls.movies_edit_href elt.Id) ] [ encodedText "Edit" ]
and when setting up routes:
routef Urls.movies_edit_route edit_handler
Update - approach #3
With approach #2, I ended up with this:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
let movies_edit_href = sprintf (Printf.StringFormat<int->string>(movies_edit))
let movies_edit_route = PrintfFormat<obj, obj, obj, obj, int>(movies_edit)
let movies_details = "/Movies/Details/%i"
let movies_details_href = sprintf (Printf.StringFormat<int->string>(movies_details))
let movies_details_route = PrintfFormat<obj, obj, obj, obj, int> (movies_details)
let movies_delete = "/Movies/Details/%i"
let movies_delete_href = sprintf (Printf.StringFormat<int->string>(movies_delete))
let movies_delete_route = PrintfFormat<obj, obj, obj, obj, int> (movies_delete)
There's some repetition there so I defined these extensions:
type String with
member this.route = PrintfFormat<obj, obj, obj, obj, int>(this)
member this.href = sprintf (Printf.StringFormat<int->string>(this))
Now, the Urls module is just:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
let movies_details = "/Movies/Details/%i"
let movies_delete = "/Movies/Details/%i"
And then to get the href string for movies_edit:
a [ _href (Urls.movies_edit.href elt.Id) ] [ encodedText "Edit" ]
And similar for the route:
routef Urls.movies_edit.route edit_handler