メールフォーム周りについて(1)-バリデーション

<p>インハウスでコーダーをしています。<br>制作会社と違い、実際の運用を日々見ることができるので、制作会社時代には気づかなかったことが見えることがあります。</p>
<p>今回はメールフォームのバリデートについて、見てみます。</p>
<p>メールフォームはコンバーションそのものです。ここで申し込んでもらうために、日々ページを作成しています。が、入力間違いで、売り上げに結び付かない事があります。バリデーションを工夫することで、少しでも減らしたいものです。</p>
<p>また、営業さんや事務の方が、メールフォームをcsvに加工し統計を取ったり、マーケッターがcsvデータを利用しています。そちらにもミスを出さないように、工夫してみました。</p>
<p>言語はjqueryを使用しますが、初心者です。</p>
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="kazu-1" data-slug-hash="MxNXqg" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="MxNXqg">
  <span>See the Pen <a href="https://codepen.io/kazu-1/pen/MxNXqg/">
  MxNXqg</a> by kazu-1 (<a href="https://codepen.io/kazu-1">@kazu-1</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
<p>基本的に、必須項目は入力前は全てエラー設定、必須なのに入力されてないから。条件を満たす入力をして初めて、エラー表示を外します。</p>
##よくある間違い３つ
<ol>
  <li>メールアドレスの間違い</li>
  <li>電話の桁数間違い</li>
  <li>住所を郵便番号で自動入力後、放置</li>
</ol>
<p>なるべくかご落ちを防ぐために、最小限の連絡先をお伺いしています。連絡先を1つしか問うていないのに、間違えられるとお手上げとなります。上記の間違いは、お客様に連絡できないため、折角のコンバージョンが無駄になってしまいます。勿体なさすぎます。</p>
##解決バリデーション
###メールアドレスの間違い
<p>メールアドレスの形式「*@*.*」に見えて違う場合があります。</p>
<p>ピリオドがカンマになっている場合が、たまにあります。キーボードが隣で、「.」「,」と形もよく似ている、小さいため、誤入力に気づかないと思われます。また、運用上csvにする場合に、「,」が区切り文字となるため、列がずれ、自動での処理が困難になり、人手を要することになります。</p>
####乱暴だけど、「,」＝「.」でよくないですか？
<p>メールアドレスに「,」は使えるのか？<br>
厳密にいえば、「,」はプロバイダが許可していれば使えます。<br>
ただし、記号（( ) , : ; < > @ [ ] " \）を含める場合には @ よりも前の部分全体を " で囲む必要があります。詳しくはRFCでググってね。実際に、「,」を含む記号の使用を許可しているプロバイダは、これまで送信されてきた中では、0でした。</p>
<p>運用上、メールアドレスに「,」はないと考え、できるだけ、フォーム利用者に負担をかけず、送信して貰うことを是とする場合、<strong>「,」＝「.」</strong>と扱った方がいい結果になると推察します。つまり、「,」は間違いではないですか？修正くださいとエラーを返したり、そのまま送信するよりも、勝手に「.」に変換してあげることのほうが、自動確認メールを送る上でも、csv統計を取る上でも有益です。</p>
<p>ダメ出しして、入力意欲をそぐ事なく、勝手に「.」に変換してあげても問題は起きないし、後処理も、楽になります。</p>
<p>そこで、入力完了時に1.全角を半角に変換、2.カンマはピリオドに置換、3.入力欄に2.と入れ替え、4.メールアドレスの形式「*@*.*」になっているか、チェック。5.通らなければ、エラーを表示、6.通れば、errorを外すことにしています。</p>

```html:html
<dl class="error">
  <dt>mail</dt>
  <dd class="error-text">必須項目です。</dd>
  <dd class="form-value">
    <input class="mail-check" type="email">
  </dd>
</dl>
```

```Javascript:js
$('.mail-check').blur(function() {
  let mail = $(this).val().replace(/[！-～]/g, function(s) { 
                                        //↑ 1.入力値を半角に変換
    return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
  });
  mail = mail.replace(/ー/gi, '-');
  mail = mail.replace(/,/gi, '.');      //2.カンマはピリオドに置換のおせっかい
  $(".mail-check").val(mail);           //3.入力欄を2.に変更
  let hantei = mail.match(/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/);
             //↑ 4.メールアドレスの形式「*@*.*」になっているか、チェック
  if (hantei == null) {                 //5.通らなければ、エラーを表示
    $(this).parent('dd').prev().html("アドレスが正しいか、ご確認ください。");
    $(this).parent('dd').prev().css("display", "inline");
    $(this).parent().parent("dl").addClass('error');
  }  else {                             //6.通れば、errorを外す
    $(this).parent('dd').prev().fadeOut();
    $(this).parent().parent("dl").removeClass('error');
  }
});
```
###電話の桁数間違い
<p>時々桁数があわない番号が来ていたことへの対応。桁数だけあっていても、正しくなければ、連絡ができないのですが、明確に間違いとわかる場合は、問題を提示し、修正いただきたいと考えています。</p>
<p>一般の電話番号のルールは以下のようです。（<a href="http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/q_and_a.html">総務省のページ</a>調べ）</p>
<p>固定電話は0で始まり、３桁目が０でない10桁の番号。<br>
携帯電話は090・080・070で始まる11桁の番号。<br>
IP電話は050で始まる11桁の番号。</p>
<p>
国際電話が010、ポケットベルが020、FMCサービスが060で、030と040が使われていない。<br>
なので、010～040で始まる番号は国内の電話番号ではない、と考えられます。</p>

```html:html
<dl class="error">
  <dt>電話番号</dt>
  <dd class="error-text">必須項目です。</dd>
  <dd class="form-value">
    <input class="tel-check" type="tel">
  </dd>
</dl>
```

```Javascript:js
$('.tel-check').blur(function() {
  var tel = $(this).val().replace(/[━.*‐.*―.*－.*\-.*ー.*\-]/gi, '');
    //↑ 入力値のハイフォンなどを判定用から削除
  tel = tel.replace(/[０-９]/g, function(s) {   
    //↑ 判定用の全角数字を半角に変更
    return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
  });
  if (tel.match(/^(0[5-9]0[0-9]{8}||0[1-9][1-9][0-9]{7})$/)) {
    //↑ 先頭の3文字で後ろの桁数を決定に0x0でxが５～９の場合続く８桁の数字(携帯電話)
    //  または、0xで始まり３桁目の数字が０でない場合続く7桁の数字か（固定電話）
    $(this).parent('dd').prev().fadeOut();
    $(this).parents(".error").removeClass('error');
  } else {
    $(this).parent('dd').prev().html("電話番号が正しいか、ご確認ください。");
    $(this).parent('dd').prev().css("display", "inline");
    $(this).parent().parent("dl").addClass('error');
  }
});
```
<p>メールアドレスとは違い、判定用の変数を入力欄に返さないのは、お客様が入力したハイホンを削除したくないからです。電話番号の確認は、ハイホンがあったほうが、誤入力に気づきやすいと考えます。</p>
###住所を郵便番号で自動入力後、放置防止
<p>郵便番号を入力すると、自動で都道府県以下を補完するプラグインを使用すると、その続きの番地やマンション名を入れてくれない場合があります。続きの入力を施したいときに、郵便番号で判明する以外の住所より文字数が増えていることと番地を含むであろう数字があるかないかでチェックし、続きの住所を入力してもらうようにメッセージを出します。</p>
<p>郵便番号の入力完成時の自動住所補完欄の文字数をチェックし、最終住所と比較し、増えていることが１つ目の条件。そして、住所につきものの番地が含まれていれば、何らかの数字が含まれている筈。つまり数字があることが２つ目の条件。</p>
<p>その為、郵便番号入力完了時に住所補完のメッセージを出し、住所欄を離れる際にもチェックを行います。</p>
```html:html
<dl class="error">
  <dt>住所</dt>
  <dd class="error-text">必須項目です。</dd>
  <dd class="form-value"><span class="zip">郵便番号</span>
    <input id="postcode" type="tel" maxlength="8">
    <span class="todoufuken">都道府県</span>
    <input type="text" id="address1" maxlength="5"></dd>
</dl>
<dl class="error">
  <dt>住所</dt>
  <dd class="error-text">必須項目です。</dd>
  <dd class="form-value">
    <input type="text" id="address2" placeholder="町名・番地・建物名・部屋名">
  </dd>
</dl>
```

```Javascript:js
$("#postcode").blur(function() {
  /**郵便番号**/
  let i = $("#postcode").val().length;
  iiii = $("#address2").val().length;
      //↑ ①郵便番号の入力完成時に補完された文字数を数えておきます。
  if (i > 3) { 
      //3文字以上の入力で、都道府県以下が入りだします。
    $("#address1").parent('dd').prev().fadeOut();
    $("#address2").parent('dd').prev().css("display", "inline");
    $("#address2").parent('dd').prev().html("住所を完成させてください。");
  }
});
$("#address2").blur(function() {
  let i = $(this).val().length;
       //↑ ②住所欄から離れた時の文字数を数えます。
  let val = $(this).val();
  let banchi = val.match(/[0-9０-９一二三四五六七八九十]/);
       //↑ 住所に全角や半角、漢字の数字が入っている事の確認（番地を入力しているか確認）
  if (banchi !== null && iiii < i) {
       //↑ 数字が入っていて、かつ郵便番号入力時より文字数が増えている場合（①と②の比較）
    $(this).parent('dd').prev().fadeOut();
    $(this).parents(".error").removeClass('error');
  } else if (val == "") {       //入力していない場合
    $(this).parent('dd').prev().html("必須項目です。");
    $(this).parent('dd').prev().css("display", "inline");
    $(this).parent().parent("dl").addClass('error');
  } else {                      //上記2つにはまらない場合
    $(this).parent().parent("dl").addClass('error');
    $(this).parent('dd').prev().css("display", "inline");
    $(this).parent('dd').prev().html("住所を完成させてください。");
  }
});
```