Reputation: 247
I am trying to learn elm from the past week and want build a simple Hacker News client by calling the official Hacker News API.
I'm calling https: //hacker-news.firebaseio.com/v0/topstories.json to get the top stories which would return an array of story Ids. Once I have the Ids I need to make subsequent calls to https ://hacker-news.firebaseio.com/v0/item/[/* Id goes here */].json fetch the details of each story item.
I have a Main.elm file which would fetch list of top stories.
type Msg = Request
| RequestSuccess (List Int)
| RequestFail Http.Error
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Request ->
(model, getTopNews)
RequestSuccess list->
(Model list, Cmd.none)
RequestFail error->
(Model [], Cmd.none)
Next part is where I am confused, fetching details for each of the item returned. I also have a NewsItem component to display the details of each news item.
How can I solve this, by creating union types inside NewsItem component(child component) to fetch details? If thats how I should do it..
You can see what I have tried so far here.
Upvotes: 1
Views: 149
Reputation: 1207
Here's my recommendation. It assumes that you'll be loading each NewsItem
independently and that they can all fail independently as well. If this isn't the case then we can definitely come up with something that works better for you.
1) Represent your NewsItem
not as just a record but a record wrapped in a type to represent the possibility that loading the details could fail. See http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html for more info.
module NewsItem
-- imports and such
type Model = Loading | Success NewsItem | Failure Http.Error
2) Write an init
function in your NewsItem
module that accepts an Int
and returns a (NewsItem.Model, Cmd NewsItem.Msg)
pair
init : Int -> (Model, Cmd Msg)
init newsItemId =
( Loading
, getNewsItem newsItemId |> Task.perform GetItemFailure GetItemSuccess
)
3) In your Main
module, once you've fetched your list of IDs, map them onto a List (NewsItem.Model, Cmd NewsItem.Msg)
using your init
function and use the techniques of the Elm architecture to store them as children in your parent model. I recommend storing them as a Dict Int NewsItem.Model
which maps ID onto child model.
RequestSuccess list ->
let
children =
list |> List.map (\id -> (id, NewsItem.init id))
childModels =
children
|> List.map (\(id, (model, cmd)) -> (id, model))
|> Dict.fromList
childCmds =
children
|> List.map (\(id, (model, cmd)) -> Cmd.map (NewsItemMsg id) cmd)
|> Cmd.batch
in
(Model childModels, childCmds)
Upvotes: 1