今回は、記事にタグ付するために以下の機能を実現する
①タグを選択するチェックボックス
②新しいタグを作成できる
③タグを作成した際、チェックボックスを自動で更新
開発の方向性
- 存在するタグの数に応じてチェックボックスを作成する
- クライアントでタグを取得
- 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の通信先)
webAPIとは
- 特定の機能を持つプログラム部品。
- ある機能を提供してくれるだけしっていれば、その内部がどう実装されているか知る必要がなく、関数の考え方に似ている。
- Web APIで機能を公開しているサーバに対して、インターネットを通じて依頼内容をHTTPリクエストの形で送信すると、処理結果がHTTPレスポンスの形で送られてくる
- 送受信するデータの形式は、XMLやHTML、JSON、各種の画像ファイル形式
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スコープ(関数内で使える)