ラベル jQuery の投稿を表示しています。 すべての投稿を表示
ラベル jQuery の投稿を表示しています。 すべての投稿を表示

2013年4月17日水曜日

[jQuery]名前空間とoneで動的にイベント処理設定を変更する。

jQueryでイベント処理の設定(bindやliveとかで)をしていて、ユーザの操作によってだとか、ajaxの受信結果の内容によって、動的にイベント処理の設定を変更できたらいいのに、と思うことがあります。

例えば、モーダルウィンドウでユーザが選択した結果を受けて、次にでるモーダルウィンドウのイベント設定内容を変えたりなど。
そんなときは、名前空間とone関数を使って動的にイベント設定内容を変えていきます。

名前空間とはNamespaced Eventsで説明されているよう、'click'や'hover'等のイベント名の後ろにクラス名のようにドットで名前がつけられる機能です。
これを設定していれば、その名前だけunbindすることができます。(clickイベントを全て削除しなくて済む)

one関数とは、ほぼbindと同じなのですが、そのイベントは一度呼び出されれば終わりで、二回以上発動することはありません。こちらで説明されています。one(type, [data], fn)

以下の例では、1行目でhidden.twtrmdlという名前空間にoneでイベント処理設定をしていますが、ajaxの結果を受けて12行目でその名前空間がunbindされています。つまり、ajaxの結果によって、イベントの処理設定が変わっていることになります。


$("#commentModal").one('hidden.twtrmdl', function () {
    $("#twtrCnfrm").modal();
});

$("#commentModal btn").bind('click',function(){
    $.ajax({
        success:function (data, textStatus) {
                if (data.success) {
                      $("#commentModal").modal('hide');
                }
                else {
                      $("#commentModal").unbind('hidden.twtrmdl');
                      alert(data.message);
                }
        },
        data:postData,
        dataType:"json",
        type:"post",
        url:url
    });
});

2013年4月5日金曜日

[jQuery]infinitescrollが正しくpage番号をincrementしてくれない件への対処

infinitescrollを使用している際、以下のような事象が発生した。

http://【mydomain】/themes/2/page:2がinfinitescrollのオプションnextSelectorに指定されている時、なぜか出力されないアイテムが表示されたり、アイテムがもっとたくさんあるはずなのに、「もうアイテムはありません」というようなメッセージが出てしまうのだ。 i

まず、サーバ側のaccessログをみると、 http://【mydomain】/themes/3/page:2というURLにアクセスしており、404エラーを返していた。なぜ、このようなURLにアクセスしてしまうのか。
infinitescrollのソースをchoromeのデバッグモードで見ていると、以下のことがわかった。
pathという2要素の配列があるのだが、 0番目に'http://【mydomain】/themes/'、1番目に'/page:2'という文字列が入っており、処理としては、このそれぞれの文字列の間にインクリメントされた数字を入れて結合しアクセス先のURLを作っているようだった。つまり、本来は 'http://【mydomain】/themes/2/page:【ページ番号】'と認識してほしいところ、'http://【mydomain】/themes/【ページ番号】/page:2'というように認識してしまったようだ。

infinitescrollのソースをよくみると、URLに/2/というようにスラッシュに直接はさまれた’2’があるとそれをページ番号として認識する作りになっていた。/suzuki2/や/2suzuki/など、他の文字列と一緒であれば、問題なかった。

これを防止するため、最初はinfinitescroll.jsに手を加えようと考えたが、pathはオプションで指定できるということがわかった。なので、以下のようにして指定した。
色々書いているが言いたいことは色が付いている行。

    path=new Array();
    path.push(location.href+'/page:');
    path.push("");
    $("#infiniteItems").infinitescroll({
            navSelector  : '#page-nav',    // selector for the paged navigation
            nextSelector : '#page-nav a',  // selector for the NEXT link (to page 2)
            itemSelector : '.rankedItem',     // selector for all items you'll retrieve
            loading: {
                finishedMsg: 'これ以上はないのじゃ',
                img: $("body").attr("data-ladingImg")
            },
            path:path
        },
        function(newElements){
            var $newElems = $( newElements ).css({ opacity: 0 });
                $newElems.each(function(i){
                    $itemInfo=$(this).children(".itemInfo");
                    $voters=$(this).children(".voters");
                    if($itemInfo.outerHeight()>$voters.outerHeight()){
                        mgnpdgSum=$voters.outerHeight()-$voters.innerHeight();
                        $voters.height($itemInfo.height()-20);
                    }
                });
            $newElems.css({ opacity: 1 });
        }
    );


2013年3月19日火曜日

[jQuery]resizeイベントが2回発動される問題への対策

$(window).resize(function)なんですが、なぜかchromeだと1度のリサイズでイベントが二回発動されていしまいます。firefoxだとおきませんでした。

