今回は、Reflex Viewを担当している genokitaさんからの嵌りの報告。Reflex Viewで、キー入力時にvalidatorが実行されるところで嵌ったようだ。 validatorは、例えば、値をチェックして「誤」と認められた場合に、入力中のテキストボックスの背景を赤色にしたりカーソルを動かなくしたりする機能である。Reflex Viewの概要およびValidatorについてはこちらを参照していただきたい。
まず、validatorの基本動作について、A,Bの2つのテキストボックスを例に以下に説明する。2つのテキストボックスにはonblurイベントが登録されており、validatorはonblurイベント駆動になっている。onblurイベントは、カーソルがテキストボックスから離れたタイミングで発行されるイベントだ。
A:テキストボックス
B:テキストボックス
【動作】
Aの値を誤に変更し、Bをクリックする
【前提条件】
(1)両テキストボックスにはonblurがかかっている
(2)blurイベントが発生するごとにvalidationがかかる
(3)validationが通らなかったら、フォーカスを誤セルに戻し、表示される値は誤のまま(=entityの値を入れなおさない)
(4)validationが通ったら再全計算(Blogic()),再描画(Refresh())がかかる
【ロジック】
if (A.blur) {
res = validate(A);
}
if (res == IS_INVALID)
alert("A is invalid!");
A.focus(); --(i)
} else if(res == IS_VALID) {
Blogic();
Refresh();
B.focus();
}
(i)に至るまでには
A.blur;
B.focus;
B.blur;
A.focus;
の順にイベントが発生するので、B.blurの時点でBのvalidationがかかる。
詳細は以下にまとめるが、今回の問題は、validator実行後にカーソルが移動してしまうことが原因で起きていた。強引にフォーカスを元に戻そうとすると移動先のonblurイベントによるvalidatorが走ってしまうが、元のテキストボックスが「誤」であるから、移動先のテキストボックスが「誤」である場合に無限ループを引き起こしてしまうのである。ちなみに、読込時の初期データに誤りがあっても同様の現象に陥るため、前提条件をクリアーしたデータでないとうまく動作しない。このことは入力点におけるデータチェックの必要性ということで、こちらに書いたとおりである。
【初期データに誤りがある場合】
A初期:正
B初期:誤
* Aの値を誤に変更し、Bをクリックしてしまうと、AとBが交互にエラーを吐くため無限ループに嵌る(←ここで嵌った)
* 初期データは正しいという前提で黙認(本当なら初期データが正しいかどうかをチェックしてあげなきゃいけない)
【初期データが正しい場合】
* Aに誤を入れた後にBをクリックすると、A.blurで最初のvalidationが実行され、B.blurの時にも再びvalidationがかかる
* blurの度にvalidation再計算再描画が行われるため、B.blurの時にAの値がentityの値で置き換えられてしまう(←ここで嵌った)
解決策としては、以下のように、本来格納すべき場所(Entity)以外の一時的な値を保持する領域を用意すればよい。Reflex Viewでは、これをpreview層と定義している。preview層に入っているデータはまだValidatorを通っていないためエラーの可能性がある。Validatorでエラーでないことが確認できればEntityの値を書き換えることができる。
【解決策】
* 誤Aの値をどこかに格納しておき、再描画の際にentity.Aを誤Aで置換してやればいい
* Validator(View)クラスを作成し、誤セルのID・値・エラーコードを静的保持しておけばいい
0 件のコメント:
コメントを投稿