diff --git a/examples/pokedex/app/Route/TailwindForm.elm b/examples/pokedex/app/Route/TailwindForm.elm index f0aedd2c..40a96455 100644 --- a/examples/pokedex/app/Route/TailwindForm.elm +++ b/examples/pokedex/app/Route/TailwindForm.elm @@ -38,6 +38,7 @@ type alias Model = type Msg = FormMsg Form.Msg | MovedToTop + | OnAction ActionData type alias RouteParams = @@ -558,6 +559,7 @@ route = , init = init , subscriptions = \_ _ _ _ _ -> Sub.none } + |> RouteBuilder.withOnAction OnAction action : RouteParams -> Parser (DataSource (Response ActionData ErrorPage)) @@ -583,6 +585,9 @@ update _ _ static msg model = MovedToTop -> ( model, Effect.none ) + OnAction actionData -> + loadActionData (Just actionData) + withFlash : Result String String -> ( Model, effect ) -> ( Model, effect ) withFlash flashMessage ( model, cmd ) = @@ -594,9 +599,13 @@ init _ _ static = _ = Debug.log "@@@static.action" static.action in - ( { form = static.action |> Maybe.map .initialForm |> Maybe.withDefault (Form.init (form defaultUser)) + loadActionData static.action + + +loadActionData maybeActionData = + ( { form = maybeActionData |> Maybe.map .initialForm |> Maybe.withDefault (Form.init (form defaultUser)) , flashMessage = - static.action + maybeActionData |> Maybe.map (\actionData -> if Form.hasErrors actionData.initialForm then diff --git a/generator/src/RouteBuilder.elm b/generator/src/RouteBuilder.elm index ddef373a..50d47f11 100644 --- a/generator/src/RouteBuilder.elm +++ b/generator/src/RouteBuilder.elm @@ -1,6 +1,7 @@ module RouteBuilder exposing ( StatelessRoute, buildNoState , StaticPayload + , withOnAction , buildWithLocalState, buildWithSharedState , preRender, single , preRenderWithFallback, serverRender @@ -38,6 +39,8 @@ We have the following data during pre-render: @docs StaticPayload +@docs withOnAction + ## Stateful Route Modules @@ -119,6 +122,7 @@ type alias StatefulRoute routeParams data action model msg = , subscriptions : Maybe PageUrl -> routeParams -> Path -> model -> Shared.Model -> Sub msg , handleRoute : { moduleName : List String, routePattern : RoutePattern } -> (routeParams -> List ( String, String )) -> routeParams -> DataSource (Maybe NotFoundReason) , kind : String + , onAction : Maybe (action -> msg) } @@ -182,9 +186,18 @@ buildNoState { view } builderState = , subscriptions = \_ _ _ _ _ -> Sub.none , handleRoute = record.handleRoute , kind = record.kind + , onAction = Nothing } +{-| -} +withOnAction : (action -> msg) -> StatefulRoute routeParams data action model msg -> StatefulRoute routeParams data action model msg +withOnAction toMsg config = + { config + | onAction = Just toMsg + } + + {-| -} buildWithLocalState : { view : @@ -227,6 +240,7 @@ buildWithLocalState config builderState = config.subscriptions maybePageUrl routeParams path sharedModel model , handleRoute = record.handleRoute , kind = record.kind + , onAction = Nothing } @@ -265,6 +279,7 @@ buildWithSharedState config builderState = config.subscriptions maybePageUrl routeParams path sharedModel model , handleRoute = record.handleRoute , kind = record.kind + , onAction = Nothing } diff --git a/generator/src/generate-template-module-connector.js b/generator/src/generate-template-module-connector.js index 2a57e2bb..5521d657 100644 --- a/generator/src/generate-template-module-connector.js +++ b/generator/src/generate-template-module-connector.js @@ -562,6 +562,7 @@ config = } , data = dataForRoute , action = action + , onActionData = onActionData , sharedData = Shared.template.data , apiRoutes = ${ phase === "browser" @@ -590,6 +591,26 @@ config = , notFoundRoute = Nothing } +onActionData actionData = + let + _ = Debug.log "onActionData" actionData + in + case actionData of +${templates + .map( + (name) => ` ActionData${pathNormalizedName(name)} thisActionData -> + Route.${name.join( + "." + )}.route.onAction |> Maybe.map (\\onAction -> onAction thisActionData) |> Maybe.map Msg${pathNormalizedName( + name + )} + +` + ) + .join("\n")} + + + globalHeadTags : DataSource (List Head.Tag) globalHeadTags = (Site.config.head diff --git a/src/Pages/Internal/Platform.elm b/src/Pages/Internal/Platform.elm index a4c5b338..c60cbcfd 100644 --- a/src/Pages/Internal/Platform.elm +++ b/src/Pages/Internal/Platform.elm @@ -367,12 +367,14 @@ update config appMsg model = ) UrlChanged url -> - let - navigatingToSamePage : Bool - navigatingToSamePage = - url.path == model.url.path - in - if navigatingToSamePage then + -- TODO is this logic always what we want? This prevents `init` from being called when an action is submitted + -- but maybe it's best to avoid calling `pushUrl` in the first place in these cases? + if url == model.url then + ( model + , NoEffect + ) + + else if url.path == model.url.path then -- this saves a few CPU cycles, but also -- makes sure we don't send an UpdateCacheAndUrl -- which scrolls to the top after page changes. @@ -489,8 +491,12 @@ update config appMsg model = | url = newUrl , pageData = Ok updatedPageData } + + onActionMsg : Maybe userMsg + onActionMsg = + newActionData |> Maybe.andThen config.onActionData in - case maybeUserMsg of + (case maybeUserMsg of Just userMsg -> ( { updatedModel | ariaNavigationAnnouncement = mainView config updatedModel |> .title @@ -519,6 +525,14 @@ update config appMsg model = NoEffect ] ) + ) + |> (case onActionMsg of + Just actionMsg -> + withUserMsg config actionMsg + + Nothing -> + identity + ) Err _ -> {- diff --git a/src/Pages/ProgramConfig.elm b/src/Pages/ProgramConfig.elm index 0261f192..95da8535 100644 --- a/src/Pages/ProgramConfig.elm +++ b/src/Pages/ProgramConfig.elm @@ -47,6 +47,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData , sharedData : DataSource sharedData , data : route -> DataSource (PageServerResponse pageData errorPage) , action : route -> DataSource (PageServerResponse actionData errorPage) + , onActionData : actionData -> Maybe userMsg , view : { path : Path , route : route