karaxのループで生成する要素のボタンクリック処理
まえがき
karaxのループで要素を生成したときにボタンクリックイベントで変数を操作しようとしてつまづいて解決した 原因と解決とかを書く
karaxでボタンクリック時に変数を操作するのはよくやる こんな感じで実装する
code:karax_test1.nim
var
text = cstring"not clicked"
proc createDom(): VNode =
result = buildHtml(tdiv):
text text
button:
text "click me"
proc onclick(ev: Event, n: VNode) =
echo "clicked"
text = cstring"clicked"
setRenderer createDom
ボタンをクリックするとtext変数が更新されて画面の描画が更新される
以下の画面が描画される
https://gyazo.com/9c51418798528baf01d7d0d2bad7dbaf
簡単
ループで要素を生成したときにへんてこなことになる
こんな感じの実装
code:karax_test2.nim
var
text = cstring"not clicked"
proc createDom(): VNode =
result = buildHtml(tdiv):
text text
button:
text "click me"
proc onclick(ev: Event, n: VNode) =
echo "clicked"
text = cstring"clicked"
hr()
for i, _ in texts:
button:
text "click me"
proc onclick(ev: Event, n: VNode) =
echo "clicked"
textsi = cstring"clicked" setRenderer createDom
textsでループして、ループカウンタでtextsにインデックスアクセスして上書きする
何も違和感ない実装のように見える
が、これだと問題がある
上のソースをビルドすると以下の画面ができる
https://gyazo.com/478984eaf0375cad73415edc606c7ede
横線の下部分がループで生成している
問題なさそう
この状態で横線下の一番左のボタンをクリックすると
https://gyazo.com/98f67d291827e946a1d5617425650979
一番右のテキストが更新されている
???
解消法
どういうわけか、proc onclickでクリックイベントを定義してプロシージャ内でループカウンタを使うと、一番最後のループカウンタの値がセットされているらしい
回避策として、onclick用のプロシージャを生成するプロシージャを定義する必要がある
以下のように実装する
code:karax_test3.nim
var
text = cstring"not clicked"
# ↓ここが大事
proc buttonOnClicked(i: int): proc(ev: Event, n: VNode) =
let i = i
result = proc(ev: Event, n: VNode) =
echo "clicked"
textsi = cstring"clicked" proc createDom(): VNode =
result = buildHtml(tdiv):
text text
button:
text "click me"
proc onclick(ev: Event, n: VNode) =
echo "clicked"
text = cstring"clicked"
hr()
for i, _ in texts:
button(onclick = buttonOnClicked(i)):
text "click me"
setRenderer createDom
buttonOnClickという引数にループカウンタを受け取るプロシージャを定義する
受け取った値をプロシージャ内のローカル変数に束縛し、ボタンクリックイベント用のプロシージャを返す
これでボタンクリックイベントが期待通りの動きをするようになった
https://gyazo.com/b13d6b005c49d9810e6d205aad35c8a7
よかったよかった