Skip to content

Commit

Permalink
Simplify logic
Browse files Browse the repository at this point in the history
  • Loading branch information
amitaibu committed Oct 31, 2023
1 parent 872b3ae commit 0d923b3
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 76 deletions.
21 changes: 7 additions & 14 deletions Guide/form.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -666,26 +666,19 @@ formFor subscription [hsx|
allContentTypes = allEnumValues @ContentType
```

### Force Seelction of Custom Enums
### Set Default Value for Custom Enums

You will notice that if we use `selectField` on enums, the first enum value is always selected. The reason is that the select field is always displaying the value it gets from the model passed to `formFor`.
When creating a new record, by default the field value will be empty. If you'd like to set a default enum, you can set it from the controller.

For a new record, that value will always be the first enum. And the reason lies in the `newRecord @Record` call in the controller. The `newRecord` creates an empty record setting all fields to a default empty value.
The default empty value for UUIDs is `00000000-0000-0000-0000-000000000000` and the default empty value for enums is the first enum value.

Now, if we have a required field, and we want to make sure the user selects a value, in the same way they have to select for a reference field.
So we check if the model is new and the field was not submitted yet, then we set the field value to an empty string. Otherwise, we use the value from the model.
Note that by default the `newRecord` populates the first enum on the record. However, when showing the form, IHP will check if the field was not explicetly set, and if so, will not render the default value.

```haskell
formFor subscription [hsx|
{selectFieldEmptyFieldValueWhenIsNew #contentType allContentTypes}
|]
where
allContentTypes = allEnumValues @ContentType
action NewPostAction = do
let post = newRecord
let postWithDefault = newRecord |> set #postType Article
render NewView { .. }
```

You can use radio buttons using the `radioFieldEmptyFieldValueWhenIsNew`

### Select Inputs with Integers

It's a common use case to have a select field consisting of ints, e.g. inside a shopping cart to select the quantity of an item.
Expand Down
62 changes: 0 additions & 62 deletions IHP/View/Form.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import IHP.View.Types
import IHP.View.Classes ()
import Network.Wai (pathInfo)
import IHP.Controller.Context
import IHP.Controller.Param (paramList)

-- | Forms usually begin with a 'formFor' expression.
--
Expand Down Expand Up @@ -723,7 +722,6 @@ checkboxField field = FormField
-- > render NewView { .. }
selectField :: forall fieldName model item.
( ?formContext :: FormContext model
, ?context :: ControllerContext
, HasField fieldName model (SelectValue item)
, HasField "meta" model MetaBag
, KnownSymbol fieldName
Expand Down Expand Up @@ -765,41 +763,6 @@ selectField field items = FormField
FormContext { model } = ?formContext
{-# INLINE selectField #-}

{- Select field where @fieldValue@ is empty text when the model is new.
You will notice that if we use `selectField` on enums, the first enum value is always selected.
The reason is that the select field is always displaying the value it gets from the
model passed to @formFor@.
For a new record, that value will always be the first enum. And the reason lies in the newRecord @Record call in the controller.
The @newRecord@ creates an empty record setting all fields to a default empty value.
The default empty value for UUIDs is 00000000-0000-0000-0000-000000000000 and the default empty value for enums is the first enum value.
Now, if we have a required field, and we want to make sure the user selects a value, in the same way they have to select for a reference field.
So we check if the model is new and the field was not submitted yet, then we set the field value to an empty string. Otherwise, we use the value from the model.
-}
selectFieldEmptyFieldValueWhenIsNew :: forall fieldName model item.
( ?formContext :: FormContext model
, ?context :: ControllerContext
, HasField fieldName model (SelectValue item)
, HasField "meta" model MetaBag
, KnownSymbol fieldName
, KnownSymbol (GetModelName model)
, CanSelect item
, InputValue (SelectValue item)
, Typeable model
, Eq (SelectValue item)
) => Proxy fieldName -> [item] -> FormField
selectFieldEmptyFieldValueWhenIsNew field items = (selectField field items)
{ fieldValue = if isNew model && isEmpty (paramList @Text (cs fieldName))
then ""
else inputValue (getField @fieldName model :: SelectValue item)
}
where
fieldName = symbolVal field
FormContext { model } = ?formContext
{-# INLINE selectFieldEmptyFieldValueWhenIsNew #-}

-- | Radio require you to pass a list of possible values to select. We use the same mechanism as for for 'selectField'.
--
-- > formFor project [hsx|
Expand Down Expand Up @@ -843,7 +806,6 @@ selectFieldEmptyFieldValueWhenIsNew field items = (selectField field items)
-- > render NewView { .. }
radioField :: forall fieldName model item.
( ?formContext :: FormContext model
, ?context::ControllerContext
, HasField fieldName model (SelectValue item)
, HasField "meta" model MetaBag
, KnownSymbol fieldName
Expand All @@ -864,30 +826,6 @@ radioField field items = (selectField field items)
}
{-# INLINE radioField #-}

{- Radio field where @fieldValue@ is empty text when the model is new.
See `selectFieldEemptyFieldValueWhenIsNew` for more details.
-}
radioFieldEmptyFieldValueWhenIsNew :: forall fieldName model item.
( ?formContext :: FormContext model
, ?context::ControllerContext
, HasField fieldName model (SelectValue item)
, HasField "meta" model MetaBag
, KnownSymbol fieldName
, KnownSymbol (GetModelName model)
, CanSelect item
, InputValue (SelectValue item)
, Typeable model
, Eq (SelectValue item)
) => Proxy fieldName -> [item] -> FormField
radioFieldEmptyFieldValueWhenIsNew field items = (radioField field items)
{ fieldValue = selectField.fieldValue
}
where
selectField = selectFieldEmptyFieldValueWhenIsNew field items

{-# INLINE radioFieldEmptyFieldValueWhenIsNew #-}

class CanSelect model where
-- | Here we specify the type of the @<option>@ value, usually an @Id model@
type SelectValue model :: GHC.Types.Type
Expand Down

0 comments on commit 0d923b3

Please sign in to comment.