# SPA ports on page init

**URL:** <https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198>\
**Category:** Request Feedback\
**Created:** [October 12, 2018, 8:07pm UTC](https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198 "2018-10-12T20:07:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![simplystuart](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/simplystuart/32/681_2.png) [@simplystuart](https://discourse.elm-lang.org/u/simplystuart)\
**Post date:** [October 12, 2018, 8:07pm UTC](https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198/1 "2018-10-12T20:07:15Z")

</div>

I recently ran into a situation that was tripping me up, so I thought I’d share the solution here in case it’s not common sense.

**First a little background:**

I needed to call out to a port when initializing a page in order to load audio. The port takes a url from the page, loads it as audio, and then sends audio metadata back to the page. What was interesting was that the port worked fine until I added a command to another page on init.

**The port worked in this example scenario:**

Main.elm:

```auto
type Page
    = Home Home.Model
    | Inner Inner.Model
    | NotFound

type alias Model =
    { key : Nav.Key, page : Page }

...

subscriptions : Model -> Sub Msg
subscriptions model =
    case model.page of
        Inner model_ ->
            Sub.map InnerMsg <| Inner.subscriptions model_

        _ ->
            Sub.none

```

Page/Home.elm:

```auto
init : ( Model, Cmd Msg )
init =
    ( Model Success, Cmd.none )

```

Page/Inner.elm:

```auto
port innerPortCmd : E.Value -> Cmd msg

port innerPortSub : (E.Value -> msg) -> Sub msg

...

init : ( Model, Cmd Msg )
init =
    ( Model Loading, innerPortCmd <| E.int 0 )

...

subscriptions : Model -> Sub Msg
subscriptions model =
    innerPortSub <| GotInnerPort << D.decodeValue D.int

```

* * *

**The port did not work when I added a command to a separate page on init:**

Page/Home.elm:

```auto
init : ( Model, Cmd Msg )
init =
    -- ( Model Success, Cmd.none )
    ( Model Loading, Task.perform GotTime Time.now )

```

Page/Inner.elm:

```auto
subscriptions : Model -> Sub Msg
subscriptions model =
    -- this never got called
    innerPortSub <| GotInnerPort << D.decodeValue D.int

```

* * *

I should have realized that I couldn’t depend on `model.page` to be immediately up to date (in Main.elm subscriptions), but since I encountered the above behavior I had to scratch my head for awhile…

**To fix the issue I used Process.sleep 0:**

Page/Inner.elm

```auto
init : ( Model, Cmd Msg )
init =
    ( Model Loading, Task.perform Ready <| Process.sleep 0 )

...

type Msg
    = GotInnerPort (Result D.Error Int)
    | Ready ()

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotInnerPort result ->
            case result of
                Err _ ->
                    ( model, Cmd.none )

                Ok num ->
                    ( Model (Success num), Cmd.none )

        Ready _ ->
            ( model, innerPortCmd <| E.int 0 )

```

* * *

This ensures that the model in Main.elm subscriptions has the correct page when the port is called!

Here is the full working example if anyone is interested: [https://github.com/simplystuart/elm-ports-spa-example](https://github.com/simplystuart/elm-ports-spa-example)

I’m also curious to know if there is a better way to do this. Thanks!

---

<div class="post-metadata">

**Author:** ![jessta](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jessta/32/660_2.png) [@jessta](https://discourse.elm-lang.org/u/jessta)\
**Post date:** [October 13, 2018, 4:07am UTC](https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198/2 "2018-10-13T04:07:48Z")

</div>

This looks like a bug to me.

`subscriptions` is called by the runtime after `update` and so should get value for model returned from the last call to `update`. The extra call to `update` you’ve added by having the `Ready` msg has allowed `subscriptions` again with the value of `model` returned from the previous call to `update`

It looks like it’s already been reported.

> <https://github.com/elm/core/issues/993>

---

<div class="post-metadata">

**Author:** ![gyzerok](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gyzerok/32/898_2.png) [@gyzerok](https://discourse.elm-lang.org/u/gyzerok)\
**Post date:** [October 13, 2018, 11:28am UTC](https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198/3 "2018-10-13T11:28:19Z")

</div>

Does it look similar to [https://github.com/elm/core/issues/896](https://github.com/elm/core/issues/896) to you? Would it work just fine in your case if you change ports declaration order?

---

<div class="post-metadata">

**Author:** ![simplystuart](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/simplystuart/32/681_2.png) [@simplystuart](https://discourse.elm-lang.org/u/simplystuart)\
**Post date:** [October 15, 2018, 1:44pm UTC](https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198/4 "2018-10-15T13:44:35Z")

</div>

@gyzerok, switching the order in which my ports are declared did not solve the issue, so I’m assuming this is related to the issue @jessta mentions. Thank you both!

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [October 25, 2018, 1:44pm UTC](https://discourse.elm-lang.org/t/spa-ports-on-page-init/2198/5 "2018-10-25T13:44:39Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
