hiroshi akutsuの日記

主にプログラミング関係のこと

jquery-ui【tooltipで表示されるhtmlのコンテンツをajaxで取得して表示】

jquery-uiのtooltipは非常に簡単にツールチップを実装できるツールとして知られている。

たとえば、
jqueryのjsファイル、
jquery-uiのjsファイル、
jquery-uiのcssファイルを読み込んだ状態で、

$(function(){
  $(document).tooltip();
})

とするとtitle属性に指定された文字がツールチップとして表示される。

htmlを表示したい場合は

$(function(){
  $(document).tooltip({
    items   : "[class]",
    content : "<div class=\"tooltip-content\">HTML表示</div>"
  });
});

とかってやるとhtmlが記述できる。

ではajaxで取得したhtmlをcontentに設定するには?
単純に以下のようにやってもだめ。

$(function(){
  $(document).tooltip({
    items   : "[class]",
    content : function(){
      return ajaxFunc();
    }
  });
});
function ajaxFunc(){
  var ret = "";
  $.post(
    "Ajax.php?class_name=hoge",
    {},
    function(d, dt){
      ret = d;//関数の戻り値を設定(しようとしている)
    },
    "html"
  );
  return ret;
}

最初はみんなやります。この間違い。
当たり前だけど、$.post()は非同期なので下の関数のretの変数にはサーバーからの返答がを待たずして、
return ret;
が先に実行されてしまうので期待通りの動作になりません。
かといって$.ajax()のasyncオプションをfalseにして同期通信でとってくるという方法もださい。ツールチップはその滑らかさが売りなのに画面がいちいちとまってしまうことになる。

$.Defferedとかも考えたけど、Defferedオブジェクトは非同期処理の実行順序を保証してくれるだけで、レスポンス結果が取得されるのを待ってreturnするとかはできない(と思うがうまく使えばできるのかな)。
何とか非同期でとってこようとしたらいろいろ方法は考えられるがStack Overflowにあった回答を参考にやったのは次の方法。openのオプションで取ってくる。

$(function(){
  $(document).tooltip({
    items   : "[class]",
    content : "now loading...",
    open    : function(){
      ajaxFunc($(this));
    }
  });
});

function ajaxFunc($oj){
  var ret = "";
  $.post(
    "Ajax.php?class_name=hoge",
    {},
    function(d, dt){
      $oj.tooltip("option", "content", d);//ここで取得した内容を設定
    },
    "html"
  );
  return ret;
}

これできちんとajaxの内容を表示できた。