1

I'm trying to listen to the "resize" event and change the image size accordingly. However the image size does not change. I think the reason is that my "onResize" function is at the wrong place. But I don't know where else to embed it in this framework. Sorry if this sounds trivial but I've been going through the docs for a long time and couldn't find a solution. The complete elm code is listed below:

module App where

import Html exposing (..)
import Html.Attributes exposing (attribute, class, style, src, width, height)
import Html.Events exposing (on)
import Json.Decode exposing (object2, (:=), int)
import StartApp.Simple exposing (start)


-- MODEL

type alias Model = 
  { width : Int
  , height : Int
  }

init : Model
init = { width = 800, height = 800 }

-- UPDATE

type Action = NewSize Int Int

update : Action -> Model -> Model
update (NewSize w h) model = 
  { model | width = w, height = h }

-- VIEW

view : Signal.Address Action -> Model -> Html
view address model =
  div
    [ class "container", onResize address ]
    [ div
      []
      [ img
        [ src "http://package.elm-lang.org/assets/elm_logo.svg"
        , width model.width
        , height model.height
        ]
        []
      ] 
    ]

onResize : Signal.Address Action -> Attribute
onResize address =
  on "resize" (getWidthHeight view) (\(w, h) -> Signal.message address (NewSize w h))

getWidthHeight : a -> Json.Decode.Decoder ( Int, Int )
getWidthHeight view =
  object2 (,) ("innerWidth" := int) ("innerHeight" := int)


-- MAIN

main : Signal Html
main =
  start
    { model = init
    , update = update
    , view = view
    }
Rudie
  • 52,220
  • 42
  • 131
  • 173
Charles Gao
  • 679
  • 2
  • 7
  • 13

1 Answers1

2

Some points about your solution.

  • The resize handler does appear to be getting attached to the right container. That's good.
  • You appear to be passing the view function as a parameter getWidthHeight.
    • This wont work but your getWidthHeight is actually not using it for anything anyway so it isn't hurting anything either I think.

I believe the view you want to use in getWidthHeight is part of the json decoder rules to access view to get to the window and then extract the innerWidth and innerHeight values. You are trying to get at view.innerWidth and view.innerHeight.

Given the description of the event properties for resize I'm pretty sure this is the decoder you want.

getWidthHeight : Json.Decode.Decoder (Int, Int)
getWidthHeight =
  object2
    (,)
    (Json.Decode.at ["view", "innerWidth"] int)
    (Json.Decode.at ["view", "innerHeight"] int)

However these changes I have applied locally and some others as well I have not got your example working yet, Still trying but I am missing something at the moment.

Alternate Hacky solution.

  • I tried a quick hack and got something that works but its a bit clunky.
  • I switched to StartApp from StartApp.Simple.
    • I did this so I could add a new input stream from Window.dimensions.
  • I then mapped Window.dimension events to the resize action you had.

This does not work for the initial window dimensions but once you start resizing you get it working.

module App where

import Effects exposing (Effects, Never)
import Html exposing (..)
import Html.Attributes exposing (attribute, class, style, src, width, height)
import StartApp exposing (start)
import Window


-- MODEL
type alias Model = 
  { width : Int
  , height : Int
  }

init : (Model, Effects Action)
init = 
  ( { width = 200
    , height = 200 }
    , Effects.none
  )

-- UPDATE
type Action = NewSize Int Int

update : Action -> Model -> (Model, Effects Action)
update (NewSize w h) model = 
  ( { model 
    | width = w
    , height = h 
    }
  , Effects.none
  )

-- VIEW

view : Signal.Address Action -> Model -> Html
view address model =
  div
    [ class "container" ] -- , onResize address ]
    [ div
      []
      [ img
        [ src "http://package.elm-lang.org/assets/elm_logo.svg"
        , width model.width
        , height model.height
        ]
        []
      ] 
    ]


main = 
  app.html

-- APP
app =
  start
    { init = init
    , update = update
    , view = view 
    , inputs = 
      [
        Signal.map (\(w,h) -> NewSize w h) Window.dimensions
      ]
    }


--port tasks : Signal (Task.Task Never ())
--port tasks =
--  app.tasks

Extra Info.

There are a bunch of useful examples of different things here http://elm-lang.org/examples. The example using Window.dimensions http://elm-lang.org/examples/resize-paint might help you understand things a bit.

Robin Luiten
  • 5,198
  • 3
  • 20
  • 24
  • Thanks! This is very helpful! I have a somewhat related design question. Suppose I wrap this image in another module and define its own Action of newsize. Now in the main module I import it, and would like to use the window signal to specify the size of the image. However since the newsize action of the image module is not exposed, how am I suppose to pass this information to it? – Charles Gao Jan 01 '16 at 22:36
  • 1
    I think working through this tutorial is probably your best bet. https://github.com/evancz/elm-architecture-tutorial/. It covers components and how to delegate stuff. As a rule I believe all your actions need to be accessible in a single type at your top level and it does the delegation to what the action causes to happen. Don't forget to vote :) – Robin Luiten Jan 02 '16 at 00:00