ここにのっている対処が一番シンプルそうです。実際うまくいきました。

JQuery: How to call RESIZE event only once it's FINISHED resizing?

コードはここにあるのを、発動される関数を自分のもに変えればいいと思います。

http://jsfiddle.net/Zevan/c9UE5/5/

2013年2月28日木曜日

[JavaScript]JSのlive関数のように動的に取得した要素にstyleを反映させるには

AJAXなどで動的に取得したHTML要素にstyleを反映させるにはどうするか。
最初からcssファイルに記述しておけばいいんだけど、値自体を動的に決めたい場合はどうするか。例えば、windowサイズに合わせて何かのサイズを決めたい時とか。

そんなときはhead内に動的にstyle要素を追加すればよいということがわかった。。
このサイトが参考になります。

jQueryのlive関数のように、後から追加されたエレメントに対して事前にスタイルを設定する方法

2013年2月7日木曜日

[jQuery]flatheightsとheightLine.jsの使い勝手比較

ブロックレベル要素の高さをそろえてくれるjsライブラリについて使い勝手を比較する。

・jquery.flatheights.js
【メリット】
 対象の要素にクラス名を付与せずに使用できる。

【デメリット】
 呼び出すjsを書く必要がある。
 要素にpaddingやmarginが指定してある場合、高さがおかしくなる。
  http://d.hatena.ne.jp/AyeBee_TY/20120710/1341926286

heightLine.js
【メリット】
 要素にpaddingやmarginが指定してあっても正しく高さを調整してくれる。
 呼び出すスクリプトを書く必要がない。あるクラスを指定するだけで動作する。
http://blog.webcreativepark.net/2007/07/26-010338.html

【デメリット】
 クラス名をつけてあげなければ動かない


結局paddingとかで高さがおかしくなるのが嫌なので後者を使うことにした。


 
 

2013年2月1日金曜日

[jQuery]CakePHPでjquery.infinitescroll.jsを使用した場合にスクロールを正常に終わらせるには

http://www.infinite-scroll.com/

上記で配布されているjquery.infinitescroll.jsであるが、スクロールが終わる条件は、私の知る限る二つある。

1.オプションのnextSelectorで指定されたリンクで指定された、次ページへのリクエストに対し404エラーが返される。
 →こちらの場合、オプションのfinishedMsgで指定された文言が最後に表示される。

2.オプションのmaxPageで最終ページを指定する。
→こちらの場合、finishedMsgはなぜか表示されない。

2の方法は、総ページ数をmaxPageに入れてしまえばいいので楽チンなのだが、やはり終わった時のメッセージは欲しい。
1の方法に関して。
当方、サーバサイドはCakePHPを使用している。CakePHPはデフォルトでは、最終ページを超えた数字が指定されても、最終ページの内容を出力し404エラーは出力しない。
なので、最終ページのnextSelectorで指定されたaタグに存在しないURLを指定したのだが、どうもうまくいかない。相変わらず最終ページの内容が出力される。
なぜかと思いfirebugで観察していたところ、どうやら、ベースになるURLは最初のページを表示したタイミングで作られ、incrementした数字をお尻に付加しているようだった。つまり、2ページ目以降のnextSelectorのaタグは見られていない。

なので、CakePHPで最終ページを超えた数字を指定された場合は404となるように細工することにした。その方法は以下で紹介している。

[CakePHP]pagination時に存在しないpageの場合は404を出すには

※CakePHPのバージョンはcakephp-cakephp-1.3.15-9-gacd25c3.zip


2012年12月7日金曜日

[jQuery]$.ajaxのオプションcompleteとsucceedの違い

completeオプションを使用した場合は、jsonからjavascriptの配列に変換する
処理が以下の3行目のように必要だった。

$.ajax({
 complete:function (data, textStatus) {
  data = $.parseJSON(data.responseText);
  if (data.redirect) {
              window.location.href = data.redirect;
         } else {
   $.alerts.dialogClass = "custom1";
   jAlert(data.message,"確認して下さい",clearAltCls);
         }
 },
 data:postData,
 type:"post",
 url:"\/rakuzon\/themes\/itemAdd"
});
だが、以下のようにsuccessを使用した場合は、11行目で指定したデータタイプに
自動的に変換されている。便利。

$.ajax({
 success:function (data, textStatus) {
  if (data.redirect) {
              window.location.href = data.redirect;
         } else {
   $.alerts.dialogClass = "custom1";
   jAlert(data.message,"確認して下さい",clearAltCls);
         }
 },
 data:postData,
 dataType:"json",
 type:"post",
 url:"\/rakuzon\/themes\/itemAdd"
}); 

ちなみに、予断だが、ajaxの結果にレスポンス結果によってリダイレクトしたい
場合は、上記の4行目のようにすればよい。

