【jquery】ajaxでpostする方法

ajaxをつかって非同期的にpostする方法について
基本的なやり方を書いておきます。

jsではpostしたいタイミングで以下のように記述します。

$.post('post先.php', {
            // 送りたいデータ
            data1_name : data1_content
            data2_name : 'data2_content'
        }, function(res){
               // post先.phpで echo した内容がresに入ってくる
               // 送信後の処理をここにかく
        }
    );

送信成功/失敗で処理を分けたい場合は
$.post() でなく $.ajax()を使う必要があります。

post内容を受け取るをphpで受け取る場合
送信先.php は以下のように記述します。

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        $res = '何らかの処理をした結果';
        header('Content-Type: application/json');
        echo json_encode($res);
        exit;
    } catch (Exception $e) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error!!', true, 500);
        echo $e->getMessage();
        exit;
    }
}

複数のデータをまとめて返す場合、

header('Content-Type: application/json');
と echo の前に書くことで結果をjson形式にでき,js側で連想配列として扱えるようになります。

【html】チェックボックスの内容がsubmitされないとき

inputタグのチェックボックスは未チェックだとdisable属性がついてしまい、
submitしてもなにも送信されません。
「未チェック」という値がないということです。

では、「チェックしている=”1”」「チェックしてない=”0”」といったふうに値を設定するにはどうすればいいでしょうか?

htmlの場合は次のように記述すれば解決できます。

<input type="hidden"   name="checkbox_name" value="0">
<input type="checkbox" name="checkbox_name"/>

「hidden」タイプの同名inputタグを作っておいて、value=0を設定しておきます。

こうすることで未チェック(=diabled)のときは前行のvalue=0が残ったままになるので、「チェックしている=”1”」「チェックしてない=”0”」とできます。

【CakePHP】ページネーションの基礎の基礎

ページネーションとは?

たくさん並んだデータをページ分けして、任意のページを開きやすくすることです。


わかりやすい例はGoogleの検索結果です。
ふつうGoogleの検索結果は、クエリにもよりますが膨大な件数で返ってきます。
ところが実際に画面に表示されるのは上位10件ほどで、残りは画面下方にあるページ選択を押すことでアクセスできます。

CakePHPでのページネーションとは、データベースに問い合わせて返ってきた結果を
一度に全て表示するのではなく、
上位数件のみを表示させ、残りを他のページへのジャンプ用リンクを使って表示させることをいいます。

 

今回はごくシンプルに、レコードをid昇順で表示させた上での
ページネーションをやってみます。

 

コントローラへの記述

public $paginate = array( 'limit' => 5, 'sort' => 'id', );

public
function index() { $this->set('items', $this->paginate()); }

$pagenateという配列を定義します。
limitには一度に表示する件数、'sort'には並び替えのキーにしたいフィールド名を入れておきます。

続いてthis->setでビューにページ分けされたレコードを送ります。

 

ビューへの記述

<table>
<tr>
<?php foreach ($items as $item): ?>
<td><?php echo $item['Item']['field_1']; ?></td>
<td><?php echo $item['Item']['field_2']; ?></td>
<td><?php echo $item['Item']['field_3']; ?></td>
<?php endforeach; ?>
</tr>
</table>

<?php echo $this->Paginator->numbers ( array ( 'before' => $this->Paginator->hasPrev() ? $this->Paginator->first('<<') : '', 'after' => $this->Paginator->hasNext() ? $this->Paginator->last('>>') : '', ) ); ?>

いつものようにforeach等でレコードを表示させたあと、Paginator->numbersでジャンプ用リンクを作ります。
これだけでもページ番号の数字は表示されますが、
beforeとafterを設定することで数字の前後のボタン(最初や最後にジャンプ、など)を設定できます。

 

ここではhasPrev(),hasNext()を使って、現在の表示ページよりも
前のページ、もしくは後ろのページがあれば''<<"というリンクを表示させています。

 

参考

https://book.cakephp.org/3.0/ja/controllers/components/pagination.html

http://cakephp.popotoo.com/other/310/

【CakePHP】データベースへのsave前にデータを編集するには?

データベースへsave, 送信する前に
フォームの入力内容を編集したいときってあると思います。

例えば入力フォームをデフォルトからいじったとかで、
入力内容のフォーマットとデータベースのカラムの型が合わなくなってしまった場合なんかが考えられます。

 

こういった場合はモデルの中に
beforeSaveという関数を定義することで解決できます。

beforeSaveはモデルの内容に関する処理の前後で呼び出される
コールバック関数の一つです。

他にもafterSaveといったものや、findやdeleteなどの前後で呼び出される関数があります。

 

使い方はこんな感じです。

```php
<?php
class Item extends AppModel {

public function beforeSave($options = array()) {
$this->data["Item"]["date"] = $this->formatDate($this->data["Item"]["date"]);

return true;
}


public function formatDate($date){
// 何かしらの処理
return $date;
}
}


```

注意すべき点は最後にreturn trueすることです。
trueが返されないとsaveが行われなくなってしまいます。

【CakePHP】その場編集(edit in place)をプラグインでやってみる

excelのセルを書き換えるときのように、
テキストをクリックしたら、テキストそのものが編集フォームに置き換わる(=その場編集、edit in place, eip)サイトがありますよね。

