【Rails】jQueryでフォームに文字数カウントをつける


フォームに文字を入力していく時、あと何文字まで打てるのか分かった方がユーザーに優しいと思ったため、文字数カウント機能を作りました。

▷今回やること
**フォームに残り何文字入力できるかを表示する**

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373922/7936136a-8e25-3f17-9875-6a2d2d50f5ea.gif)

####


#文字数カウント方法を考える
・文字を入力したり、消したりするたびフォームの文字数を数える → 残り何文字まで入力できるか表示する
・文字数がオーバーしていた場合、文字色を赤にする → ユーザーに警告する

#文字数カウントのアルゴリズムを考える
jQueryで文字数カウントをする

```html

▷jsが読み込まれたら以下の処理をする

　・処理内容（ページが読み込まれた時、フォームに残り何文字入力できるかを数えて表示する）
　フォームのvalueを取得して文字数を数える
　<!-- Macの改行コードは1文字(\n)であるが、Rails側では改行コードが2文字(\r\n)で保存されるため、\nは２文字とカウントするように設定 -->
　最大文字数　ー　取得した文字数　（＝残りの入力できる文字数）

　if 最大文字数より取得文字数の方が大きい
　　表示する文字色を赤にする

　“あと　（残りの入力できる文字数）文字”　と表示する

　　▷jQueryのkeyup()でキーボードが押されて離れるたびに処理を行う

　　　・処理内容（キーボードを押した時、フォームに残り何文字入力できるかを数えて表示する）
　　　　フォームのvalueを取得して文字数を数える。
　　　　<!-- Macの改行コードは1文字(\n)であるが、Rails側では改行コードが2文字(\r\n)で保存されるため、\nは２文字とカウントするように設定 -->
　　　　入力最大文字数　ー　取得した文字数　（＝残りの入力できる文字数）

　　　if 最大文字数より取得文字数の方が大きい
　　　　表示する文字色を赤にする
　　　　“あと　（残りの入力できる文字数）文字”　と表示する
　　　else
　　　　表示する文字色を黒にする
　　　　”あと　（残りの入力できる文字数）文字”　と表示する

　　処理終了
処理終了
```

#コードで文字数カウント処理を書く
###１.htmlでフォーム入力タグと文字数表示タグにclassを設定し、jsで指定できるようにする
フォーム入力タグ**text_area**のクラスに`js-text`、文字数表示タグ**p**のクラスに`js-text-count`を指定する
（フォームにbootstrapを適用しています）

```form.html.erb
<%= form_for(@profile) do |f| %>
  <div class="panel-body">
    <div class="form-group">
    <%= f.label :yourself, '自己紹介（最大150文字）' %>

    <%# js-textをclassに追加 %>
    <%= f.text_area :yourself, class: 'form-control  js-text', rows: 6, placeholder: '改行は反映されません' %>

    <%# js-text-count をclassに追加 %>
    <P class="js-text-count pull-right"></P>
  </div>
      
  <div class="text-center">
     <%= f.submit '保存する', class: 'btn btn-info'%>
  </div>
<% end %>    
```
###2.jsファイルにフォームと文字数表示に対する処理を書く
`js-text`のvalueを数えて、`js-text-count`に結果を表示する
app/assets/javascripに**count.jsファイル**を作成し、文字数カウントの処理を書いていく
（今回のフォームの最大文字数は１５０）

```app/assets/javascrip/count.js
// jquery書きはじめ
$(function (){
  // 処理（ページが読み込まれた時、フォームに残り何文字入力できるかを数えて表示する）

  //フォームに入力されている文字数を数える
  //\nは"改行"に変換して2文字にする。オプションフラグgで文字列の最後まで\nを探し変換する
  var count = $(".js-text").text().replace(/\n/g, "改行").length;
  //残りの入力できる文字数を計算
  var now_count = 150 - count;
  //文字数がオーバーしていたら文字色を赤にする
  if (count > 150) {
    $(".js-text-count").css("color","red");
  }
  //残りの入力できる文字数を表示
  $(".js-text-count").text( "残り" + now_count + "文字");
  
  $(".js-text").on("keyup", function() {
    // 処理（キーボードを押した時、フォームに残り何文字入力できるかを数えて表示する）
    //フォームのvalueの文字数を数える
    var count = $(this).val().replace(/\n/g, "改行").length;
    var now_count = 150 - count;
    
    if (count > 150) {
      $(".js-text-count").css("color","red");
    } else {
      $(".js-text-count").css("color","black");
    }
    $(".js-text-count").text( "残り" + now_count + "文字");
  });
});
```
###3.リンクをクリックしてページ遷移した時、jacascriptを読み込むようにする
現在のままでは、ページ遷移してもjsが機能しない

▷原因
**rails４.０からデフォルトで導入されたgem「turbolinks」が読み込まれているため**

〜turbolinksとは〜
>画面遷移を高速化させるライブラリ。
ページ遷移するとき、現在のページのtitleとbodyだけを抜き取り、
新しいhtmlのtitleとbodyに交換することで、ページ遷移を高速化させる。
→ページ読み込みを起点としたJavascriptは機能しなくなる
jQuery を使用している場合、 下記の様にページが読み込まれたときの処理を記述出来ますが、 Turbolinksによって、実行されなくなります。
$(function() {
    ＃処理内容
});

[『Turbolinks』って、なんぞ？](https://www.ryotaku.com/entry/2019/01/15/213420 )より抜粋

▷解決方法
**count.jsを読み込みたいリンクのtubolinksを無効にする**
**aタグ**は`data-turbolinks="false"`、**link_toメソッド**は`data: {"turbolinks" => false}`でtubolinksを無効化できる

リンク設定がaタグの場合

```html
<a href=“◯◯” data-turbolinks="false">turbolinksを使わずにリンクする</a>
```
リンク設定がlink_toメソッドの場合

```
<%= link_to "turbolinksを使わずにリンクする", ◯◯_path, data: {"turbolinks" => false} %>
```
これでページ遷移した時、count.jsが読み込まれるようになり、文字数カウント処理が行われる。

#参考
・[[簡単すぎる]Rails + jQueryで文字数カウント](https://qiita.com/k19911848/items/60e19282dc934d9a5803)
・[【JavaScript】文字列から改行を全て削除する方法](https://nullnull.dev/blog/javascript-remove-line-breaks/)
・[turbolinksチートシート](https://qiita.com/morrr/items/54f4be21032a45fd4fe9)
・[『Turbolinks』って、なんぞ？](https://www.ryotaku.com/entry/2019/01/15/213420 )