onblur ハンドラーで、別のハンドラー (onfocus、keydown など) で削除しようとしている同じノードを変更しようとしている場合、removeChild
実際にノードを削除する前に、最初の呼び出しで onblur ハンドラーが起動されます。次に、onblur ハンドラーがノードを変更してその親が変更されると、制御が onblur ハンドラーからremoveChild
onfocus ハンドラーの呼び出しに戻り、ノードの削除が試行され、説明した例外で失敗します。
onfocus ハンドラーを呼び出す前に子の存在をいくらでもチェックしてremoveChild
も無駄です。これは、これらのチェックが onblur ハンドラーがトリガーされる前に行われるためです。
イベント処理とノードの変更を再配置する以外に、try catch ブロックで例外を処理するのがおそらく最善の策です。
removeChild
次のコードは、onfocus で実際に子を削除する前に、onblur イベント ハンドラーがどのように実行されるかを示しています。jsfiddleにもあります
html
<div id="iParent">
<input id="i">
</div>
js
var input = document.querySelector("#i"),
inputParent = document.querySelector('#iParent');
input.onblur = function() {
console.log('onblur : input ' + (input.parentNode ? 'has' : 'doesnt have')
+ ' a parent BEFORE delete');
try {
inputParent.removeChild(input);
} catch (err) {
console.log('onblur : removeChild failed, input '
+ (input.parentNode ? 'has' : 'doesnt have') + ' a parent');
return false;
}
console.log('onblur : child removed');
};
input.onfocus = function() {
console.log('onfocus : input ' + (input.parentNode ? 'has' : 'doesnt have')
+ ' a parent BEFORE delete');
try {
inputParent.removeChild(input);
} catch (err) {
console.log('onfocus : removeChild failed, input '
+ (input.parentNode ? 'has' : 'doesnt have') + ' a parent');
return false;
}
console.log('onfocus : child removed');
};
入力フィールドにフォーカスした後のコンソール出力は
onfocus : input has a parent BEFORE delete
onblur : input has a parent BEFORE delete
onblur : child removed
onfocus : removeChild failed, input doesnt have a parent