Rails・jQueryで文字数カウント機能（Bootstrap）

## はじめに
* エンジニア転職用のRailsポートフォリオで、長文のテキストエリア下に色付きの「あと○○文字」というカウントを表示させた際の記録です。
* シンプルな文字数カウンターの機能に加えて、Bootstrapを用いてテキストの表示色を指定しています。
* プログラミング学習3か月目の初心者です。誤りなどありましたらお教えいただけると幸いです。

## 環境
* Ruby 3.1.2
* Rails 6.1.7.3
* IDE: Cloud9

## 完成イメージ
実装した機能の動作デモです
![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296175/34c1cb79-4f68-404e-8ee0-6b5c71b8758c.gif)

## 参考URLなど
* [【Rails】jQueryでフォームに文字数カウントをつける](https://qiita.com/rio_threehouse/items/d9f9149bb8eee13973d4)
 ⇒こちらの記事を参考にさせていただきました。
## 実装
### ①フォームを作成（slim）
まずはビューに入力フォームを作成します。Bootstrapを使用する想定です。
今回はJobモデルのintroductionカラムに値を送るフォームを作ります。他のカラムに値を渡す記述は省きますので適宜追加してください。
```slim:app/views/jobs/new.html.slim
= form_with model: @job do |f|
    = f.label :introduction,"紹介文"
    = f.text_area :introduction, class: "introduction form-control"
    small.text-count.text-success
```
※クラス名"introduction"と"text-count"が今回jQueryを動かすために追加したもので、"text-success"はBootstrapで緑色のテキストを表示するクラス名です。
<br>

### ②scriptタグ内に処理を記述
同じページの最下部にscriptタグを作り、その中に処理を記述していきます。
ここでは最大文字数は3000文字にします。
【2023/06/13修正 ibyrjbf様よりご指摘いただいた内容を修正しました。】
```erb:app/views/jobs/new.html.slim
<script>
$(function (){
  
  //最大文字数として指定したい数を変数maxに。
  const max = 3000

  //文字数カウント・テキスト色変更の処理を関数化
  const addClassToTextCounter = elem => {
    
    //elem.val()→ここではクラス"introduction"の文字数を変数countに。改行は"改行"の二文字にカウントする。
    const count = elem.val().replace(/\n/g, "改行").length;
    
    //残りの入力できる文字数を計算
    const now_count = max - count;
    
    //文字数がオーバーしているかどうかで分岐し、クラス"text-counter"にBootstrapのクラスを付け外しする
    //オーバーしている時はtext-sucsessをtext-dangerに。
    if (count > max) {
      $(".text-count").removeClass("text-success");
      $(".text-count").addClass("text-danger");
    //していないときはtext-dangerをtext-sucsessに。
    }else if (count < max){
      $(".text-count").removeClass("text-danger");
      $(".text-count").addClass("text-success");
    }
    //残りの入力できる文字数を表示
    $(".text-count").text( "あと" + now_count + "文字");
  };

  //関数呼び出し（ページ読み込み時）
  addClassToTextCounter($(".introduction"));

 // キーボードを押した時にも発火させる
  $(".introduction").on("keyup", function() {
     addClassToTextCounter($(this));
  });
});
</script>
```
機能としてはここまでで完成です。

### ③パーシャル化
拡張性を考慮して、Job以外のモデルでも同じ機能が使いやすいようにscriptタグの部分をパーシャル化します。
フォーム最下部で呼び出すように書き直します。最大文字数はモデルごとに変えるかもしれないので変数にして渡します。
```slim:app/views/jobs/new.html.slim
//最下部に追記
= render "/layouts/textcounter", max: 3000
```
<br>
先ほどのscriptタグ部分を切り出して、変数maxだけ呼び出し時に渡される値を使うようにします。

```erb:app/views/layouts/_textcounter.html.erb
<script>
$(function (){
  const max = <%= max %> //ここだけ変更！！！

  const addClassToTextCounter = elem => {
    const count = elem.val().replace(/\n/g, "改行").length;
    const now_count = max - count;
    if (count > max) {
      $(".text-count").removeClass("text-success");
      $(".text-count").addClass("text-danger");
    }else if (count < max){
      $(".text-count").removeClass("text-danger");
      $(".text-count").addClass("text-success");
    }
    $(".text-count").text( "あと" + now_count + "文字");
  };

  //関数呼び出し（ページ読み込み時）
  addClassToTextCounter($(".introduction"));

 // キーボードを押した時にも発火させる
  $(".introduction").on("keyup", function() {
     addClassToTextCounter($(this));
  });
});
</script>
```
他のファイルから呼び出すときには、maxにつど文字数を渡してやれば同じように動作させられます。