Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KVar not binding if Element ID is changed #164

Closed
DineshSolanki opened this issue Oct 3, 2020 · 17 comments
Closed

KVar not binding if Element ID is changed #164

DineshSolanki opened this issue Oct 3, 2020 · 17 comments
Labels

Comments

@DineshSolanki
Copy link
Member

DineshSolanki commented Oct 3, 2020

I tried to bind variable of type KVar, but it is not binding to the "src" attribute -

var imageString: KVar<String> = KVar("")
img("").setAttribute("src", imageString)
I also tried -

val imgElement =img("")
imgElement.setAttribute("src", imageString)

But to no avail. the value of imageString doesn't affect the src attribute. not even one directional

I also read the doc about img, and it said, "Kweb doesn't support internal routing yet, use external source". does that mean what I'm trying to achieve is not possible ?

@DineshSolanki
Copy link
Member Author

well, in fact, the src attribute is not changing programmatically even if I use a simple string as a value, it only works if given the value in the constructor

@sanity sanity added the bug label Oct 4, 2020
@sanity
Copy link
Member

sanity commented Oct 4, 2020

Hmm, will investigate - appreciate the bug report.

@DineshSolanki
Copy link
Member Author

Hmm, will investigate - appreciate the bug report.

thanks, and "changing src by javascript works"

@sanity
Copy link
Member

sanity commented Oct 4, 2020

Hmm, I'm having trouble replicating the bug. Here is what I tried:

import kweb.state.KVar

fun main() {
    Kweb(port = 5415) {
        doc.body.new {
            val counter = KVar(1)
            val imageString = counter.map { "$it.img" }
            img().setAttribute("src", imageString)
            button().let { button ->
                button.text("Increment")
                button.on.click {
                    counter.value++
                }
            }
        }
    }
}

The image is broken because it's not a valid URL, but looking at the inspector I do see <img src="1.img"> as expected, and the value increments when I click the button.

Would it be possible for you to share a complete main() function that replicates the issue you're seeing?

@sanity
Copy link
Member

sanity commented Oct 4, 2020

Oh, when you change the value of imageString, are you doing it with something like imageString = KVar("new value")? If so I think that's your problem, it should be imageString.value = "new value".

@DineshSolanki
Copy link
Member Author

Oh, when you change the value of imageString, are you doing it with something like imageString = KVar("new value")? If so I think that's your problem, it should be imageString.value = "new value".

No, I'm using imageString.value = "new value", as I have been using kvar at other input tags too.

@DineshSolanki
Copy link
Member Author

DineshSolanki commented Oct 5, 2020

I tried your snippet and tested it, and I think I found what caused it to break. -

import kweb.*
import kweb.state.KVar

fun main() {
    Kweb(port = 5415, debug = true)
    {
        doc.body.new {
            val counter = KVar(1)
            val imageString = counter.map { "$it.img" }
            img().setAttribute("src", imageString)
//                    .setAttributeRaw("id","imgFile")
            //input(type = InputType.number).setAttributeRaw("id","inp").setAttribute("max", imageString) //any element after this are not rendered.
            //input(type = InputType.number).setAttributeRaw("id","inp") //elements will be rendered
            input(type = InputType.number).setAttribute("max", imageString).setAttributeRaw("id","inp") //Elements will be rendered but KVar is somehow not binded
            button().let { button ->
                button.text("Increment")
                button.on.click {
                    counter.value++
                }
            }
            button().text("click me")
        }
    }
}

What I Found -

  • When an Id is set to an element, It somehow is unbinded from KVal (Maybe some internal routing bug) else it works
  • If Element.setAttributeRaw("id","anyid") is used on the element before attaching KVal to any of its attributes, all the elements after it would not be rendered. NO HTML CODE FOR THEM

@DineshSolanki
Copy link
Member Author

DineshSolanki commented Oct 5, 2020

input(type = InputType.number).let {
                it.setAttributeRaw("id","inp")  // if ID is set first, then elements will not be rendered , however if no ID is set, KVar binds correctly
                it.setAttribute("max", imageString) //If Kvar is set first then ID, in this case Elements will be rendered, but still KVal will not be binded
            } 

@DineshSolanki
Copy link
Member Author

also changing the value using javaScript doesn't update the binded KVar -
document.getElementById("Kg").value="1"; //this won't update the KVar binded to its Value attribute,
also which don't have a GUI input such as img, they will be unbinded from their KVar once modified by javascript.

