hiyoko-programingの日記

プログラミングを勉強したてのひよっ子。   エンジニア目指して勉強中。

jQueryを使って検索機能を実装

以下のような検索ボックスに入力した文字と一致するフルーツが検索できるアプリケーションを作成する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//8b6a10197e9a5a04ca91ca93f5c5dd4d.gif

事前準備

アプリケーションをクローンする

ターミナル
1
2
3
$ cd  #ホームディレクトリに移動
$ cd projects  #projectsディレクトリに移動
$ git clone https://github.com/we-b/jquery-exercise.git -b for_clone  #クローンする

フォルダ構成を確認する

ダウンロードしたアプリケーションが以下のような構成になっているか確認する。

  •  jquery-exercise
  • index.html
  • style.css
  • main.js

jquery-exerciseフォルダの中のファイルの中のmain.jsのみを編集する。

 1. 検索ボタンを押した時に入力されたものを表示する

検索ボックスに入力後、検索ボタンを押した時に入力された文字をページ上に表示するようにする。

index.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    <script src="main.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <div class="form-group">
      <input type='text' id="keyword" class="form-control" placeholder="好きなフルーツを入力してください">
      <button type="button" id="submit" class="btn">検索</button>
    </div>
    <p id="result"></p>
  </body>
</html>

フォームに入力された値は、15行目のpタグの中に表示させる。

検索ボックスに入力後、検索ボタンを押した時に入力された文字をページ上に表示する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//73a37c08befe42995db800b1be3072c8.gif

作業ファイル

main.js

①検索ボタンがクリックされた際にイベントが発火させる。

https://tech-master.s3.amazonaws.com/uploads/curriculums//04e1008842f96b39f2f036d2537947b9.png

1
2
3
  $("検索ボタンのidセレクタを指定").on("click", function() {
    // 処理
  });


②入力された値を取得するval()を使用する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//c524f0c13ea5f0391ce4db9f5c33ca14.png


③取得した値を表示するtext()を使う。
text()を使用して、引数に取得した要素を取って、表示する

main.js
1
2
3
4
5
6
$(function() {
  $("#submit").on("click", function() {
    let input = $("#keyword").val();
    $("#result").text(input);
  });
});

2行目で、検索ボタンがクリックされた時に処理を行うようにしている。
検索ボタンのidがsubmitなので、要素の指定は#submitとすれば良い。

3行目で、フォームに入力された値を取得していく。
val()を使うことで、入力された値を取得できます。取得した値をinputという変数に代入している。

4行目で、text()を使ってHTML要素のテキストを書き換えている。書き換えるべきHTML要素はpタグということだったので、#resultをセレクタに指定すれば良い。

 2.入力された条件で検索して表示する

続いて、入力された言葉に一致するものを表示する。検索に使うデータは、main.jsの1行目に定義されているフルーツ名が要素として入っている配列を使用する。入力された値を配列の中のデータと照らし合わせて、一致したものを同じようにpタグの中に表示させる。

検索ボックスに入力後に検索ボタンを押した時に、入力された文字をページ上に表示するようにする。

https://tech-master.s3.amazonaws.com/uploads/curriculums//96df867904b23fdf62bb170624152173.gif

 

実装のヒント

each文を使用して入力された値と配列の要素を1つずつ比較しましょう。

https://tech-master.s3.amazonaws.com/uploads/curriculums//b3fb45b7db6692587cf69b8d763f499f.png

main.js
1
2
3
4
$.each(fruits, function(i, fruit) {
    // 配列の要素fruitと入力した値が一致するかどうかの処理を書く
    // 一致したらループ抜ける
});

jQueryにも、一致したらループ処理を抜けるRubyで言うbreak文のようなものがあるので、リファレンスで調べて記入する。

main.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var fruits = ['apple', 'apricot', 'avocado', 'blueberry', 'cherry', 'coconut', 'cranberry', 'dragonfruit', 'durian', 'grape', 'grapefruit', 'guava', 'kiwi fruit', 'lemon', 'lime', 'lychee', 'mango', 'melon', 'watermelon', 'miracle fruit', 'orange', 'bloodorange','clementine','mandarine','tangerine','papaya','passionfruit','peach','pear','persimmon','physalis','plum/prune','pineapple','pomegranate','raspberry','rambutan','star fruit','strawberry'];

$(function() {
  $("#submit").on("click", function() {
    let input = $("#keyword").val();
    $.each(fruits, function(i, fruit) {
      if (input === fruit) {
        $("#result").text(input);
        return false;
      } 
    });
  });
});

ポイントは、入力された値と配列の要素を比較して一致したものを見つけること。
配列の要素を比較するには、配列の要素を一つずつ取り出して比較する必要がある。配列の要素一つずつを取り出して何らかの処理をするには、$.each()を使用する。

6行目から、$.each()を使用している。$.each()の第一引数には、入力された値と比較する配列(変数名がfruits)を渡す。配列から取り出した要素に対する処理の内容は、入力された要素と配列の要素が一致した場合にpタグ内のテキストを入力された値にするようにする。

