Building a Pokedex app with Kotlin, KVision and Redux (part 2)
Tags: kvision, kotlin, redux, webdev
Published: 2019-04-11 11:51:17

---
title: Building a Pokedex app with Kotlin, KVision and Redux (part 2)
published: true
description: This guide shows how to build a web application with KVision and Redux.
tags: kvision,kotlin,redux,webdev
---

Hello again :)

In the [first part of this article](https://dev.to/rjaros/building-a-pokedex-app-with-kotlin-kvision-and-redux-part-1-51h5) we have designed the Redux model for our application. Everything is ready, the Pokémons are downloading, but there is nothing on the screen. We need to create a GUI. 

Remember, you can find [the complete application](https://rjaros.github.io/kvision-examples/pokedex/) and all the sources in the [kvision-examples](https://github.com/rjaros/kvision-examples) GitHub repository.

# The GUI

The user interface of our application consists of four parts:

- A search input field.
- An information text (visible during loading process and in case of an error).
- A responsive grid of boxes for selected Pokémons.
- Pagination buttons.

We can use the following skeleton of the `start` method, which is the entry point of our app and takes care of the GUI creation. The `stateBinding` method is the core part of the Redux architecture in KVision. It makes all the components inside the given container become functions of the state, automatically refreshed when the state changes.

```kotlin
    override fun start(state: Map<String, Any>) {
        root = Root("kvapp") {
            vPanel(alignItems = FlexAlignItems.STRETCH) {
                searchField()
                vPanel(alignItems = FlexAlignItems.STRETCH) {
                    maxWidth = 1200.px
                    textAlign = TextAlign.CENTER
                    marginLeft = auto
                    marginRight = auto
                }.stateBinding(store) { state -> // !!! Redux binding is here !!!
                    informationText(state)
                    pokemonGrid(state)
                    pagination(state)
                }
            }
        }
        store.dispatch(downloadPokemons())
    }
```
As you can see, we can delegate most of the work to some smaller methods (all of them are extension methods for the `Container` class).

# The search input field

The `searchField` method is responsible for instantiating `Text` component. The event listener dispatches `SetSearchString` Redux action when the user enters some text into the field. 

```kotlin
    private fun Container.searchField() {
        text {
            placeholder = "Enter pokemon name ..."
            width = 300.px
            marginLeft = auto
            marginRight = auto
            autofocus = true
            setEventListener<Text> {
                input = {
                    store.dispatch(PokeAction.SetSearchString(self.value))
                }
            }
        }
    }
```

# The information text

The `informationText` method is responsible for displaying "Loading ..." label or an error message.

```kotlin
    private fun Container.informationText(state: Pokedex) {
        if (state.downloading) {
            div("Loading ...")
        } else if (state.errorMessage != null) {
            div(state.errorMessage)
        }
    }
```

# The grid

First let's design the box, which will display the name and the picture of the single Pokémon. We will declare a new class inheriting from a `DockPanel` container and a `Style` object with some CSS properties. The `PokeBox` class is fairly simple - it has just two child components - an Image and a Div. We apply the style by using `addCssClass` method.

```kotlin
val pokeBoxStyle = Style {
    border = Border(1.px, BorderStyle.SOLID, Col.GRAY)
    width = 200.px
    height = 200.px
    margin = 10.px

    style("img") {
        marginTop = 30.px
    }

    style("div.caption") {
        textAlign = TextAlign.CENTER
        background = Background(Col.SILVER)
        width = 100.perc
    }
}

class PokeBox(pokemon: Pokemon) : DockPanel() {
    init {
        addCssClass(pokeBoxStyle)
        image(
            "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.url.substring(34,pokemon.url.length - 1)}.png",
            centered = true
        )
        add(Div(pokemon.name.capitalize(), classes = setOf("caption")), Side.DOWN)
    }
}
```

The `pokemonGrid` method is responsible for rendering the CSS grid with a single `PokeBox` object inside every cell. It uses the `GridPanel` component with an appropriate `templateColumns` property value to make it responsive.

```kotlin
    private fun Container.pokemonGrid(state: Pokedex) {
        if (!state.downloading && state.errorMessage == null) {
            gridPanel(
                templateColumns = "repeat(auto-fill, minmax(250px, 1fr))",
                justifyItems = GridJustify.CENTER
            ) {
                state.visiblePokemons.forEach {
                    add(PokeBox(it))
                }
            }
        }
    }
```

# The pagination

The pagination is created by the following method, using `ButtonGroup` and `Button` KVision components. Both "next" and "previous" buttons are disabled when necessary and both dispatch suitable Redux actions.

```kotlin
    private fun Container.pagination(state: Pokedex) {
        if (!state.downloading && state.errorMessage == null) {
            hPanel(justify = FlexJustify.CENTER) {
                margin = 30.px
                buttonGroup {
                    button("<<") {
                        disabled = state.pageNumber == 0
                        onClick {
                            store.dispatch(PokeAction.PrevPage)
                        }
                    }
                    button(" ${state.pageNumber + 1} / ${state.numberOfPages} ", disabled = true)
                    button(">>") {
                        disabled = state.pageNumber == (state.numberOfPages - 1)
                        onClick {
                            store.dispatch(PokeAction.NextPage)
                        }
                    }
                }
            }
        }
    }
```

# Final words

Our application is ready. We've created the whole GUI with about 100 lines of code (half of the [original](https://github.com/alik0211/pokedex) JavaScript project). KVision really gives you "the best of both worlds" - modern, expressive language, with lots of reusable components, that can be used with well known patterns and libraries like Redux.

The [complete application](https://rjaros.github.io/kvision-examples/pokedex/) in the [GitHub repository](https://github.com/rjaros/kvision-examples/tree/master/pokedex) has some small additions, not mentioned in this article (touch gestures, I18n) and is also a fully compatible [Progressive Web App (PWA)](https://developers.google.com/web/progressive-web-apps/).

Thank you for reading this article and hope I'll catch you in the next one!

Cheers :)