Pass in fetcher for current Route as part of StaticPayload.

This commit is contained in:
Dillon Kearns 2022-05-10 10:16:09 -07:00
parent d608b34e91
commit 5b9fd32a7c
6 changed files with 113 additions and 11 deletions

View File

@ -28,7 +28,7 @@ type Effect msg
{ decoder : Result Http.Error Bytes -> msg
, fields : List ( String, String )
, headers : List ( String, String )
, url : String
, url : Maybe String
}
@ -111,7 +111,7 @@ perform :
{ decoder : Result Http.Error Bytes -> pageMsg
, fields : List ( String, String )
, headers : List ( String, String )
, url : String
, url : Maybe String
}
-> Cmd msg
, fromPageMsg : pageMsg -> msg

View File

@ -5,9 +5,13 @@ import Effect exposing (Effect)
import ErrorPage exposing (ErrorPage)
import Head
import Head.Seo as Seo
import Html
import Html.Attributes as Attr
import Http
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Path exposing (Path)
import Route
import RouteBuilder exposing (StatefulRoute, StatelessRoute, StaticPayload)
import Server.Request as Request
import Server.Response as Response exposing (Response)
@ -21,6 +25,7 @@ type alias Model =
type Msg
= NoOp
| GotResponse (Result Http.Error ActionData)
type alias RouteParams =
@ -51,23 +56,53 @@ action _ =
(field "email")
|> Request.map
(\( first, email ) ->
Success
validate
{ email = email
, first = first
}
|> Response.render
|> DataSource.succeed
)
)
validate : { first : String, email : String } -> Response ActionData ErrorPage
validate { first, email } =
if first /= "" && email /= "" then
Route.redirectTo Route.Signup
else
ValidationErrors
{ errors = [ "Cannot be blank" ]
, fields =
[ ( "first", first )
, ( "email", email )
]
}
|> Response.render
init :
Maybe PageUrl
-> Shared.Model
-> StaticPayload Data ActionData RouteParams
-> ( Model, Effect Msg )
init maybePageUrl sharedModel static =
( {}, Effect.none )
( {}
, static.submit
{ headers = []
, fields =
-- TODO when you run a Fetcher and get back a Redirect, how should that be handled? Maybe instead of `Result Http.Error ActionData`,
-- it should be `FetcherResponse ActionData`, with Redirect as one of the possibilities?
--[ ( "first", "Jane" )
--, ( "email", "jane@example.com" )
--]
[ ( "first", "" )
, ( "email", "" )
]
}
|> Effect.SubmitFetcher
|> Effect.map GotResponse
)
update :
@ -82,6 +117,13 @@ update pageUrl sharedModel static msg model =
NoOp ->
( model, Effect.none )
GotResponse result ->
let
_ =
Debug.log "GotResponse" result
in
( model, Effect.none )
subscriptions : Maybe PageUrl -> RouteParams -> Path -> Shared.Model -> Model -> Sub Msg
subscriptions maybePageUrl routeParams path sharedModel model =
@ -119,4 +161,27 @@ view :
-> StaticPayload Data ActionData RouteParams
-> View Msg
view maybeUrl sharedModel model static =
View.placeholder "Signup"
{ title = "Signup"
, body =
[ Html.p []
[ case static.action of
Just (Success { email, first }) ->
Html.text <| "Hello " ++ first ++ "!"
Just (ValidationErrors { errors }) ->
errors
|> List.map (\error -> Html.li [] [ Html.text error ])
|> Html.ul []
_ ->
Html.text ""
]
, Html.form
[ Attr.method "POST"
]
[ Html.label [] [ Html.text "First", Html.input [ Attr.name "first" ] [] ]
, Html.label [] [ Html.text "Email", Html.input [ Attr.name "email" ] [] ]
, Html.input [ Attr.type_ "submit", Attr.value "Signup" ] []
]
]
}

View File

@ -82,11 +82,13 @@ When there are Dynamic Route Segments, you need to tell `elm-pages` which pages
-}
import Bytes exposing (Bytes)
import DataSource exposing (DataSource)
import DataSource.Http
import Effect exposing (Effect)
import ErrorPage exposing (ErrorPage)
import Head
import Http
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
import Pages.Internal.RoutePattern exposing (RoutePattern)
import Pages.PageUrl exposing (PageUrl)
@ -131,6 +133,14 @@ type alias StaticPayload data action routeParams =
, routeParams : routeParams
, path : Path
, action : Maybe action
, submit :
{ fields : List ( String, String ), headers : List ( String, String ) }
->
{ decoder : Result Http.Error Bytes -> Result Http.Error action
, fields : List ( String, String )
, headers : List ( String, String )
, url : Maybe String
}
}

View File

@ -223,6 +223,9 @@ view page maybePageUrl globalData pageData actionData =
}
, action = actionDataOrNothing
, path = page.path
, submit = submitFetcher Route.${moduleName(
name
)}.w3_decode_ActionData
}
|> View.map Msg${pathNormalizedName(name)}
|> Shared.template.view globalData page model.global MsgGlobal
@ -238,6 +241,9 @@ view page maybePageUrl globalData pageData actionData =
, routeParams = ${emptyRouteParams(name) ? "{}" : "s"}
, action = Nothing
, path = page.path
, submit = submitFetcher Route.${moduleName(
name
)}.w3_decode_ActionData
}
`
}
@ -314,6 +320,9 @@ init currentGlobalModel userFlags sharedData pageData actionData navigationKey m
emptyRouteParams(name) ? "{}" : "routeParams"
}
, path = justPath.path
, submit = submitFetcher Route.${moduleName(
name
)}.w3_decode_ActionData
}
|> Tuple.mapBoth Model${pathNormalizedName(
name
@ -452,6 +461,9 @@ update sharedData pageData navigationKey msg model =
"routeParams"
)}
, path = justPage.path
, submit = submitFetcher Route.${moduleName(
name
)}.w3_decode_ActionData
}
msg_
pageModel
@ -478,6 +490,21 @@ update sharedData pageData navigationKey msg model =
)
.join("\n ")}
submitFetcher byteDecoder options =
{ decoder =
\\bytesResult ->
bytesResult
|> Result.andThen
(\\okBytes ->
okBytes
|> Bytes.Decode.decode byteDecoder
|> Result.fromMaybe (Http.BadBody "Couldn't decode bytes.")
)
, fields = options.fields
, headers = ("elm-pages-action-only", "true") :: options.headers
, url = Nothing
}
templateSubscriptions : Maybe Route -> Path -> Model -> Sub Msg
templateSubscriptions route path model =
@ -1335,7 +1362,7 @@ something :
{ decoder : Result Http.Error Bytes -> msg
, fields : List ( String, String )
, headers : List ( String, String )
, url : String
, url : Maybe String
}
something toMsg options =
{ decoder =
@ -1352,8 +1379,8 @@ something toMsg options =
, headers = ("elm-pages-action-only", "true") :: options.headers
, url = ${
fetcherPath === ""
? '"/content.dat"'
: `[ ${fetcherPath}, [ "content.dat" ] ] |> List.concat |> String.join "/"`
? 'Just "/content.dat"'
: `[ ${fetcherPath}, [ "content.dat" ] ] |> List.concat |> String.join "/" |> Just`
}
}
`;

View File

@ -702,7 +702,7 @@ perform config currentUrl maybeKey effect =
, tracker = Nothing
, body = Http.stringBody contentType body
, headers = options.headers |> List.map (\( name, value ) -> Http.header name value)
, url = options.url
, url = options.url |> Maybe.withDefault (Path.join [ currentUrl.path, "content.dat" ] |> Path.toAbsolute)
, method = "POST"
, timeout = Nothing
}

View File

@ -110,7 +110,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
{ decoder : Result Http.Error Bytes -> userMsg
, fields : List ( String, String )
, headers : List ( String, String )
, url : String
, url : Maybe String
}
-> Cmd mappedMsg
, key : Browser.Navigation.Key