main.js
1
2
3
4
5
// 入力した値と配列要素の値が一致したら、`return false`でループを抜ける
if (input === fruit) {
        $("#result").text(input);
        return false;
} 

一致するものが見つかったら、そのあとは繰り返さなくて良いのでRubyで言うbreak文にあたる、return falseを使用して繰り返し処理が終了するようにする。
ちなみに、return trueを指定すると、Rubyで言うnext文と同じで、ループの次の処理を行う。

 3.一致するものがなかった場合の表示を考える

一致するものは表示できるようになったので、今度は一致するものがなかった場合に、「一致するものがありませんでした。」と表示する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//a162423b3ac562dc59a70f2b6828e3e8.gif

実装のヒント

elseを使って"一致する果物はありませんでした。"と表示できるようにする。

解答・解説

main.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
let fruits = ['apple', 'apricot', 'avocado', 'blueberry', 'cherry', 'coconut', 'cranberry', 'dragonfruit', 'durian', 'grape', 'grapefruit', 'guava', 'kiwi fruit', 'lemon', 'lime', 'lychee', 'mango', 'melon', 'watermelon', 'miracle fruit', 'orange', 'bloodorange','clementine','mandarine','tangerine','papaya','passionfruit','peach','pear','persimmon','physalis','plum/prune','pineapple','pomegranate','raspberry','rambutan','star fruit','strawberry'];

$(function() {
  $("#submit").on("click", function() {
     let input = $("#keyword").val();
    $.each(fruits, function(i, fruit) {
      if (input === fruit) {
        $("#result").text(input);
        return false;
      } else {
        $("#result").text("一致する果物はありませんでした。");
      }
    });
  });
});

一致しなかった場合の条件分岐を追加するだけで良い。

 4.一部の言葉で検索できるようにする

今の時点では、入力された値と配列の要素名が完全に一致しないとページに表示されない。文字が一部しか入力されていない状態で検索ボタンが押された時に、その文字と一致するものがあれば表示できるようにする。
「ap」と検索したら「appleとaprcot」が一致するので、この2つのフルーツが表示されるようにする。このように単語の前方と一致する単語を検索することを前方一致という。前方一致で検索をするには、正規表現を使う必要がある。

https://tech-master.s3.amazonaws.com/uploads/curriculums//322955ee43916cbb34df2ffab21ef5e0.gif

検索結果が複数になる可能性があるので、ulタグを使用して結果をliタグで表示する。

index.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    <script src="main.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <div class="form-group">
      <input type='text' id="keyword" class="form-control" placeholder="好きなフルーツを入力してください">
      <button type="button" id="submit" class="btn">検索</button>
    </div>
    <ul id="list"></ul>
  </body>
</html>

実装のヒント

JavaScriptでの正規表現の書き方を調べる。
②matchメソッドを使用して、正規表現と比較することができる。

引数に正規表現オブジェクトを使用するため、RegExp()で変換する必要がある。(match, 前方一致を検索)

1
2
3
4
5
// 正規表現オブジェクトに変換
let reg = new RegExp("前方一致");

// matchメソッドで一致したらtrueかfalseを戻す
match(reg);

③検索結果はli要素で出力する(append()を使用してli要素に出力する値を追加する)
④2度目以降に検索された時に前の検索結果が残らないようにする

 

ヒント
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$(function() {
  // id名がlistを取得し、変数に格納
  let list =

  // append()を使って、listに値を出力するappendList(word)関数としてまとめる
  function appendList(word) {
    // 処理
  }

  $("#submit").on("click", function() {
    let input = $("#keyword").val();
    // 正規表現オブジェクトを生成し、変数に格納する
    let reg =

    // listクラスを取り除く 
    $(".list").

    $.each(fruits, function(i, fruit) {
      // fruitとマッチしたらlistクラスに出力する
    });

    if ($(".list").length === 0) {
      appendList("一致する果物はありませんでした");
    }
  });
});

 

main.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$(function() {
  let list = $("#list");

  function appendList(word) {
    let item = $('<li class="list">').append(word);
    list.append(item);
  }

  $("#submit").on("click", function() {
    let input = $("#keyword").val();
    let reg = new RegExp("^" + input);

    $(".list").remove();

    $.each(fruits, function(i, fruit) {
      if (fruit.match(reg)) {
        appendList(fruit);
      }
    });

    if ($(".list").length === 0) {
      appendList("一致する果物はありませんでした");
    }
  });
});

ポイントは、正規表現によって入力された値で配列の要素に対して前方一致での検索を行うこと。
11行目で、入力された値をRegExp()を使って正規表現として使用できるようにしている。^を使うことで前方一致で検索できるようになる。この時regという変数に格納している。

main.js
1
2
// 正規表現オブジェクトを生成して、変数regに格納する
let reg = new RegExp("^" + input);

16行目で、match()を使用して配列の要素に一致するものがあるか調べています。ある場合は、テキストが要素名のliタグを作成しappend()を使ってHTML要素を追加している。liタグにクラスを追加しているのは、2回目以降の検索時に前の検索結果をremove()を使って削除するため(13行目)。

