Create album form
Because of possible namespace conflicts between Suave.Form.input
and Suave.Html.input
, let's define a helper function to the former:
View.fs
18:
|
|
To define a form for album creation, we can invoke renderForm
like this:
View.fs
144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: |
|
We can see that for the Html
values we can invoke selectInput
or input
functions.
Both of them take as first argument function which directs to field for which the input should be generated.
input
takes as second argument a list of optional attributes (of type string * string
- key and value).
selectInput
takes as second argument list of options (of type decimal * string
- value and display name).
As third argument, selectInput
takes an optional selected value - in case of None
, the first one will be selected initially.
Note: We are hardcoding the album's
ArtUrl
property with "/placeholder.gif" - we won't implement uploading images, so we'll have to stick with a placeholder image.
Now that we have the createAlbum
view, we can write the appropriate WebPart handler.
Start by adding getArtists
to Db
:
Db.fs
22:
|
|
Db.fs
62: 63: |
|
Then proper entry in Path
module:
Path.fs
16: 17: 18: 19: |
|
and WebPart in App
module:
App.fs
43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: |
|
App.fs
78:
|
|
Once again, warbler
will prevent from eager evaluation of the WebPart - it's vital here.
To our View.manage
we can add a link to createAlbum
:
View.fs
101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: |
|
This allows us to navigate to /admin/create
, however we're still lacking the actual POST handler.
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp.Data
--------------------
namespace Microsoft.FSharp.Data
type LiteralAttribute =
inherit Attribute
new : unit -> LiteralAttribute
Full name: Microsoft.FSharp.Core.LiteralAttribute
--------------------
new : unit -> LiteralAttribute
Full name: SuaveMusicStore.Db.ConnectionString
Full name: SuaveMusicStore.Db.Sql
Full name: FSharp.Data.Sql.SqlDataProvider
<summary>Typed representation of a database</summary>
<param name='ConnectionString'>The connection string for the SQL database</param>
<param name='ConnectionStringName'>The connection string name to select from a configuration file</param>
<param name='DatabaseVendor'> The target database vendor</param>
<param name='IndividualsAmount'>The amount of sample entities to project into the type system for each SQL entity type. Default 1000.</param>
<param name='UseOptionTypes'>If true, F# option types will be used in place of nullable database columns. If false, you will always receive the default value of the column's type even if it is null in the database.</param>
<param name='ResolutionPath'>The location to look for dynamically loaded assemblies containing database vendor specific connections and custom types.</param>
<param name='Owner'>The owner of the schema for this provider to resolve (Oracle Only)</param>
<param name='CaseSensitivityChange'>Should we do ToUpper or ToLower when generating table names?</param>
<param name='TableNames'>Comma separated table names list to limit a number of tables in big instances. The names can have '%' sign to handle it as in the 'LIKE' query (Oracle and MSSQL Only)</param>
<param name='OdbcQuote'>Odbc quote characters: Quote characters for the table and column names: `alias`, [alias]</param>
<param name='SQLiteLibrary'>Use System.Data.SQLite or Mono.Data.SQLite or select automatically (SQLite only)</param>
| MSSQLSERVER = 0
| SQLITE = 1
| POSTGRESQL = 2
| MYSQL = 3
| ORACLE = 4
| MSACCESS = 5
| ODBC = 6
| FIREBIRD = 7
Full name: FSharp.Data.Sql.Common.DatabaseProviderTypes
| ORIGINAL = 0
| TOUPPER = 1
| TOLOWER = 2
Full name: FSharp.Data.Sql.Common.CaseSensitivityChange
Full name: SuaveMusicStore.Db.DbContext
member ClearUpdates : unit -> List<SqlEntity>
member CreateConnection : unit -> IDbConnection
member GetUpdates : unit -> List<SqlEntity>
member Public : publicSchema
member SubmitUpdates : unit -> Unit
member SubmitUpdatesAsync : unit -> Async<Unit>
nested type public.albumdetails.Individuals
nested type public.albumdetailsEntity
nested type public.albums.Individuals
nested type public.albumsEntity
...
Full name: FSharp.Data.Sql.SqlDataProvider,DatabaseVendor="2",ConnectionString="Server=192.168.99.100;Database=suavemusicstore;User Id=suave;Password=1234;",CaseSensitivityChange="0".dataContext
Full name: SuaveMusicStore.Db.Album
Full name: SuaveMusicStore.Db.Genre
Full name: SuaveMusicStore.Db.AlbumDetails
Full name: SuaveMusicStore.Db.Artist
Full name: SuaveMusicStore.Db.getContext
<summary>Returns an instance of the SQL Provider using the static parameters</summary>
SqlDataProvider<...>.GetDataContext(transactionOptions: Transactions.TransactionOptions) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='transactionOptions'>TransactionOptions for the transaction created on SubmitChanges.</param>
SqlDataProvider<...>.GetDataContext(connectionString: string) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
SqlDataProvider<...>.GetDataContext(connectionString: string, transactionOptions: Transactions.TransactionOptions) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
<param name='transactionOptions'>TransactionOptions for the transaction created on SubmitChanges.</param>
SqlDataProvider<...>.GetDataContext(connectionString: string, resolutionPath: string) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
<param name='resolutionPath'>The location to look for dynamically loaded assemblies containing database vendor specific connections and custom types</param>
SqlDataProvider<...>.GetDataContext(connectionString: string, resolutionPath: string, transactionOptions: Transactions.TransactionOptions) : SqlDataProvider<...>.dataContext
<summary>Returns an instance of the SQL Provider</summary>
<param name='connectionString'>The database connection string</param>
<param name='resolutionPath'>The location to look for dynamically loaded assemblies containing database vendor specific connections and custom types</param>
<param name='transactionOptions'>TransactionOptions for the transaction created on SubmitChanges.</param>
Full name: SuaveMusicStore.Db.getGenres
Full name: Microsoft.FSharp.Collections.list<_>
<summary> The base table genres belonging to schema public</summary>
module Seq
from FSharp.Data.Sql
--------------------
module Seq
from Microsoft.FSharp.Collections
Full name: Microsoft.FSharp.Collections.Seq.toList
Full name: SuaveMusicStore.Db.getAlbumsForGenre
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.query
<summary> The base table albums belonging to schema public</summary>
Calls Linq.QueryBuilder.Join
<summary> integer</summary>
Calls Linq.QueryBuilder.Where
<summary> character varying(120)</summary>
Calls Linq.QueryBuilder.Select
Full name: SuaveMusicStore.Db.getAlbumDetails
Full name: Microsoft.FSharp.Core.option<_>
<summary> The view albumdetails belonging to schema public</summary>
<summary> integer</summary>
Full name: Microsoft.FSharp.Collections.Seq.tryHead
Full name: SuaveMusicStore.Db.getAlbumsDetails
module List
from FSharp.Data.Sql
--------------------
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
Full name: Microsoft.FSharp.Collections.List.sortBy
<summary> character varying(120)</summary>
Full name: SuaveMusicStore.Db.getAlbum
<summary> integer</summary>
Full name: SuaveMusicStore.Db.deleteAlbum
<summary>Save changes to data-source. May throws errors: To deal with non-saved items use GetUpdates() and ClearUpdates().</summary>
Full name: SuaveMusicStore.Db.getArtists
<summary> The base table artists belonging to schema public</summary>
Full name: SuaveMusicStore.Path.IntPath
type PrintfFormat<'Printer,'State,'Residue,'Result> =
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result>
member Value : string
Full name: Microsoft.FSharp.Core.PrintfFormat<_,_,_,_>
--------------------
type PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple> =
inherit PrintfFormat<'Printer,'State,'Residue,'Result>
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple>
Full name: Microsoft.FSharp.Core.PrintfFormat<_,_,_,_,_>
--------------------
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result>
--------------------
new : value:string -> PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple>
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Full name: Microsoft.FSharp.Core.unit
Full name: SuaveMusicStore.Path.withParam
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
Full name: SuaveMusicStore.Path.home
Full name: SuaveMusicStore.Path.Store.overview
Full name: SuaveMusicStore.Path.Store.browse
Full name: SuaveMusicStore.Path.Store.details
Full name: SuaveMusicStore.Path.Store.browseKey
from SuaveMusicStore.Path
Full name: SuaveMusicStore.Path.Admin.manage
Full name: SuaveMusicStore.Path.Admin.createAlbum
Full name: SuaveMusicStore.Path.Admin.deleteAlbum
from Suave
{ArtistId: decimal;
GenreId: decimal;
Title: string;
Price: decimal;
ArtUrl: string;}
Full name: SuaveMusicStore.Form.Album
val decimal : value:'T -> decimal (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.decimal
--------------------
type decimal = System.Decimal
Full name: Microsoft.FSharp.Core.decimal
--------------------
type decimal<'Measure> = decimal
Full name: Microsoft.FSharp.Core.decimal<_>
Full name: SuaveMusicStore.Form.album
union case Form.Form: FormProp<'a> list * ServerSideValidation<'a> list -> Form<'a>
--------------------
type Form<'a> = | Form of FormProp<'a> list * ServerSideValidation<'a> list
Full name: Suave.Form.Form<_>
Full name: Suave.Form.maxLength
Full name: Suave.Form.min
Full name: Suave.Form.max
Full name: Suave.Form.step
from Suave
Full name: SuaveMusicStore.View.em
Full name: Suave.Html.tag
Full name: SuaveMusicStore.View.cssLink
Full name: Suave.Html.link
Full name: SuaveMusicStore.View.h2
Full name: SuaveMusicStore.View.ul
Full name: SuaveMusicStore.View.li
Full name: SuaveMusicStore.View.table
Full name: SuaveMusicStore.View.th
Full name: SuaveMusicStore.View.tr
Full name: SuaveMusicStore.View.td
Full name: SuaveMusicStore.View.strong
Full name: Suave.Html.text
Full name: SuaveMusicStore.View.form
Full name: SuaveMusicStore.View.formInput
Full name: Suave.Form.input
Full name: SuaveMusicStore.View.submitInput
Full name: Suave.Html.input
{Label: string;
Html: Form<'a> -> Node;}
Full name: SuaveMusicStore.View.Field<_>
Field.Html: Form<'a> -> Node
--------------------
type HtmlAttribute = string * string
Full name: Suave.Form.HtmlAttribute
union case Form.Form: FormProp<'a> list * ServerSideValidation<'a> list -> Form<'a>
--------------------
module Form
from SuaveMusicStore
--------------------
type Form<'a> = | Form of FormProp<'a> list * ServerSideValidation<'a> list
Full name: Suave.Form.Form<_>
| Element of Element * Node list
| VoidElement of Element
| Text of string
| Raw of string
| WhiteSpace of string
Full name: Suave.Html.Node
{Legend: string;
Fields: Field<'a> list;}
Full name: SuaveMusicStore.View.Fieldset<_>
{Fieldsets: Fieldset<'a> list;
SubmitText: string;
Form: Form<'a>;}
Full name: SuaveMusicStore.View.FormLayout<_>
FormLayout.Form: Form<'a>
--------------------
module Form
from SuaveMusicStore
--------------------
type Form<'a> = | Form of FormProp<'a> list * ServerSideValidation<'a> list
Full name: Suave.Form.Form<_>
Full name: SuaveMusicStore.View.renderForm
Full name: Suave.Html.div
Full name: SuaveMusicStore.View.home
Full name: SuaveMusicStore.View.store
Full name: Suave.Html.p
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
Full name: Microsoft.FSharp.Collections.List.length
from SuaveMusicStore
from SuaveMusicStore.Path
Full name: Suave.Html.a
Full name: SuaveMusicStore.View.browse
from SuaveMusicStore
Full name: SuaveMusicStore.Db.Album
Full name: SuaveMusicStore.Path.Store.details
<summary> integer</summary>
<summary> character varying(160)</summary>
Full name: SuaveMusicStore.View.details
Full name: SuaveMusicStore.Db.AlbumDetails
<summary> character varying(160)</summary>
Full name: Suave.Html.img
<summary> character varying(1024)</summary>
<summary> character varying(120)</summary>
<summary> character varying(120)</summary>
<summary> numeric</summary>
System.Decimal.ToString(provider: System.IFormatProvider) : string
System.Decimal.ToString(format: string) : string
System.Decimal.ToString(format: string, provider: System.IFormatProvider) : string
Full name: SuaveMusicStore.View.truncate
System.String.Substring(startIndex: int, length: int) : string
Full name: SuaveMusicStore.View.manage
Full name: SuaveMusicStore.Path.Admin.deleteAlbum
<summary> integer</summary>
Full name: SuaveMusicStore.View.deleteAlbum
Full name: Suave.Html.br
Full name: SuaveMusicStore.View.createAlbum
Full name: SuaveMusicStore.Form.album
Full name: Suave.Form.HtmlAttribute
Full name: Suave.Form.selectInput
Full name: SuaveMusicStore.View.notFound
Full name: SuaveMusicStore.View.index
Full name: Suave.Html.html
Full name: Suave.Html.head
Full name: Suave.Html.title
Full name: Suave.Html.body
Full name: Suave.Html.htmlToString
from SuaveMusicStore
from Suave
from Suave
from Suave
from Suave
from Suave
Full name: SuaveMusicStore.App.html
Full name: Suave.Successful.OK
from SuaveMusicStore
Full name: SuaveMusicStore.View.index
Full name: SuaveMusicStore.App.browse
Full name: Suave.Http.request
Full name: SuaveMusicStore.Db.getContext
Full name: SuaveMusicStore.Db.getAlbumsForGenre
Full name: SuaveMusicStore.View.browse
Full name: Suave.RequestErrors.BAD_REQUEST
Full name: SuaveMusicStore.App.overview
Full name: Suave.WebPart.warbler
Full name: SuaveMusicStore.Db.getGenres
Full name: Microsoft.FSharp.Collections.List.map
<summary> character varying(120)</summary>
Full name: SuaveMusicStore.View.store
Full name: SuaveMusicStore.App.details
Full name: SuaveMusicStore.Db.getAlbumDetails
Full name: SuaveMusicStore.View.details
Full name: Suave.WebPart.never
Full name: SuaveMusicStore.App.manage
Full name: SuaveMusicStore.Db.getAlbumsDetails
Full name: SuaveMusicStore.View.manage
Full name: SuaveMusicStore.App.createAlbum
Full name: Suave.WebPart.choose
Full name: Suave.Filters.GET
<summary> integer</summary>
Full name: SuaveMusicStore.Db.getArtists
<summary> integer</summary>
<summary> character varying(120)</summary>
Full name: SuaveMusicStore.View.createAlbum
Full name: SuaveMusicStore.App.deleteAlbum
Full name: SuaveMusicStore.Db.getAlbum
Full name: SuaveMusicStore.View.deleteAlbum
Full name: Suave.Filters.POST
Full name: SuaveMusicStore.Db.deleteAlbum
from Suave
Full name: Suave.Redirection.FOUND
Full name: SuaveMusicStore.App.webPart
Full name: Suave.Filters.path
Full name: SuaveMusicStore.View.home
Full name: Suave.Filters.pathScan
Full name: Suave.Filters.pathRegex
from Suave
Full name: Suave.Files.browseHome
Full name: SuaveMusicStore.View.notFound
Full name: Suave.Web.startWebServer
Full name: Suave.Web.defaultConfig
Show code from this section on GitHub