1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【rails入門】javascriptを用いてカーソルを制御する

Posted at

はじめに

皆さんこんな経験ありませんか?

スクリーンショット 2022-04-15 11.41.01.png

ログインするときメールアドレスの次にパスワードを入力しようとしたけど、保存してるパスワードとか予測変換とかでパスワードの入力欄が隠れてしまう!!

今回やること

javascriptを用いてメールアドレスを入力し終わってenterを押すと自動でパスワード入力欄にカーソルが合わさるようにする

早速やっていきましょう!

前提としてrailsでdeviseというGemを使用してログイン機能を実装しているとします!

1.現状のコード

views/users/sessions/new.html.erb
<h2>ログイン</h2>
<p>※登録したメールアドレスとパスワードを入力してください。</p>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  <div class="field">
    <h2>メール </h2><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email", id:"email" %>
    <!-- autofocus: true と id:"email" をつけてるよ!! -->
  </div>

  <div class="field">
    <h2>パスワード </h2><br />
    <%= f.password_field :password, autocomplete: "off", id:"password" %>
    <!-- id:"password" をつけてるよ!! -->
  </div>

  <% if devise_mapping.rememberable? -%>
    <div class="field">
      <%= f.check_box :remember_me %>
      <h2>私を覚える</h2>
    </div>
  <% end -%>

  <div class="actions">
    <%= f.submit "Log in" %>
  </div>
<% end %>

<%= render "users/shared/links" %>

重要なところはemailのフォームにautofocus: trueがついていることと、
email, passwordのフォームにidをつけていることです!

autofocus: trueはページが表示されて一番最初にカーソルが合う場所に指定しています!
idはjavascriptで取得しやすいようにつけてます!

2. javascriptを書いていきます!

views/users/sessions/new.html.erb

<h2>ログイン</h2>
<p>登録したメールアドレスとパスワードを入力してください</p>

<!-- 省略 -->

<%= render "users/shared/links" %>

<script>
  const email = document.querySelector('#email'); //emailの入力フォーム取得
  const pass = document.querySelector('#password'); //passwordの入力フォーム取得
  email.onkeydown = function(event){ //キーボード押されたら
    if (event.key === 'Enter') { //そのキーボードがenterキーなら
      pass.focus(); //passwordの入力フォームにフォーカスする
      return false; //これがなかったら一瞬しかカーソル合わない
    }else{
      return true;
    }
  }
</script>

以上!!

発展編①

ここからは発展的な内容でやっていきます!!発展とはいえちょっとしたお遊びなので最後まで見ていって下さい

まずはpassword入力欄でenterを押すと勝手にloginボタンを押してくれるようにします!

views/users/sessions/new.html.erb

  <!-- 省略 -->

  <div class="actions">
    <%= f.submit "Log in", id:"login" %> <!-- idを追加 -->
  </div>

  <!-- 省略 -->

<script>

  // 省略

  // ここから追記
  pass.onkeydown = function(event){
    if (event.key === 'Enter') {
      document.querySelector("#login").click();
    }
  }
  // ここまで
</script>

発展編②

フォームがもっとたくさんあるときenter押したら一つ下のフォームにカーソルが合うようにする
htmlファイルはこんな感じです

form.html.erb
<%= form_for @post do |f| %>
    <div class="all">
        <div class="element">
            <%= f.text_field :body1, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body2, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body3, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body4, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body5, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body6, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body7, class:"form" %>
        </div>

        <%= f.submit "post", id:"post" %>
    </div>
<% end %>

javascriptはこんな感じ

form.html.erb
<%= form_for @post do |f| %>

<!-- 省略 -->

<% end %>

<script>
    const forms = document.querySelectorAll('.form'); //class名がformの要素をlistとして取得
    function nextfocus(e){
        if (e.keyCode === 13){ //キーボードがenterキーの時
            this.parentNode.nextElementSibling.children[0].focus();
                        //めちゃややこしいですが、要素を辿っています
        }
    }
    for (let i = 0;i < forms.length - 1;i++){
        forms[i].addEventListener("keypress", nextfocus);
                //最後のform以外の全てのformに対してキーボードが押されたときのfunctionを設定する
    }
</script>

解説

this.parentNode.nextElementSibling.children[0].focus();

ここでは要素を辿っています!

  • parentNode → 親要素取得
  • nextElementSibling → 同じ親要素を持つ次の要素取得
  • children[0] → 子要素の中の1つ目の要素

今やりたいことはenterが押されたときに一つ下のフォームへカーソルを動かすことです:frowning2:
ですが、ただ一つ下の要素というわけではなく、一つ一つのformdivで囲まれています:frowning2::frowning2:
なので、カーソルの移動先はenterが押されたformの親要素のdiv(class="element")の次の要素のなかのformということになります!
以下の画像参照↓↓↓
スクリーンショット 2022-04-16 2.21.19.png

ここでちょっと問題発生:rotating_light::rotating_light:

enterを押すとsubmitボタンが勝手に押されてしまう

なのでちょっと変更

form.html.erb
<!-- 変更前 -->
<%= f.submit "post", id:"post" %>

<!-- 変更後 -->
<button type="button" onclick="submit()" id="post">post</button>

type="submit"が良くなかったようです

発展編②続き

さらに発展編②に付け加えていきましょう!!
まずは発展編①でもやりましたが、最後のフォームでenterを押すとsubmitされるようにしましょう

form.html.erb
<script>

    //追記
    forms[forms.length-1].onkeydown = function(event){
        if (event.key === 'Enter') {
            document.querySelector('#post').click();
        }
    }

</script>

以上!

最後に

今回のコードこんな感じ

form.html.erb
<%= form_for @post do |f| %>
    <div class="all">
        <div class="element">
            <%= f.text_field :body1, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body2, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body3, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body4, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body5, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body6, class:"form" %>
        </div>
        <div class="element">
            <%= f.text_field :body7, class:"form" %>
        </div>

        <button type="button" onclick="submit()" id="post">post</button>
    </div>
<% end %>

<script>
    const forms = document.querySelectorAll('.form');
    function nextfocus(e){
        if (e.keyCode === 13){
            this.parentNode.nextElementSibling.children[0].focus();
        }
    }
    for (let i = 0; i < forms.length - 1; i++){
        forms[i].addEventListener("keypress", nextfocus);
    }
    forms[forms.length-1].onkeydown = function(event){
        if (event.key === 'Enter') {
            document.querySelector('#post').click();
        }
    }
</script>

ここまで見ていただきありがとうございます!
僕はこれからもたくさん記事を書いてアウトプットしていこうと思っています!間違いや不明点、改善点などなんでもコメントしていただきたいです!
それではばいばいばあああい!!!!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?