フォームの入力内容をAjaxで加工後、別タブに送信(Ajaxとsubmitの2回送信)


フォームで入力された内容を、別タブで確認させたいが、単にsubmitで送信するのではなく、一度プログラムを通して加工する必要がある、という面倒な案件があったので、メモとして残しておきます。

javascript

function sample(url){

  // フォームの入力内容を取得し、クエリ文字列に変換
  var form = $('#form_id');
  var query_str = form.serialize();

  var postData = {
    'query_str' : query_str,
  };

  $.ajax({
    async: false,       // ajax を同期処理にする
    url: './act.php',   // 送信先ファイル名
    type : 'POST',
    data : postData,
    timeout: 10000,

  }).done(function(getData){
    // 前回追加したフォームを削除
    var old = document.getElementById('append_data');
    if (old) {
      document.form_id.removeChild(old);
    }

    // ajaxで取得したデータをフォームに追加
    var appendData = document.createElement('input');
    appendData.type = 'hidden';
    appendData.id = 'append_data';
    appendData.name = 'append_data';
    appendData.value = getData;

    document.form_id.appendChild(appendData);
  });

  // 指定 URL に submit
  document.form_id.action = url;
  document.form_id.enctype = 'application/x-www-form-urlencoded';
  document.form_id.target = '_blank';
  document.form_id.submit();
}

 

処理内容は、以下の流れになってます。

1.フォームにデータを入力する
 

2.ボタンを押された際に「sample」関数を呼び出す

<input type="button" value="確認" onclick="sample('http://hoge.hoge/disp.html');">

 

3.フォームの入力内容を「serialize()」を使い、クエリ形式で取得

// クエリ形式
category=1&title=sample

 

4.act.php に ajax でPOST送信

act.php の例

// クエリ文字列の取得例
$input_data = '';

if (isset($_POST['query_str'])) {
    $query_str = $_POST['query_str'];

    // クエリ文字列として送られてきたフォームの値を、input_data に格納する
    parse_str($query_str, $input_data);

	// こんな感じで取得できる
    // $input_data['category'] = 1;
    // $input_data['title'] = 'sample';
}

// 適当に加工

// 出力例
// 配列などにも対応させるため、シリアル化している
echo serialize($output_data);

 

5.act.php の出力内容をフォームにhiddenで追加する
2回め以降は、前回追加したフォームデータが残っているので、まずは削除してから追加しています。
 

6.別タブに submit
action の URL を書き換えているので、必要であれば書き換え前のURLを保存し、書き戻してください。
同様に、enctype や target も。
 

7.submit されたデータを受け取って表示
PHP での受け取り例

// POSTデータの取得
$post_data = $_POST;

// 追加データの取得
$append_data = array();
if (isset($_POST['append_data'])) {
    $append_data = unserialize($_POST['append_data']);
}

// POSTデータに、追加データをセット
if (is_array($append_data)) {
    foreach ($append_data as $key => $val) {
        if (isset($val)) {
            if (isset($post_data[$key])) {
                $post_data[$key] += $val;
            } else {
                $post_data[$key] = $val;
            }
        }
    }
}

 

最初は ajax 完了後に submit したいということで ajaxの「always」で行けないか?と試したのですが、何故か「always」の中に「document.form_id.submit();」を書くと動きませんでした。
そこで、仕方なく ajax を「async: false」で同期処理にしています。

それなら「submit()」を辞めればいいんじゃないか?とも思いましたが、テキストエリアの入力に使っている CKEditor が、エディタの入力内容を textarea の value にセットするタイミングが submit の時だったようで、これを submit 以外の時にも対応させるのは時間が掛かりそうなため断念しました。

この辺は改良すれば、もっとスマートに行けそうです。


【jQuery】ページ内リンク(スクロール)


baseタグで相対パスの URI が指定されたサイトで、ページ内リンクを貼りたかったのですが

<base href="http://ooo.oo">

<a href="#id">ページ内リンク</a>

上記のように aタグで行うと、base で指定されたURL「http://ooo.oo/#id」にアクセスしてしまいます。
そこで、jQuery のスクロール機能を使い実装しました。

 

■ jQuery

<script type="text/javascript">
function scrollAttribute(attr){
    var p = $(attr).offset().top;
    $('html,body').animate({scrollTop:p}, 'slow');
}
</script>

 

■ HTML

<a href="#id" onClick="scrollAttribute('#id');return false;"></a>

<div id="id">
リンクさせたい箇所
</div>

aタグ側の「href=”#id”」は指定する必要がないため「href=””」などと空にしても良いですが、リンク先として表示されるようにしています。(ブラウザ依存)

引数で属性値を渡せるようにしていますので、「#id」や「.class」など、ID名でもクラス名でも動くようになっています。

 


【jQuery】Lightbox風の単純な画像の拡大表示機能を自作する


プラグインほどの多機能は要らず、単純に画像クリックで拡大画像を表示するという Lightbox 風の機能が欲しかったので作ってみました。

以前も作ったことはあったのですが、その際にブログに残すなどをしていなかったため、どこかに紛失してしまいました。
ということで、今回新たに作ったものを簡単な説明とともに残しておきます。


欲しい機能

