Since there is no select or dropdown component backed in into elm-ui, we will be adding another dependency to our project called PaackEng/elm-ui-dropdown
and adding to it additional styles and settings so that it looks and behaves exactly as we want to.
To make this works, we need to make a few changes:
dropdownState : Dropdown.State String
to our Model
Msg
type: OptionPicked (Maybe String)
, to be dispatched by our dropdown whenever we click on any option, and DropdownMsg (Dropdown.Msg String)
to update the internal state of the dropdown from the outside.List String
.dropdownConfig : Dropdown.Config String Msg
that is going to contain all our customisation of our dropdown.Dropdown.view
to display our custom dropdown wherever we need it.Flavio Corpa: [0:00] We're going to now turn our compare button into an actual fully working dropdown. We need to stop the server and say elm install PaackEng/elm-ui-dropdown. We say yes. Now we can run the app in. I'm going to scroll to the top and say import dropdown.
[0:17] We need a few things to make this work. First, we're going to store here the dropdownState. We're going to say that this is dropdownState, and the state for our dropdown is going to be a String.
[0:29] We need to initialize this with Dropdown.init. We're going to say, "my-dropdown." Then we need a couple messages to make this work, Maybe String, and we need another one called DropdownMsg, which is going to contain the internal messages for the dropdown.
[0:49] We can better match on the messages and say that on Model op we're going to do nothing. On OptionPicked, we're going to do also nothing for now, but on DropdownMsg, we're going to do some stuff.
[1:02] You can copy this code from the library but basically, we need to call here Dropdown.update, and call a function called dropdownConfig that we're going to define later, pass this subMsg and pass the model.dropdownState, and our options. We don't have options yet, but we'll define it later.
[1:22] Here we're going to say in { model | dropdownState = state }, and the message that we're going to send is the message that it's here. In the case for OptionPicked, we are also not going to do anything for now.
[1:37] We're just going to go ahead and construct our fake list of options, which is going to be a list of Strings. We're going to say List.range 1 10. We want List.map (\item) and we want the string "Option" with String.fromInt from the item. This way, we create a fake list of [inaudible] options.
[1:59] Options is good to go, and we need to define dropdownConfig. We're going to say dropdownConfig is going to be Dropdown.Config with a String and it's going to send a message. Now we're going to define a let binding, itemToElement, and this takes selected highlighted item.
[2:20] For now, we're going to say just text item and we're going to say that Dropdown.multi takes a DropdownMsg, takes an OptionPicked. Always displays a button. This is the element that appears in the prompt and it's going to be using this itemToElement function.
[2:36] Now we can go to our card and replace the button that we were using by dropdown.field, dropdownConfig model.dropdownState and pass in the options. As you're noticing, we are not passing anywhere the model to our viewCards. We need to make it explicit here, model.
[2:57] In our dashboard, we are not passing either our model to our viewCards. Now we pass it here as well. Dashboard needs a model. We're going to pass it here. Then, in the view, the main function, we have the model. We can say here that we received here the model. We need to pass it down to all of the cards. ViewCard needs the model, this one too, this one too, and this one too, perfect.
[3:21] Now it's complaining. If we have a look at the error, it's mentioning that our viewCard function returns an element of message, but what we're expecting is the actual message that we're using in the application. Also, our dashboard has the same problem. We change it here, and now it should work.
[3:40] We have our dropdown, but it's not exactly looking good yet. We need to go back to our dropdownConfig. Here, we're going to say Dropdown.withPromptElement. We're going to say that it's our button. We're going to create another thing called listAttrs, which is going to be Background.color white, Border.rounded 5, padding 20, spacing 20, alignRight, and we want to have a height (px 220).
[4:13] We can pass another property to our dropdown and say Dropdown.withListAttributes and pass listAttrs. As you see, the list has a bit more color, and we need to continue passing things. We want to display the scrollbarX and as you notice now, we can display the scrollbar. This is how easy it is to display a scrollbar with Elm-UI.
[4:37] We need another list that we're going to call selectAttrs. It's going to contain pointer, because we want the cursor to be a pointer, paddingXY is going to be 13 7, the Background.color is going to be (rgb255 224 228 237), Border.rounded is going to be 15, Font.letterSpacing is going to be 1 and the Font.size is going to be 16.
[5:06] We want the element to be focused, have a different Background.color of (rgb255 25 45 91) and the Font.color to be white. We're going to pass this list of attributes as well to our dropdown, Dropdown.withSelectAttributes. Now our button is looking good.
[5:27] Finally, we can customize the arrows to be up and down. We need one more thing that we're going to call arrow icon. There is going to be an el [ Font.size 7, paddingEach { edges | left = 5 }] . We're going to contain the icon here.
[5:45] We're going to say we want again the Dropdown.withOpenCloseButtons. The openButton is going to be an arrow with the text of "▼" and the closeButton is going to be an arrow with the text of "▲". Our dropdown is looking great right now.
[6:04] Since we're no longer using our previous button, but the dropdown contains the button, now we need to go back here and add an additional element and say that we want alignTop, and alignRight, perfect. Our dropdown is looking good.
[6:19] We can see our options now, but let's go back to the dropdown and change the itemToElement. Now we want to use Input.checkbox. This needs a few things. onChange, we don't want to do anything, this is going to be a no-op. The icon is going to be Input.defaultCheckbox, checked is going to be false for now.
[6:40] For the label, we want to use Input.labelRight. Then we can choose the side of the label. It needs some attributes, and then the text that we had before.
[6:49] On our onChange method, you notice that it needs to take a Bool and return a message. We're going to go back to our no-op and say it's going to take a Bool. We don't want to react when the checkbox is clicked because the dropdown is going to have its own state. We can ignore the item here. Now it's going to work and we're able to see the checkboxes.
[7:08] Since we're marking them checked always, we cannot actually mark them. This can be changed by saying selected. Yes, this should work. We wanted more. Label we wanted to have paddingEach { edges | left = 7 } to have a bit more space, perfect.
[7:25] I just noticed the reason why the button doesn't work correctly is because here in our selectAttrs, we put rgb instead of rgb255, which has the blue color.
[7:35] Now our dropdowns are good to go.