LoginSignup
0
2

More than 3 years have passed since last update.

ajaxを用いた動的なチェックボックス

Last updated at Posted at 2020-05-05

今回は、記事にタグ付するために以下の機能を実現する
①タグを選択するチェックボックス
②新しいタグを作成できる
③タグを作成した際、チェックボックスを自動で更新

開発の方向性

  • 存在するタグの数に応じてチェックボックスを作成する
  • クライアントでタグを取得
    • tagデータをjson形式で返すapiを作る(データを返すurl、cakephp)(ajaxの通信先)
    • ajaxでapiにHttpリクエストを投げる
  • 新しいタグを追加する
    • tag情報を送ると、保存してくれるapiを作る(ajaxの通信先)
    • タグの追加が終わったタイミングでtagデータを返すapiを呼び出し、追加したデータを取得する

存在するタグの数に応じてチェックボックスを作成する

タグの数分、ループを回し、その都度document.createElement("input");
などでHtmlタグを生成する。

function make_checkbox(tags) {
    var box = document.getElementsByClassName("box");
    var number_checkbox=Object.values(box).length;
    if(Object.keys(tags).length==number_checkbox+1){ //追加したタグの時
        checkbox_key = [Object.keys(tags)[Object.keys(tags).length-1]];
    }else{
        checkbox_key = Object.keys(tags);
    }
    checkbox_key.forEach(
        function(key){
            tag_name = Object.keys(tags[key]);
            var checkbox = document.createElement("input");
            checkbox.setAttribute("type", "checkbox");
            checkbox.setAttribute("name", "data[tag][]");
            checkbox.setAttribute("value", key);
            checkbox.setAttribute("id", "Tag"+key);
            checkbox.setAttribute("class", "box");
            if(tags[key][tag_name]){
                checkbox.setAttribute("checked","checked");
            }
            var label = document.createElement("label");
            label.setAttribute("for","Tag"+key)
            label.innerHTML     = tag_name;
            var checkboxs = document.getElementById("checkbox");
            checkboxs.appendChild(checkbox);
            checkboxs.appendChild(label);
        }
    )
}
  • appendChildは、HTMLタグに入れ子構造で新たなHTMLタグを追加できる。* 参考

<div id="prime_minister_list"><div>

var abe = document.createElement("li"); //引数で指定したhtmlタグをさくせいする
abe.setAttribute("id", "abe_prime_minister"); //オプションの指定、例えば、name,id,value
abe.innerHTML     = "安倍晋三首相"; //タグの間の値

var prime_minister_list = document.getElementById("prime_minister_list"); //idがprime_minister_listのhtmlタグをとってくる

prime_minister_list.appendChild(abe); //とってきたhtmlタグに先ほど新しくつくったhtmlタグを挿入

クライアントでタグを取得

jQueryでajaxを利用するための設定

jsファイルで読み込む

<head><script src="jsファイルのパス"></script>

以下エラー

GET http://localhost:8000/posts/edit/tag.js net::ERR_ABORTED 404 (Not Found)

jsが読み込めない!!!
これが謎すぎるから、一旦無視

解決

htmlヘルパーを使った
echo $this->Html->script('scripts');

jqueryを使いたいがネットワークから使う方法を検討してみる

ネット経由で読み込む

jquery導入参考サイト
https://creive.me/archives/19581/#jQuery-2

<head><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>

tagデータをjson形式で返すapiを作る(データを返すurl、cakephp)(ajaxの通信先)

参考
ajaxの分かりやす参考資料
はじめてajax

webAPIとは

  • 特定の機能を持つプログラム部品。
    • ある機能を提供してくれるだけしっていれば、その内部がどう実装されているか知る必要がなく、関数の考え方に似ている。
    • Web APIで機能を公開しているサーバに対して、インターネットを通じて依頼内容をHTTPリクエストの形で送信すると、処理結果がHTTPレスポンスの形で送られてくる
    • 送受信するデータの形式は、XMLやHTML、JSON、各種の画像ファイル形式

webAPIの参考

jsonでデータを返すapiを作成

このサイトの手順でさくせいした

  • Router::parseExtensions('json'); をルータファイルに追加すると、 .json 拡張子の リクエストを受けた時や、 application/json ヘッダを受け取った時に CakePHP は自動的に ビュークラスを切り替えるようになります。
    • これをし設定しないと以下のようなエラーが出る
Error: The action addtag2.json is not defined in controller PostsController

public $components = array('RequestHandler');をしっかり描かないと以下のエラーが出るので注意!

Error: The view for TagsController::get_tag() was not found.

api(controllerのアクション=url)
findでデータベースからtag情報を返す。
他のアクションとあまり変わらない。setを2回やってるくらい?

public function get_tag(){
        $id = $this->request->query('id');
        $options['joins'] = array(
            array('table' => 'post_taggings',
                'type' => 'LEFT',
                'conditions' => array(
                    'Tag.id = post_taggings.tag_id',
                    "post_taggings.post_id = ${id}"
                )
            )
        );
        $options['fields'] = array('name','post_taggings.tag_id','id');
        $tags = $this->Tag->find('list',$options);
        $this->set(compact('tags'));
        $this->set('_serialize','tags');
    }
  • formやajax全てのhttp通信でクライアントからサーバに送られた値は、postの場合:サーバ側で$data = $this->request->data; getの場合:$page = $this->request->query();で取得する。
  • Joinの種類
    • 内部結合:共通部分だけをとってくる
    • 左外部結合:左にあるものを全部とってくる
    • 右外部結合:右にあるものを全部とってくる
    • 完全外部結合:どちらかにあれば全部とってくる

ajaxでapiにHttpリクエストを投げる

url = window.location.href; 
    var ary_url = url.split('/');
    let id = ary_url[ary_url.length - 1];
    $.ajax({
        type: 'GET',
        datatype:'json',
        url: "http://localhost:8000/tags/get_tag.json",
        data:{'id':id},
        success: function(data,dataType){         
           console.log(data);
           make_checkbox(data);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown){
            alert('Error : ' + errorThrown);
        }
    }).done(function(){
        ajax_get_tag();
    }
url = window.location.href; //http://localhost:8000/posts/edit/109が取得できる
    var ary_url = url.split('/'); // /で区切りリストを作る
    let id = ary_url[ary_url.length - 1]; 

新しいタグを追加する

tag情報を送ると、保存してくれるapiを作る(ajaxの通信先)

 public function save_tag(){
        $data = $this->request->data['name'];
        $this->Tag->save(array('name' => $data));
        $this->set(compact('data'));
        $this->set('_serialize','data');
    }

tag保存APIを呼び出す

tag保存APIへ通信が完了したタイミングでtagデータを返すapiを呼び出し、追加したデータを取得する

function ajax_post_tag(){
    var element = document.getElementById( "hoge" ) ;
    var data = { 'name' : element.value };

    $.ajax({
        type: 'POST',
        datatype:'json',
        url: "http://localhost:8000/tags/save_tag.json",
        data:data,
        success: function(data,dataType){         
           console.log(data);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown){
            alert('Error : ' + errorThrown);
        }
    })
}

※webブラウジング(初期ロード時)の際
window.onloadは、webブラウジングのさいhtmlが全て読み込まれた後に実行される。

window.onload = function(){
      ajax_get_tag(); //tag情報を取ってくる
}

開発を通しての学び

  • キャッシュクリア:jsやcssなどクライアント側の修正をしているときに、コードを直しても変化がない場合などがある。そのときはキャッシュクリアしよう。

  • if (!str) {変数strが空文字 or nullの時実行}

  • 入力フォームの値をボタンを押すと保存されるようにしたい

inputタグ間、例えば以下のように、text入力とbuttonがある。そのさい、buttonを押したときにtextのvalueがほしい。

<input id="hoge" type="text" value= " "><input type="button">

それを可能にするのが、EHTMLInputElement
https://syncer.jp/Web/API_Interface/Reference/IDL/HTMLInputElement/value/

  • $this->set(配列名、値)`とする必要があるが、compact()を用いると$this->set(compact(配列名))だけでいける。 compact(引数)は、引数に指定した配列名をキーとして配列の値をvalueとする。
  • letは、ブロックスコープ({})。varはfunctionスコープ(関数内で使える)
0
2
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
0
2