Kotlin/kotlinx.html

Attribute value is not yet defined for tag input

renatoathaydes opened this issue · 4 comments

Got the following error trying to get the value of an input:

message: "Attribute value is not yet defined for tag input"

Code:

import kotlinx.browser.document
import kotlinx.html.div
import kotlinx.html.dom.append
import kotlinx.html.h2
import kotlinx.html.id
import kotlinx.html.input
import kotlinx.html.js.onKeyUpFunction
import kotlinx.html.style
import kotlinx.html.unsafe
import org.w3c.dom.HTMLElement

object HtmlIds {
    const val base58Result = "base58-result"
}

/**
 * Test application for the base58 library.
 *
 * It helps test that the code works on a browser.
 */
fun main() {
    byId("root").append {
        h2 {
            +"Enter some text:"
        }
        input {
            placeholder = "Text to encode to base58"
            onKeyUpFunction = { _ ->
                byId(HtmlIds.base58Result).textContent = value
            }
        }
        div {
            id = HtmlIds.base58Result
            style {
                unsafe { raw("padding: 10px; background: green; color: white") }
            }
        }
    }
}

private fun byId(id: String): HTMLElement {
    return (document.getElementById(id) as HTMLElement?)!!
}

A workaround for this is to define the onKeyUp() function after the declaration of the input tag, e.g.

        val input = input {
            placeholder = "Text to encode to base58"
        }
        input.onkeyup = { _ ->
            byId(base58Result).textContent = input.value
            asDynamic()
        }

@e5l some input on this would be worthwhile, because I'm not sure how to reconcile the fact that the input object within the builder block isn't the actual input object within the DOM - and thus, you're not getting the actual value field within the DOM object when you invoke value within the builder block - without some considerable refactoring.

e5l commented

@severn-everett, yep we can't make it without refactoring. Could you tell me if you have an idea on how to do that?

As workaround we can try introducing some property (like input { domItem.value } ) which will be resolved to actual dom item when it called. It also can cause error if the element is not initialized yet, so we need to check

It might be worth updating the onEvent callback signature in this codebase so that the actual DOM object gets passed in as well, so the user could then do something like:

        input {
            placeholder = "Text to encode to base58"
            onKeyUpFunction = { inputDOM, _ ->
                byId(HtmlIds.base58Result).textContent = inputDOM.value
            }
        }

Not the prettiest, but at least it'd minimize the amount of code that would need to get shuffled around behind the scenes.