2012年12月6日木曜日

[jQuery]「jQuery Alert Dialogs」での$(this)の参照が変わる?

検証はしていないので、原因が違ったらすみません。
以下の「jQuery Alert Dialogs」を使っています。

http://h2ham.seesaa.net/article/117267913.html

jAlertやjConfirmの後に$(this)を使うと、想定していたオブジェクトを
指していないようです。
firebugで見たところ、「Window」オブジェクトになっていました。

jAlertやjConfirmの処理の中で$(this)が変わる処理が入っているのでは
ないか、と推測します。

なので、仕方なしに、$(this)で取得したい値をjAlertやjConfirmを使う前に
変数に代入しておくことにします。


2012年11月22日木曜日

[jQuery]コロンを含むセレクタを指定する方法

以下のサイトで説明されているよう、コロンの前に二つのバックスラッシュを
つけてエスケープしなければならない。
なぜ二つかはわからない。

JQueryでコロン付きのセレクターを使う場合

私の場合は既に変数で指定されている文字列を使う必要があったので
下記のようにコロンを置換して実装した。
なお、4行目に試しに置換後の文字列を表示しているが、
なぜか「abc\:1234」とバックスラッシュが一つだけで表示される。
//以下JavaScript部分 
var test ="abc:1234"
test2=test.replace(':',"\\:")
alert(test2);  //「abc\:1234」と表示される。
alert($("#"+test2).val());  //「5678」と表示される。
//以下HTML部分
<input type="hidden" id="abc:1234" value="5678"> 

2012年11月6日火曜日

[jQuery]$.ajaxではまった件

$.ajax({
    complete:function (XMLHttpRequest, textStatus) {
        document.getElementById("result").innerHTML=XMLHttpRequest.responseText;
    },
    data:"data[Keywords]="+$("#lastKeywords").val()+"&data[ItemPage]="+$("#nextPage").val();
    type:"post",
    url:    "\/rakuzon\/themes\/itemSearch"
});
このコードが動かなかったんだけど、5行目のセミコロンをカンマにしてあげたら
動いた。(丸一日つぶした。。。)
また、dataには配列として渡してあげたほうが見やすいきがしたので以下のように修正。
$.ajax({
    complete:function (XMLHttpRequest, textStatus) {
        document.getElementById("result").innerHTML=XMLHttpRequest.responseText;
        eval($("#result script").text());
    },
    data:{
        'data[Keywords]':$("#lastKeywords").val(),
        'data[ItemPage]':$("#nextPage").val()
    },
    type:"post",
    url:"\/rakuzon\/themes\/itemSearch"
}); 
以下が参考にしたサイト。

[jQuery]postメソッドとajaxメソッドを使ってPOST送信を行うサンプル
連想配列の使用方法

【追記 2012/11/6】
なお、data:に設定するのは連想配列となる。
事前に連想配列を以下のように用意しておくことも可能だ。
postData={
    'data[Keywords]':$("#lastKeywords").val(),
    'data[ItemPage]':$("#prevPage").val()
};
$.ajax({
    complete:function (XMLHttpRequest, textStatus) {
        $("#result").html(XMLHttpRequest.responseText);
        bindPager();
    },
    data:postData,
    type:"post",
    url:"\/rakuzon\/themes\/itemSearch"
});
しかし、以下のように連想配列の要素ごとに代入していくやり方だと
なぜかうまく$.ajax()が動かなかった。原因不明。
postData['data[Keywords]']=$("#lastKeywords").val();
postData['data[ItemPage]']=$("#prevPage").val();
$.ajax({
    complete:function (XMLHttpRequest, textStatus) {
        $("#result").html(XMLHttpRequest.responseText);
        bindPager();
    },
    data:postData,
    type:"post",
    url:"\/rakuzon\/themes\/itemSearch"
}); 

2012年10月26日金曜日

[jQuery]かっこいいアラートやプロンプトを使う。

このページを見てできました。
なかなか素敵。

ダイアログボックスを美しくみせる「jQuery Alert Dialogs」を使ってみる


別のやつで下記もいいかなと思ったんだけど、
なんか表示されるフェードインが遅すぎるんだよな。

jQuery Impromptu | 設置サンプル

2012年10月16日火曜日

[jQuery]bindについてわかったこと

・イベントによって生成された要素にbind()するには。 


生のHTMLに書かれた要素に対してイベント登録するには
単純にbind()すればよい。
だが、イベント発生後にJavaScriptで生成された要素に対してイベント登録するには
要素の作成時にbindしなくてはならない。

$("#submit-1528237246").bind("click", function (event) {
                $("#tags").append("<p><span class=\"tag\">"+$("#tag").val()+"</span> <span class=\"rm\">×</span></p>");
                rmTag();
});

