In my slow navigation of the nim learning curve, I had reason to use the javascript output function for modifying contents of a web page. In short it was a simple exercise to learn with. However there were some things that took me a lot longer to figure out than I expected. So I over-commented my code for my future reference and stripped out non-essentials to keep it brief and to the point for the forum. The goal was to alphabetize the contents of the textarea. The most surprising thing was that there is no value field in the Element object in dom.nim. Reviewing the notes for that project, it appears that it was removed because it wasn't used or referenced. Because of that I had to make a small in-page script to get and set the data in textarea. I thought there was a way to in-line javascript, but couldn't find it. Feel free to share comments and suggestions because I'm sure there is much room for improvement.
<html>
<head>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript">
function getTextValue(strID) {
return document.getElementById(strID).value
}
function setTextValue(strID, strValue) {
document.getElementById(strID).value = strValue
}
</script>
</head>
<body>
<div id="theid" name="theid">
<center>
<textarea id="thetext" cols="80" rows="20" spellcheck="false"></textarea>
<button type="button" onclick="doEcho()">Organize</button>
</center>
</div>
</body>
</html>
import dom
import strutils # spliteLines, join
import algorithm # cmp
# javascript routines on the webpage (library or whatever) need to be
# forward declared so that nim knows about them and can compile to use them.
# importc means this procedure is external to nim and needs to come in
# these js routines were made because nim had no way of accessing the "value"
# of a "textarea" object
proc getTextValue(strID: cstring): cstring {.importc.}
proc setTextValue(strID, strValue: cstring) {.importc.}
# the exportc is needed for javascript on the web page to call this routine
# For the page javascript to know about this routine it has to be "exported"
proc doEcho() {.exportc.} =
# Data (list of strings) is expected to be pasted into the text box
let csInput = getTextValue("thetext") # This comes as a cstring from js
let sInput = $csInput # Now it is a real (nim) string
var lInput = splitLines(sInput) # put the contents into a sequence
lInput.sort(cmp) # Sort the sequence (default compare function)
let strResult = join(lInput, "\n") # move the sequence back to a string
setTextValue("thetext", strResult) # display the new string in the webpage
proc Intialize(event: Event) {.nimcall.} = # Not sure what this pragma does
document.title = "Test" # Something to verify script works
when isMainModule: # Took from documentation. Trusting it works as it looks
window.onload = Intialize # Needed this - somethings don't work right away
I tried with Karax the last couple of days as time permitted. The part I'm having trouble with is getting to the data that has been put into the text area. I understand that Karax uses a vdom implementation, however the actual DOM seems to only update from the vdom and not the other way around.
The following code works. However if I remove line 14 [ ota.setInputText("Test") ] it will fail stating that a variable referencing the specified data is null. The idea with this test was to simply echo what is entered into the text field into the console. So, how does one get new data that the user has put into the text field?
include karax / prelude
proc createDom(): VNode =
result = buildHtml(tdiv(align="Center")):
p:
text "Hello World"
p:
input(class = "text", id = "theid")
p:
button:
text "Organize"
proc onclick(ev: Event; n: Vnode) =
let ota = getVNodeById("theid")
ota.setInputText("Test")
let sText: kstring = ota.text
echo($sText)
setRenderer createDom
maybe something like that:
include karax / prelude
var testText = kstring"..."
proc onChText(id: kstring): proc() =
result = proc() =
testText = getVNodeById(id).text
echo "onChText..."
proc createDom(): VNode =
echo "render createDom..."
result = buildHtml(tdiv(align="Center")):
p:
text "Hello World" & " : " & testText
p:
input(class = "text", id = "theid", value=testText, onchange = onChText("theid"))
p:
button:
text "Organize" & " : " & testText
proc onclick(ev: Event; n: Vnode) =
let sText: kstring = testText
echo sText
setRenderer createDom
it works: onchange -> rerender -> onclick
But what happen wenn onchange -> rerender will be slower as onclick?