・サムネイル画像クリックで、大きな画像を手前に表示

・画像表示時に、周囲を透過処理で暗くする

・画像は画面の中央に表示

・画像を閉じる際は、画面内のどこをクリックしても閉じる
(☓ボタンで閉じるなどは面倒)

・フェードイン、フェードアウトのような余分な処理は要らない

 

ちなみにフェードイン、フェードアウトなどの処理を入れたい場合は、表示を切り替えている部分を改造すれば実装可能です。

「画像は画面の中央に表示」の機能を実装するには、大きな画像の縦横のサイズを予め把握している必要があります。
縦横のサイズが不明の場合は、決め打ちで大体中央に表示させることになります。

 

画像が「サムネイル画像」と「大きな画像」の2枚あるパターンと、「大きな画像」1枚のみの2パターンについて書きます。

 

サムネイル画像と大きな画像の2枚あるパターン

■HTML

<a class="img_popup" width="大きな画像の横幅" height="大きな画像の高さ" href="大きな画像のURL"><img src="サムネイル画像のURL"></a>

aタグに独自の属性 width と height を追加していますが、これを JavaScript から参照して画像を中央に表示するために使用します。
大きな画像の縦横のサイズを取得できない場合は、aタグに記載している width と height を削除します。

 

■CSS

.overlay {
position: absolute;
display: none;
top: 0;
width: 100%;
z-index: 1;
background-color: rgba(0,0,0,0.6);
}
.overlay img {
display: inline-block;
position: absolute;
border: 5px solid #fff;
}

background-color で拡大画像表示時の背景色を指定しています。
rgba は RGBカラーに、透明度(alpha)を追加したもので、0.0~1.0の間で指定できます。
0 が透明、1 が不透明となります。

border: 5px solid #fff; で、画像の周囲を白い線で囲っています。
この辺はお好みで変えてください。

 

■JavaScript

$(function() {
  $('body').prepend('<div class="overlay"></div>');

  $('a.img_popup').click(function() {
    var left = ($(window).width() / 2) + $(window).scrollLeft() - ($(this).attr('width') / 2);
    var top = ($(window).height() / 2) + $(window).scrollTop() - ($(this).attr('height') / 2);

    $('div.overlay').css('height', $(document).height());
    $('div.overlay').empty().append('<img src="' + $(this).attr('href') + '" />').css({display: 'block'});
    $('div.overlay img').css({left: left, top: top, opacity: '1'});
    return false;
  });

  $('div.overlay').click(function() {
    $('div.overlay').hide();
  });
});

各項目の簡単な説明

$('body').prepend('<div class="overlay"></div>');

大きな画像を表示する際の背景となる divタグを body に追加しています。

 

$('a.img_popup').click(function() {

クラス名が img_popup の aタグがクリックされたら 5~11行目の処理を行います。

 

var left = ($(window).width() / 2) + $(window).scrollLeft() - ($(this).attr('width') / 2);
var top = ($(window).height() / 2) + $(window).scrollTop() - ($(this).attr('height') / 2);

(ブラウザのウィンドウサイズ ÷ 2) + body のスクロール位置 ー (aタグに指定した大きな画像の縦横 ÷ 2)
これにより、ページがスクロールしていても、常にブラウザの中央に画像が表示されます。

※大きな画像の縦横の値が分からない場合は、マイナスする値に適当な数値を入れます。
ただし、この場合は画像のサイズによって表示位置を変えることはできないので、画面のバランスが悪くなります。

 

$('div.overlay').css('height', $(document).height());

divタグの高さをドキュメントの高さと同じにしています。

 

$('div.overlay').empty().append('<img src="' + $(this).attr('href') + '" />').css({display: 'block'});

divタグの中身(html)を一度空にしてから、imgタグを追加しています。
また、その際に src に aタグの href の内容を指定しています。

 

$('div.overlay img').css({left: left, top: top, opacity: '1'});

imgタグの表示位置を指定し、非表示から表示に切り替えています。

 

return false;

aタグの href のリンクが起動しないように false を返しています。

 

$('div.overlay').click(function() {
  $('div.overlay').hide();
});

divタグがクリックされたら divタグを非表示にしています。

これで、簡単な Lightbox 風の画像拡大表示機能が実装できます。

 

大きな画像1枚のみで実装するパターン

■HTML

<a class="img_popup" width="大きな画像の横幅" height="大きな画像の高さ"><img style="width: 100px" src="大きな画像のURL"></a>

imgタグに width を指定して縮小表示し、サムネイル画像にします。

 

■CSS
css は同じものを使用します。

 

■JavaScript
JavaScript も基本は同じですが、9行目だけ書き換えます。

$('.overlay').empty().append('<img src="' + $($(this).children('img')).attr('src') + '" />').css({display: 'block'});

src に指定する値を imgタグの src に変えています。

以上です。

 

単純な画像拡大機能であれば、わざわざプラグインを入れなくても簡単に実装できますね。
そう言いつつ、当ブログの画像拡大機能は、プラグインを使っていたりしますが・・・。

ちなみに、この前アップした「【PHP】画像データ文字列から画像の横幅と高さを取得する」という記事は、今回の中央表示をしたいための処理だったりします。