function rmTag(){
    $(".rm").unbind();
    $(".rm").bind({
        click:function(event){
            $(this).parent().remove();
        },
        mouseenter:function(){
            $(this).css("cursor","pointer");
        },
        mouseleave:function(){
            $(this).css("cursor","default");
        }
    });
}
2行目によってクリック時に要素を追加する設定をしている。
ここで追加された要素に対してイベント登録するには、この作成時の時点で
イベント登録を行わなければならない。
なので3行目でイベント登録する関数を呼び出している。

・bindによるイベント登録は上書きではなくappend


ちなみに、7行目でunbindしているのは下記のサイトで説明されているよう
bindは上書きではなくappendしていくためだ。

jQueryのイベント時の関数を上書きする

上記のソースのようにイベント発生時にrmクラス全てにイベント登録して
いくと、最初の方にbindされた要素は同じイベント登録が複数回appendされて
しまうため、毎回全登録をunbindしている。

・一つの要素に複数のイベント登録をするには


また、一つの要素に複数のイベント登録をするには8~18行目のようにする。

・"hover"はbind()で使用できない。


 下記のようにhover()という関数を使ってイベント登録をできるが、
これをbind()で実現するには上記のソースのように、mouseenterとmouseleaveに
分けて記述する必要がある。

            $(function(){
                $(".rm").hover(
                    function(){
                        $(this).css("cursor","pointer"); 
                    },
                    function(){
                        $(this).css("cursor","default"); 
                    }
                );
                $(".rm").click(
                    function(){
                        $(this).parent().remove();
                    }
                );
            });


2012年10月10日水曜日

[CakePHP]$js->submit()のoptionsのbeforeの限界と対策

以下のような形でbeforeオプションを使用し、
ajax送信直前に送ろうとしているformの値自体を操作しようと
したのだけど、うまく送れなかった。
おそらく、beforeが完了してから送信の処理が開始されるので
はなく、beforeと同時並行的に送信するデータ自体は取得して
いるからだろう。

echo $js->submit("登録する",array(
    'id'=>'register',
    'url'=>'add',
    'update'=>'#complete'
    'before'=>'
        var fm = document.getElementById("add");
        $("#add").append("<input type=\"hidden\" name=\"data[Theme][explanation]\"/>");
        fm.elements[\'data[Theme][explanation]\'].value=$("#explanation").val();
    '
));

では、どうすればよいか。
beforeで設定するのではなく、別で$js->submitより上に、
onclickのイベント設定をしてしまえばよい。
こうすれば、フォームの値の操作が完了してから、
送信の処理が開始されるようになる。

$js->get("#register")->event('click','
    var fm = document.getElementById("add");
    $("#add").append("<input type=\"hidden\" name=\"data[Theme][explanation]\"/>");
    fm.elements[\'data[Theme][explanation]\'].value=$("#explanation").val();
');

echo $js->submit("登録する",array(
    'id'=>'register',
    'url'=>'add',
    'update'=>'#complete'
)); 
※CakePHPのバージョンはcakephp-cakephp-1.3.15-9-gacd25c3.zip

[CakePHP]inputタグのnameをjQueryで指定できない。

CakePHPでajaxを使ってフォームの内容を送信する際に、
javascriptでinputタグのtype=hiddenのvalueを操作したい場合が
あったのですが、その際に対象のinputエレメントを指定するのに
苦労しました。

inputタグにidをつけてしまえば簡単なのですが、
nameというユニークの属性を持っておきながら、
さらにidを付与するのは少し不細工なので、なんとか
nameで指定するやり方を考えました。

jQueryだと通常、
$(*"input[name=XXX]")
といった形で、name属性で指定できる。

だが、CakePHPのhtmlヘルパーで作成されるinputタグは以下のように
"["と"]"を含むので指定することができない。
色々な方法でエスケープを試みたができなかった。
<input type="text” name=”data[Model][field]“/> 
なので、以下のサイトを参考にした。

cakePHPの Formヘルパーで作られるdata[Model][Field]をJavascript処理する
[CakePHP] 配列のname属性をJavaScriptで参照する方法
var fm = document.getElementById("add");
//中略
fm.elements[\'data[Item][\'+i+\'][code]\'].value=itemLst[i];
上記のような形でnameを変数で動的に変動させることもできるのだ。
上記の例では、formエレメントをidで取得してきているが、
nameをつけている場合には、以下のように書くことができる。
(formのnameが"add"である場合)
document.add.elements[\'data[Item][\'+i+\'][code]\'].value=itemLst[i]; 
※ここでのバックスラッシュはWindwosでいういわゆるYENマークね。
※CakePHPのバージョンはcakephp-cakephp-1.3.15-9-gacd25c3.zip