main.js
1
2
3
4
5
6
7
    $(".list").remove();

    $.each(fruits, function(i, fruit) {
      if (fruit.match(reg)) {
        appendList(fruit);
      }
    });

21行目で、クラスセレクタが一つもない場合は、入力された値に一致する要素がないことになるので、「一致する果物はありませんでした」と表示する。

main.js
1
2
3
if ($(".list").length === 0) {
      appendList("一致する果物はありませんでした");
}

一致する要素があった場合も一致する要素がなかった場合も、liタグを追加する記述はほとんど一緒なので、appendListというメソッドにまとめている。

main.js
1
2
3
4
function appendList(word) {
  let item = $('<li class="list">').append(word);
  list.append(item);
}

 5.複数の言葉で検索できるようにしよう

これまでは、1つの言葉で検索してたが、複数の言葉でも検索できるようにする。「ap k」と検索された場合、「apple, apricot, kiwi fruit」が一致するので、これら3つが表示されるようにする。

https://tech-master.s3.amazonaws.com/uploads/curriculums//66054265d26fe7a7da8a582ef2b15e9f.gif

実装のヒント

最終ゴールのイメージをつかもう

「"ap"または(or)"k"」という文字列に対して、配列fruitsとマッチするものを検索するという実装する。

 

splitを使って文字列から配列を作成

https://tech-master.s3.amazonaws.com/uploads/curriculums//721f558b899f59e949dc979f9e0d2582.png

mapを使って配列要素を前方一致で加工した新しい配列を作成

https://tech-master.s3.amazonaws.com/uploads/curriculums//a9880f9b21745576f0ea3eeacb680f13.png

joinを使ってor検索で配列の要素をつないだ正規表現を作成(joinを検索してみましょう)

https://tech-master.s3.amazonaws.com/uploads/curriculums//f0cfca27d28247d41be27149b8819e0e.png


解答・解説

main.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let fruits = ['apple', 'apricot', 'avocado', 'blueberry', 'cherry', 'coconut', 'cranberry', 'dragonfruit', 'durian', 'grape', 'grapefruit', 'guava', 'kiwi fruit', 'lemon', 'lime', 'lychee', 'mango', 'melon', 'watermelon', 'miracle fruit', 'orange', 'bloodorange','clementine','mandarine','tangerine','papaya','passionfruit','peach','pear','persimmon','physalis','plum/prune','pineapple','pomegranate','raspberry','rambutan','star fruit','strawberry'];

$(function() {
  let list = $("#list");

  function appendList(word) {
    let item = $('<li class="list">').append(word);
    list.append(item);
  }

  function editElement(element) {
    let result = "^" + element;
    return result;
  }

  $("#submit").on("click", function() {
    let input = $("#keyword").val();
    let inputs = input.split(" ");
    let newInputs = inputs.map(editElement);
    let reg = RegExp(newInputs.join("|"));

    $(".list").remove();

    $.each(fruits, function(i, fruit) {
      if (fruit.match(reg)) {
        appendList(fruit);
      }
    });

    if ($(".list").length === 0) {
      appendList("一致する果物はありませんでした");
    }
  });
});

ポイント① splitを使って文字列から配列を作成

複数の言葉を入力するときは、言葉と言葉の間にスペースが入る。スペースで区切って配列を作成すれば良い。このようにある文字列を特定の文字で区切った配列を作成する場合にはsplit()を使用。
18行目では、引数にスペースを指定することで、スペースで文字列を区切った配列を作成。

18行目
18
 let inputs = input.split(" ");

split()

split()は、文字列を複数の部分文字列に区切り、文字列の配列に分割する。引数には文字列を区切るための文字を指定。

ポイント② mapを使って要素を加工した新しい配列を作成する

前方一致に対応するためには、^を検索する言葉の前につける必要がある。splitで作成した配列要素の前に^をつければ前方一致ができそう。このように配列の要素を加工した新しい配列を作成するには、map()を使用。
19行目では、map()の引数に要素の頭に^をつける関数editElementを渡している。map()によって作成された新しい配列をnewInputsという変数に格納している。

19行目
19
let newInputs = inputs.map(editElement);

map()

map()は、配列から要素を1つずつ取り出し、引数に与えられた関数の処理を行った結果から新しい配列を作る。

ポイント③ joinを使って|で配列の要素をつないだ正規表現を作成する

複数の言葉で正規表現を使用するには|を使って言葉を繋げます。複数の言葉が要素の配列newInputsの要素を|でつなぐことで複数検索ができるようにする。配列の要素をつなげるには、join()を使用する。
20行目では、join()の引数に|を渡すことでnewInputsの要素を|でつないでいる。その結果をRegExpの引数に渡すことで正規表現を作成している。

20行目
20
 let reg = RegExp(newInputs.join("|"));

join()

join()は、配列のすべての要素をつないだ文字列を作成する。引数に文字列を渡すと、その文字列で文字と文字をつなげる。