あれをCakePHPでやろうとしたのですが、検索でヒットした方法はAjaxヘルパーやjsヘルパーを使ったものでした。
これらは最近非推奨だったり、将来的になくなってしまうとのことなので
思い切ってプラグインを使ってみることにしました。

 

今回使ったのはこちらです。

github.com

 

さて、結論から言いますとうまく動かなかったのですが、
たぶん導入まではうまくいったと思いますので手順を書いておきます。

導入手順

まずは上記githubプラグインをクローンします。

git clone https://github.com/zeroasterisk/CakePHP-Eip.git app/Plugin/Eip

続いてプラグインEipフォルダに含まれるbootstrap-editableをeipとしてapp/webrootにコピーします。

cd app/webroot
cp -r ../Plugin/Eip/webroot/bootstrap-editable/bootstrap-editable eip

次に設定ファイルをコピーします

cd app/Config
cp ../Plugin/Eip/Config/eip.php ./

次にConfigフォルダにあるbootstrap.phpの末尾に
次の1行を書き加えます

CakePlugin::load('Eip');

githubのREADMEにはここまでしか書かれていませんが、
プラグインのヘルパーファイル

app/Plugin/Eip/View/Helper/EipHelper.php
にStringクラス(CakePHPのバージョン2.7以降では廃止)が使われているので、該当行(たぶん284行目)を書き変えます。

// generate an elementId
$elementId = $key = 'eip_' . CakeText::uuid();

これで導入完了です。

あとはREADMEのUsageの通りにやれば使えるはず…なのですが
私の場合、とくにエラーは出ないけど、eip化したテキストをクリックしても何も起きないという現象に見舞われています。
ちょっと原因を特定するのに時間がかかりそうです…

【jquery】表のセルを選択可能にする

excelの表みたいに「いまここを選んでますよ」というのを表示する機能を
HTMLの表で実現する方法をまとめておきます。

 

今回は一つのセルだけ選択できるようにしたいと思います。
これを実現するためにはざっくり次の2つの処理が必要になります。

  • クリックしたセルが何かしらのアクションをする(色が変わるなど)
  • セルAを選択した状態でセルBを押すと、Bが選択された状態になり
    Aは選択されていない状態に戻る

こちらをjqueryで実装すると次のような感じになると思います。

var selectedTd;
$('td').dblclick(function(){
    $(selectedTd).css('color', '#000000');
    selectedTd = '#' + $(this).attr('id')
    $(selectedTd).css('color', '#013ADF');
});

ダブルクリックされた<td>のidをselectedTdに格納しておき、色変更などのアクションをさせます。
次に他のtdがダブルクリックされたときはselectedTdに、一つ前に選択されていたtdのidが格納されています。
この値を使って選択前の状態を復元することで、excelのようなセル選択が可能になります。

 

【css / javascript】スクロールバーが反応しない!?

先日、こんな感じ↓のレイアウトを作ろうとしました。

f:id:kento0824jp:20171112225406p:plain

要素Aの子に横スクロールできる要素1があって、
要素2がその下にくっついてる感じです。

今回親要素にはposition: relative、要素1にはposition: absoluteが設定されてるので、要素2は要素1の高さの影響を受けません。
また、要素1の高ささをいろいろと変えたいので、親要素には高さを設定していません。
なのでそのままだと要素2は要素1に重なってしまいます。

 

これを回避するためにこんなスクリプトを当てていました。

$(function(){
    var youso1_height = $('#youso1').height();
    $('#youso2').css('top', youso1_height + 'px');
});

要素1の高さを要素2の位置(top)に設定します。
これできれいに縦に並んだぜ!やったぜ!と思いきや…

要素1のスクロールバーがまったく反応しない(押せない)事態が発生。
(表示はされてます)

これはどうしましょう…と会社の先輩方に相談したところ、
大変迅速に原因と対処法を頂いたのでまとめておきます。

 

原因

そもそもの原因は要素2がスクロールバーの上に重なってしまっていることでした。
要素が上に重なっていると、スクロールバーを押すことは出来ないみたいです。

 

今回は要素2のtopを要素1のheightと同じ値に設定していたのですが、
これは要素1と2が1ピクセルの隙間もなく縦に並ぶことを意味します。

一方でスクロールバーは要素1をちょっとはみ出た所に表示されるので、今回のようなことが起きてしまったのです。

 

ちなみに実験してみたのですが、
marginが重なるのはokpaddingはダメでした。borderより内側ならダメということですね。

対処法

jsで設定する要素2のtopに適当な数字を足して、要素1との間に隙間をあけてやればOKです。

$(function(){
    var youso1_height = $('#youso1').height();
    var youso2_top = youso1_height;
    $('#youso2').css('top', youso2_top + 'px');
});

もしくは要素1にmargin-bottomを適当に設定して、heightでなくouterHeightを取得する方法でもOKです。

$(function(){
    var youso1_height = $('#youso1').outerHeight();
    $('#youso2').css('top', youso1_height + 'px');
});

 

 

まとめ

スクロールバーは、上にある要素のborderより内側が重なっていると押せない。

 

position:absoluteを使うときは要注意ですね…