karaxnim / karax

Karax. Single page applications for Nim.
MIT License
1.07k stars 90 forks source link

node wrongly deleted after a redraw if style param is used #287

Open timotheecour opened 4 months ago

timotheecour commented 4 months ago

nim js -o:app_bug.js -d:case_ok app_bug.nim: no bug nim js -o:app_bug.js -d:case_bug1 app_bug.nim: when you click the button a few times, the foreign node gets (wrongly) deleted

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta content="width=device-width, initial-scale=1" name="viewport"/>
    <title>bug</title>
  </head>
  <body id="body">
    <div id="ROOT"></div>
    <script type="text/javascript" src="/app_bug.js"></script>
  </body>
</html>

app_bug.nim:

#[
nim js -o:app_bug.js app_bug.nim
python -m http.server 8006
d_forward_tunnel_simple $host_node_gpu 8006
http://localhost:8006/
]#

import karax / [vdom, kdom, karax, karaxdsl]
import karax / kbase
import karax / vstyles

{.emit: """
function initTimeline2(){
    var container = document.getElementById('timeline_container');
    const textNode = document.createTextNode("Hello, World!");
    container.appendChild(textNode);
}
""" .}
proc initTimeline2() {.importc.}

type State = ref object
  loaded: bool
  textTimelines: seq[kstring]

let state = State()

proc handleClick(ev: Event; n: VNode) =
  state.textTimelines.add "foo"
  redraw()

proc createDom(data: RouterData): VNode =
  result = buildHtml(tdiv):
    button(onclick=handleClick):
      text "click"
    for i in 0..<len(state.textTimelines):
      tdiv:
        text state.textTimelines[i]

    when defined(case_bug1):
      tdiv(id="timeline_container", style = style(StyleAttr.width, cstring"200px"))
    elif defined(case_bug2):
      tdiv(id="timeline_container", style = "width: 200px".toCss)
    elif defined(case_ok):
      tdiv(id="timeline_container")
    else:
      static: assert false, "use -d:..."

proc clientPostRenderCallback(data: RouterData) =
  if not state.loaded:
    state.loaded = true
    initTimeline2()

setInitializer(createDom, root = "ROOT", clientPostRenderCallback = clientPostRenderCallback)
setForeignNodeId "timeline_container"

notes