LoginSignup
0
0

More than 3 years have passed since last update.

CakePHP ブログチュートリアル tag機能をJavaScriptで実装

Last updated at Posted at 2020-04-28

本章の内容

CakePHPブログチュートリアルに追加したタグ機能をJavaScriptで実装させる。

JavaScriptで実装させる理由

CakePHPブログチュートリアルに、PHPのみでタグ機能を実装してしまうと、サーバーの通信を待たなければならない。
PHPのみで実装すると、新しいタグを追加する際に、記事の編集内容が保存されない。

そこで、JavaScriptによってView上で処理させることによって、タグ追加を実装させる。
これにより、サーバーの通信を待たずに処理ができるので、記事の内容に影響なく保存ができる。

注意 : JavaScriptの処理が大きくなりすぎると、ブラウザ上での処理が重くなってしまうので注意する。

タグ機能を使用している場所と機能

  • add.ctp、edit.ctp
    • タグの一覧表示
    • タグの選択
    • 新しいタグの追加
  • index.ctp
    • タグの一覧表示
    • タグの選択

CakePHP 2.xでJavaScriptを書く方法

HtmlHelperで書く

JavaScriptファイルを作成する

/app/webroot/jsのディレクトリの中にJavaScriptファイルを作成する。

Viewファイルで下記のように呼び出す。(パスは絶対パスを指定)

echo $this->Html->script('script_file');

Viewファイルに直接書く

下記のいずれかで<script>開始タグを生成する。

$this->Html->scriptBlock($code, $options = array());

$this->Html->scriptStart($options = array());

scriptBlockは、変数$codeを含めた開始タグである。

そして、下記のようにして</script>終了タグを生成する。

$this->Html->scriptEnd();

上記の開始タグと終了タグの間に、JSの処理を書いていくのだが、JSHelperは、推奨されていない。

また、直接<script></script>を書いて動かすことも可能。

調べたこと

変数の受け渡し

json_encode($value)により、与えられた$valueをJSON形式にした文字列を返す。

これを使って、下記のようにすることで、PHPからJavaScriptに値を渡すことができる。


var 変数 = <?php echo json_encode($value); ?>;

連想配列から値だけを取り出す

下記のようにして、連想配列から値だけをリスト化することができる。

var data = {a:1 ,b:2};

var data_list = Object.values(data);  // [1,2]

配列の中に特定の値があるか判定

リスト.indexOf(値)で、リストの中にある特定の値のindex値を返す。リストの中に含まれていなければ、-1を返す。

下記のようにして、あるかないかを判定できる。

if(list.indexOf(value) !== -1){
    //listにvalueが含まれているときの処理
}

変数の型を調べる

typeof(変数)で型が調べられる。

valueをJSで受け取る

下記のようにdocument.getElementById()を使うことで、指定したidの要素を表すElementオブジェクトを返す。

View側
<input id="id.name">
JS側
var element = document.getElementById("id.name");

これを使い、下記のようにしてvalueを取得する。

JS側
var value = document.getElementById("id.name").value;

JSでHTML要素を生成する

document.createElement("HTMLの要素")を使って指定したHTML要素をJavaScript上で生成することができる。

また、setAttribute()を使うことで、指定した要素に新しい属性を追加することができる。

const element = document.createElement("input");
element.setAttribute("id","id.name");
element.setAttribute("type","button");

上記の結果

<input id="id.name" type="button">

HTML要素を動的に追加する

上記のcreateElementsetAttributeを使って作成したHTML要素を、appendChild()を使って特定の親ノードの子ノードの末尾にノード(作成したHTML要素)を追加することができる。

<script>
function add (){
    const Parent = document.getElementById("parent");
    const child = document.createElement("input");
    child.setAttribute("id","child.id");

    Parent.appendChild(child);
}
</script>

<input type="button" onclick="add()">  //このボタンを押すと下記のようになる
View側
<div id="parent">
    <input id="child.id">
</div>

ajaxについて(Asynchronous JavaScript + XML)

参考資料

ajaxは、サーバーと非同期通信処理を行う。

同期通信の場合
webブラウザからサーバーにリクエストを通信して、レスポンスが返ってくる。
その際、全ての情報を通信するため、画面が白くなる。(リロード状態)

非同期通信の場合
webブラウザから一部の情報をリクエストするので、それ以外の部分は変わらない。
サーバーからのレスポンスが返ってこなくても他の作業ができる。
(リロードしなくても情報がとってこれる)

ajaxの仕組み

  • XMLHttpRequest

ブラウザ上でサーバーとHTTP通信(POSTとかGETとか)を行うためのAPI。

  • JavaScript

XMLHttpRequestがjavascriptの組み込みオブジェクトのため、jsを用いる。

  • DOM(Document Object Model)

Ajaxを使って動的なWebページを作成するときに、HTML,XML上のどの要素を変更するかを指定する。
DOMは、HTMLやXMLを「ツリー構造」として展開し、アプリケーション側に文章の情報を伝え、加工や変更をしやすくする。

  • XML(Extensible Markup Language)

文書やデータの意味や構造を記述するためのマークアップ言語の一つ。

ajaxを使ってタグ情報を取得する流れ

タグ一覧

  1. ページ上でイベント発生(get:ページを表示)
  2. JS+XMLHttpRequestでサーバーに対してリクエストを送信(全てのTagの情報を取得。find('list')とか)
  3. リクエストした情報取得

タグ追加

  1. ページ上でイベント発生(post:タグ追加ボタン)
  2. JS+XMLHttpRequestでサーバーに対してリクエストを送信(新しいタグの追加save?
  3. サーバーからsaveが成功したってくる(saveした情報はこの時点では得られてない)
  4. JS+XMLHttpRequestでサーバーに対してリクエストを送信(全てのTagの情報を取得。find('list')とか)
  5. リクエストした情報取得

ajaxの使い方

データビューを有効にする
app/Config/routes.phpにRouter::parseExtensions();を追加。
ControllerのcomponentsにRequestHandlerを追加。

続いて、下記のようにControllerにDBからデータを取ってきて、ajaxに送る。

Controller
public function hoge(){
    $data = $this->MODEL->find('list');
    $this->set(compact('data'));
    $this->set('_serialize',array('data'));
}
View
//省略

<?php echo $this->Html->script('javascript');?>

//省略

下記のexecAjax()を実行すれば、データを取得することができる。

javascript
function execAjax() {
    var xhr = new XMLHttpRequest();

    xhr.open('GET', '/****/hoge.json');
    xhr.send();

    xhr.onreadystatechange = function() {
        if(xhr.readyState === 4 && xhr.status === 200) {
        //データを取得後の処理を書く
            console.log(xhr.responseText);  //Controllerで送ったデータがjson形式で入っている。
        }
    }
}

JSでjson形式のものをobjectとして受け取る

JSON.parse(text)メソッドは文字列(text)をJSONとして解析し、文字列によって記述されているJavaScriptの値やオブジェクトを構築する。

ajax通信で値を送信する

GET

URLの後ろに送りたいデータを付与して送る

http://*****/**?パラメータ名=値という感じで送る。
複数送るときは、&で区切る。

送るデータは、表示的にクライアントに見える。(URLに書かれているため)

データを取得したいとき、データベースの書き換えが必要ないときに使う。

POST

.send()に送りたいデータを入れる。
.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");を指定しなければならない。
上記の例は、string型で送れるようにしている。
文字列で送るなら.send("パラメータ名=値")という感じ。

送るデータは、表示的にクライアントに見えないが、通信内容を見に行った場合見れる。

データの変更、ソート、更新、削除、新規登録などで使用するとき、
パスワードのような秘匿情報をURLに表示したくないとき、
送信するデータ量が多いとき、
バイナリデータを送信したいときなどに使う。

ajax通信で送信したデータをControllerで受け取る

GETで送ったものは$this->request->queryに入っているので、そこから取得する。
POSTで送ったものは、$this->request->dataに入っているので、そこから取得する。

findでjoinする方法

findのオプションでjoinsを使うことでテーブルをjoinしてデータを取ってくることができる。

$options['joins'] = array(
    array('table' => 'テーブル名',
        'type' => 'JOINの種類',
        'conditions' => array(
            'モデル名.カラム名 = テーブル名.カラム名',
            'テーブル名.カラム名 = 値'
            )
        )
    );

$変数名 = $this->モデル名->find('all',$options);

HTML要素の再構築

cloneNodeにfalseを渡すことで、中身を空の状態にしたHTML要素をクローンすることができる。


const Parent = document.getElementById("id.name");
const clone = Parent.cloneNode(false);

下記のreplaceChild()を使うことで、「Parent」を「clone」として置き換えることができる。
それをparentNodeでParentに渡すことでParentの中身を更新しているように見せている。


Parent.parentNode.replaceChild(clone, Parent);
0
0
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
0