@sanity
Copy link
Member

sanity commented Oct 6, 2020

Ah, yes - Kweb relies on the id attribute to reference the element, so if the id is changed afterwards then that probably would cause problems. It should work fine if the alternate id is provided in the Element constructor.

I'll need to give it some thought, it might be necessary to disallow setAttribute() or setAttributeRaw() for id, or provide some special case handling.

May I ask the reason you need to change an Element's id?

@sanity
Copy link
Member

sanity commented Oct 6, 2020

Re: document.getElementById("Kg").value="1"; not updating the Kvar, I think the reason for this is that the KVar is only updated when the input event is fired on the InputElement, and I don't think updating the element value from JavaScript will do this.

This is the relevant code: https://github.com/kwebio/kweb-core/blob/master/src/main/kotlin/kweb/prelude.kt#L214

@DineshSolanki
Copy link
Member Author

DineshSolanki commented Oct 6, 2020

Re: document.getElementById("Kg").value="1"; not updating the Kvar, I think the reason for this is that the KVar is only updated when the input event is fired on the InputElement, and I don't think updating the element value from JavaScript will do this.

This is the relevant code: https://github.com/kwebio/kweb-core/blob/master/src/main/kotlin/kweb/prelude.kt#L214

yes, I figured, although when KVar is binded, changing via javascript seems redundant, in my case I need to change it using javascript at least once.

@DineshSolanki
Copy link
Member Author

DineshSolanki commented Oct 6, 2020

Ah, yes - Kweb relies on the id attribute to reference the element, so if the id is changed afterward then that probably would cause problems. I'll need to give it some thought.

I got around it using, the id that Kweb assigns, and I think this behavior can be worked around most of the time. and setAtrribute/setAttributeRaw() for id should not be restricted, as not always KVar will be used. although this statement should be made into docs that this doesn't work so don't set id if using KVar on the element.

@DineshSolanki
Copy link
Member Author

DineshSolanki commented Oct 6, 2020

and I would like some help, currently, I'm reading a file from a [input type= file], so I'm using FileReader API, which doesn't let me properly return the result data so I have to manipulate the dom in the Reader's Load event which is javascript code. that's why my src unbinds from KVar even if I worked around ID.
Here's my javascript -

fun showImage(idOfImg: String): String = """function previewFile(e) {
  const preview = document.getElementById("$idOfImg");
  const file = e.files[0];
  const reader = new FileReader();
  reader.addEventListener("load", function () {
    preview.src = reader.result;
  }, false);

  if (file) {
    reader.readAsDataURL(file); 
}
}"""

and here's how I'm using it. -

doc.body.new {
input(InputType.file).let {
it.setAttributeRaw("onChange", "previewFile(this);")
}
val imgElement = img()
doc.head.new {
 element("script").text(showImage(imgElement.id))
}
}

although working, I would want it to do in Kweb/Kotlin style.
if somehow I could use fileReader without using this script then I could bind the value to KVar and as I wouldn't be using direct javascript but Kweb to manipulate values, the problem of Kvar detaching would be gone.

@DineshSolanki
Copy link
Member Author

I'm looking to do something Like this -

var imageString = KVar("")
        doc.body.new {
            input(InputType.file).let { fileInput ->
                fileInput.on.change {
                    val file = fileInput.files[0]
                    val reader = FileReader()
                    reader.on.load {
                        imageString = reader.result
                    }
                    reader.readAsDataURL(file);
                }
            }
            img().setAttribute("src", imageString)
        }

@sanity
Copy link
Member

sanity commented Oct 10, 2020

Sorry for the delayed response. This probably belongs in a separate issue, but Kweb doesn't currently have direct support for FileReader in the way you describe although it could be added, the relevant code is here.

You're welcome to create a separate issue for FileReader support.

sanity added a commit that referenced this issue Oct 10, 2020
@DineshSolanki DineshSolanki changed the title KVar doesn't support src of img tag KVar not binding if Element ID is changed Oct 10, 2020
@DineshSolanki
Copy link
Member Author

DineshSolanki commented Oct 10, 2020

thank you for the update, the recent commit fixed the issue of KVar not binding when ID is changed, and the elements are also rendered correctly now, however, changing value by javascript such as my code changing src by javascript still causes KVar to unbind. and as you said before, we should separate these issues, therefor I'm closing this one as resolved.
commit 7642ff1 fixes #164

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants