- PR -

SetFocusについて

投稿者投稿内容
kuwabala^2
会議室デビュー日: 2005/02/02
投稿数: 2
投稿日時: 2006-12-01 00:47
引用:

こんな感じなんですけど...。多分、bodyタグのonloadも当てにならないですね。


http://www.w3.org/TR/html4/interact/scripts.html#h-18.2.3
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2006-12-01 21:29
こんばんは。ぼのぼのです。
改めてスレを読み返してたんですが…

引用:

ぼのぼのさんの書き込み (2006-11-28 23:15) より:

それならもう知ってるので10へぇw


この発言は、非常に不適切でした。
不快な印象を与えてしまい、申し訳ありませんでした。m(_ _)m

編集で消してしまってもいいんですが、自戒の意を込めて残しときます。
長いこと回答者の立場で投稿してると、つい調子にのって偉そうな発言をしてしまうことがあり…
自分のレベルなんて、ようやく初心者の壁をのっこえて、
中級者の域に足を踏み入れかけてきたかな?という程度なのに。

お詫びの代わりに情報提供ってわけでもないんですが、
今回は脱初心者を目指す自分が、どんな思考過程で問題を解決に導くか、
ちょっと解説してみたいと思います。

つづく
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2006-12-01 21:55
まずは2006-11-30 01:35の書き込みで、偉そうにアドヴァイスたれたとこの、具体的な実践例です。

コード:

<%@ Page Language="VB" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Me.ClientScript.RegisterClientScriptBlock(Me.GetType(), "RCSB", _
"<script type='text/javascript'>alert('RegisterClientScriptBlock')</" & "script>")
Me.ClientScript.RegisterStartupScript(Me.GetType(), "RSS", _
"<script type='text/javascript'>alert('RegisterStartupScript')</" & "script>")
SetFocus(TextBox1)
End Sub
</script>
<html>
<head>
<title>test</title>
<script type="text/javascript">
function onloadFunc() {
alert("onload");
}
function isTextBoxExists(pos) {
if (document.getElementById("TextBox1") == null) alert(pos + "だとNo!");
else alert(pos + "だとYes!");
}
</script>
</head>
<body onload="onloadFunc()">
<form id="form1" runat="server">
<script type="text/javascript">isTextBoxExists("TextBox1より前");</script>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<script type="text/javascript">isTextBoxExists("TextBox1より後");</script>
<asp:RegularExpressionValidator ID="RegularExpressionValidator1"
runat="server" ErrorMessage="数値を入れて" ControlToValidate="TextBox1"
ValidationExpression="[0-9]*"></asp:RegularExpressionValidator><br />
<asp:Button ID="Button1" runat="server" Text="Button" />
<script type="text/javascript">alert("formタグ末尾");</script>
</form>
<script type="text/javascript">alert("bodyタグ末尾");</script>
</body>
</html>


TextBox、RegularExpressionValidator、Buttonの3つを配したミニマムコードのaspxに、
サーバ側のコードとクライアント側のコード両方でいたるところにスクリプトを埋め込みます。
これをビルドして実行して、ブラウザでソースの表示をすると、以下のようになります。

コード:

<html>
<head>
<title>test</title>
<script type="text/javascript">
function onloadFunc() {
alert("onload");
}
function isTextBoxExists(pos) {
if (document.getElementById("TextBox1") == null) alert(pos + "だとNo!");
else alert(pos + "だとYes!");
}
</script>
</head>
<body onload="onloadFunc()">
<form name="form1" method="post" action="Default.aspx" onsubmit="javascript:return WebForm_OnSubmit();" id="form1">

<div>
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTE2NTY0Mjg0ODlkZAhHtAfTO9k+6wXKbV468ennuJQY" />
</div>

<script type="text/javascript">
<!--
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
// -->
</script>


<script src="/WebSite1/WebResource.axd?d=keM44xwtheLkNFgMxBy71Q2&t=632963049499531250" type="text/javascript"></script>

<script type='text/javascript'>alert('RegisterClientScriptBlock')</script>
<script src="/WebSite1/WebResource.axd?d=VnYd4A71Kedb5DRLYb5O3MhJDbe1KH3tIi8zx3MfVvg1&t=632963049499531250"
type="text/javascript"></script>
<script src="/WebSite1/WebResource.axd?d=0EABchCYaWD1XZBa5XNZlg2&t=632963049499531250" type="text/javascript"></script>
<script type="text/javascript">
<!--
function WebForm_OnSubmit() {
if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;
return true;
}
// -->
</script>

<script type="text/javascript">isTextBoxExists("TextBox1より前");</script>
<input name="TextBox1" type="text" id="TextBox1" />
<script type="text/javascript">isTextBoxExists("TextBox1より後");</script>
<span id="RegularExpressionValidator1" style="color:Red;visibility:hidden;">数値を入れて</span><br />
<input type="submit" name="Button1" value="Button"
onclick="javascript:WebForm_DoPostBackWithOptions(
new WebForm_PostBackOptions("Button1", "", true, "", "", false, false))" id="Button1" />
<script type="text/javascript">alert("formタグ末尾");</script>

<script type="text/javascript">
<!--
var Page_Validators = new Array(document.getElementById("RegularExpressionValidator1"));
// -->
</script>

<script type="text/javascript">
<!--
var RegularExpressionValidator1 =
document.all ? document.all["RegularExpressionValidator1"] : document.getElementById("RegularExpressionValidator1");
RegularExpressionValidator1.controltovalidate = "TextBox1";
RegularExpressionValidator1.errormessage = "数値を入れて";
RegularExpressionValidator1.evaluationfunction = "RegularExpressionValidatorEvaluateIsValid";
RegularExpressionValidator1.validationexpression = "[0-9]*";
// -->
</script>

<div>

<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
value="/wEWAwLE5/GuCgLs0bLrBgKM54rGBhwo8b5YWQNSI2ZVBBP2Gk2c4O72" />
</div>
<script type='text/javascript'>alert('RegisterStartupScript')</script>
<script type="text/javascript">
<!--
var Page_ValidationActive = false;
if (typeof(ValidatorOnLoad) == "function") {
ValidatorOnLoad();
}

function ValidatorOnSubmit() {
if (Page_ValidationActive) {
return ValidatorCommonOnSubmit();
}
else {
return true;
}
}
// -->
</script>

<script type="text/javascript">
<!--
WebForm_AutoFocus('TextBox1');// -->
</script>
</form>
<script type="text/javascript">alert("bodyタグ末尾");</script>
</body>
</html>



太字以外のとこが、ASP.NETが自動生成した部分です。
実際に動かしてみると、埋め込んだスクリプトがどんな順番で実行されていくかがよくわかります。

つづく

<編集>コードの横幅が広がってものすごく見づらくなってしまったので改行を入れました。</編集>

[ メッセージ編集済み 編集者: ぼのぼの 編集日時 2006-12-01 22:17 ]
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2006-12-01 22:06
次に、当初のお題。一度全文引用しときます。

引用:

のすけさんの書き込み (2006-11-15 13:32) より:
SetFocusについて質問させて頂きます。

<前提>
言語:ASP.NET 2.0 (VB.NET)
環境:VisualStudio2005

<要件>
画面上のボタンを押下したときに、テキストボックス入力値を文字種チェックし、エラーの場合は当該テキストボックスにフォーカスを設定する。
但し、検証は(サーバではなく)クライアントにて行う。

<ご質問>
どのようにすれば、上記要件を実現できますでしょうか。

<現状>
検証コントロールRegularExpressionValidatorで文字種チェックを実装。
この時、SetFocusOnErrorにTRUEを設定すると、ボタン押下時ではなく、検証対象のテキストボックスのLostFocus時にチェックが走ってしまう。
 ↓
検証コントロールRegularExpressionValidatorでの文字種チェックは実装したまま、SetFocusOnErrorにFALSEを設定。
ボタンのOnClientClickプロパティを用い、クライアントでSetFocusのロジックのみ実装。
この場合は、検証コントロールのクライアントでのチェックが走らず、よってSetFocusのロジックも通り過ぎ、サーバでのチェックとなってしまう。
 ↓
検証コントロールを使用する以上、上記要件は実現不可!?
 ↓
そんなわけないような気がする・・・。


以上、宜しくお願い申し上げます。


簡単にまとめると、

・RegularExpressionValidatorでチェックをしている。
・既定の動きだとLostFocus時とボタン押下時にチェックが走る。
・ボタン押下時のみチェックが走るようにしたい。

というもの。まずはミニマムコードです。

コード:

<%@ Page Language="VB" %>
<script runat="server">
</script>
<html>
<head>
    <title>test</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:RegularExpressionValidator ID="RegularExpressionValidator1"
         runat="server" ErrorMessage="数値を入れて" ControlToValidate="TextBox1"
         ValidationExpression="[0-9]*"></asp:RegularExpressionValidator><br />
        <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
        <asp:RegularExpressionValidator ID="RegularExpressionValidator2"
         runat="server" ErrorMessage="数値を入れて" ControlToValidate="TextBox2"
         ValidationExpression="[0-9]*"></asp:RegularExpressionValidator><br />
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </form>
</body>
</html>


今回はTextBoxとRegularExpressionValidatorを2つずつ用意しました。
SetFocusOnErrorはまだつけません。

つづく
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2006-12-01 22:54
今度も同じくビルドして実行してソースの表示。

コード:
<html>
<head>
    <title>test</title>
</head>
<body>
<form name="form1" method="post" action="Default.aspx"
 onsubmit="javascript:return WebForm_OnSubmit();" id="form1">
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
 value="/wEPDwUKLTE1MTUxMjU4OGRkl29W7ENoggkahyLJfxl1U9paTJs=" />
</div>

<script type="text/javascript">
<!--
var theForm = document.forms['form1'];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
// -->
</script>


<script src="/WebSite1/WebResource.axd?d=keM44xwtheLkNFgMxBy71Q2&t=632963049499531250"
 type="text/javascript"></script>


<script src="/WebSite1/WebResource.axd?d=VnYd4A71Kedb5DRLYb5O3MhJDbe1KH3tIi8zx3MfVvg1&t=632963049499531250"
 type="text/javascript"></script>
<script type="text/javascript">
<!--
function WebForm_OnSubmit() {
if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;
return true;
}
// -->
</script>

    <input name="TextBox1" type="text" id="TextBox1" />
    <span id="RegularExpressionValidator1" style="color:Red;visibility:hidden;">数値を入れて</span><br />
    <input name="TextBox2" type="text" id="TextBox2" />
    <span id="RegularExpressionValidator2" style="color:Red;visibility:hidden;">数値を入れて</span><br />
    <input type="submit" name="Button1" value="Button"
        onclick="javascript:WebForm_DoPostBackWithOptions(
            new WebForm_PostBackOptions("Button1", "", true, "", "", false, false))" id="Button1" />
    
<script type="text/javascript">
<!--
var Page_Validators = new Array(
    document.getElementById("RegularExpressionValidator1"),
    document.getElementById("RegularExpressionValidator2"));
// -->
</script>

<script type="text/javascript">
<!--
var RegularExpressionValidator1 =
    document.all ? document.all["RegularExpressionValidator1"] :
                   document.getElementById("RegularExpressionValidator1");
RegularExpressionValidator1.controltovalidate = "TextBox1";
RegularExpressionValidator1.errormessage = "数値を入れて";
RegularExpressionValidator1.evaluationfunction = "RegularExpressionValidatorEvaluateIsValid";
RegularExpressionValidator1.validationexpression = "[0-9]*";
var RegularExpressionValidator2 =
    document.all ? document.all["RegularExpressionValidator2"] :
                   document.getElementById("RegularExpressionValidator2");
RegularExpressionValidator2.controltovalidate = "TextBox2";
RegularExpressionValidator2.errormessage = "数値を入れて";
RegularExpressionValidator2.evaluationfunction = "RegularExpressionValidatorEvaluateIsValid";
RegularExpressionValidator2.validationexpression = "[0-9]*";
// -->
</script>

<div>

<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
 value="/wEWBAKUxuGBBgLs0bLrBgLs0fbZDAKM54rGBnG+1CbBwCZolHfl4Q7XKxTRX66f" />
</div>

<script type="text/javascript">
<!--
var Page_ValidationActive = false;
if (typeof(ValidatorOnLoad) == "function") {
    ValidatorOnLoad();
}

function ValidatorOnSubmit() {
    if (Page_ValidationActive) {
        return ValidatorCommonOnSubmit();
    }
    else {
        return true;
    }
}
// -->
</script>
</form>
</body>
</html>


太字のとこは、ソースをざっと眺めて検証コントロールに関係してそうなところ。
そして、このソースはテキストファイルに保存しておきます。
次に、2つのRegularExpressionValidatorのSetFocusOnErrorプロパティをTrueにし、
同様にビルドして実行してソースの表示して、これもテキストファイルに保存します。
2つのテキストファイルをDIFFツールで比較すると、差分は以下の2箇所だけであることがわかります。

コード:
<script type="text/javascript">
<!--
var RegularExpressionValidator1 =
    document.all ? document.all["RegularExpressionValidator1"] :
                   document.getElementById("RegularExpressionValidator1");
RegularExpressionValidator1.controltovalidate = "TextBox1";
RegularExpressionValidator1.focusOnError = "t";
RegularExpressionValidator1.errormessage = "数値を入れて";
RegularExpressionValidator1.evaluationfunction = "RegularExpressionValidatorEvaluateIsValid";
RegularExpressionValidator1.validationexpression = "[0-9]*";
var RegularExpressionValidator2 =
    document.all ? document.all["RegularExpressionValidator2"] :
                   document.getElementById("RegularExpressionValidator2");
RegularExpressionValidator2.controltovalidate = "TextBox2";
RegularExpressionValidator2.focusOnError = "t";
RegularExpressionValidator2.errormessage = "数値を入れて";
RegularExpressionValidator2.evaluationfunction = "RegularExpressionValidatorEvaluateIsValid";
RegularExpressionValidator2.validationexpression = "[0-9]*";
// -->
</script>


既にかるあさんが挙げてますが、これでこの部分がフォーカス戻しの要否を決定ししてるらしいことがわかります。

つづく
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2006-12-02 00:38
さて、次はいよいよLostFocusでチェックが走らないようにする方法です。
HTMLのソースを眺めて、まず疑問に思うのは、テキストボックスのHTMLに、
onで始まる属性が何もついていなことです。

しかし、実際に動かしてみると、テキストボックスに数値以外を入れてフォーカスを外しただけで、
エラーメッセージのラベルが表示されます。

このことから、テキストボックスにASP.NETが自動生成したjavascriptが、
何かしらのイベントハンドラを埋め込んでいるのではないかと予測されます。

まずはこれを検証するため、検証用のjavascriptを仕込みます。
先の「順番の検証」から、最も遅いタイミングで実行されたスクリプトは、
bodyタグのonloadから呼び出したfunctionなので、
ここに書いておけばASP.NETが自動生成したjavascriptより後に実行されるだろうと考えます。

また、いちいちgetAttributeで怪しそうなイベントを全部チェックするのはめんどくさいので、
空のfunctionを作ってデバッガで確認することにします。

コード:

<head>
<title>test</title>
<script type="text/javascript">
function testFunc() {
var txt = document.getElementById("TextBox1");
alert("マテ!");
var tmpstr = "ここにブレークポイントをはる";
}
</script>
</head>
<body onload="testFunc()">


aspxに仕込んだクライアントスクリプトはそのままブレークポイントはれないので、
ここではデバッグ実行した後、「マテ!」のダイアログが表示された状態で
スクリプトエクスプローラでDefault.aspxを開き一行下にブレークポイントをはります。

ダイアログでOKを押すとブレークポイントで止まるので、txtをウォッチします。
そしてonではじまる属性を…っていっぱいあるなぁ。(;´Д`)
めんどくさいのでウォッチウィンドウから一度秀丸に貼り付けます。
Tab区切りテキストになるので、正規表現の置換をうまいこと使いまわして、
属性がonで始まってない行と値がnullになってる行を全部削除します。
すると残ったのがonkeypress、onblur、onchangeの3つ。
せっかくなのでどんなスクリプトが埋め込まれてるか見てみます。

コード:

<head>
<title>test</title>
<script type="text/javascript">
function testFunc() {
var txt = document.getElementById("TextBox1");
alert(txt.getAttribute("onkeypress"));
alert(txt.getAttribute("onblur"));
alert(txt.getAttribute("onchange"));
}
</script>
</head>
<body onload="testFunc()">


動かしてみると、なんかfunction anonymousというのが埋め込まれています。
anonymousってなんだ?ぐぐってみる。

anonymous(匿名)とは無名のFunctionオブジェクトに仮に付けられた名です。

そうなんだ。知らなかった。( ・∀・)つ〃∩ ヘェーヘェーヘェーヘェーヘェー


さて、「検証は走らせたいけどフォーカスは戻したくない」ということならもう少し工夫が必要ですが、
今回はLostFocus時には検証が走る必要すらないようなので、
あとは検証用に仕込んだスクリプトを書き換えるだけです。

コード:

<head>
<title>test</title>
<script type="text/javascript">
function removeLostFocusValidate() {
document.getElementById("TextBox1").onkeypress = null;
document.getElementById("TextBox1").onblur = null;
document.getElementById("TextBox1").onchange = null;
document.getElementById("TextBox2").onkeypress = null;
document.getElementById("TextBox2").onblur = null;
document.getElementById("TextBox2").onchange = null;
}
</script>
</head>
<body onload="removeLostFocusValidate()">


これで完成です。
動かしてみると、期待通りの動作になりました。

以上、長文失礼しました。

[ メッセージ編集済み 編集者: ぼのぼの 編集日時 2006-12-02 00:55 ]
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2006-12-07 00:31
結局根拠のない反論をしたわりに謝罪なしか。
のすけ(スレ主)は救いようがないな。

スキルアップ/キャリアアップ(JOB@IT)