web-dev-qa-db-ja.com

Ajaxの成功後にDrupal.attachBehaviorsをトリガーする方法

リンクをクリックしたときにajaxを介してノードを更新するモジュールがあります。

リンクはトグルです。最初のクリックでノードを値1で更新し、その後のクリックで値0でノードを更新する必要があります。

以下のコードは、ページの読み込み後の最初のクリックでは機能しますが、その後のクリックでは機能しません。クリックするたびにDrupal.attachBehaviorsを呼び出し/トリガーする必要があると思いますが、これを行う方法がわかりません。

  1. モジュール

    _function mymodule_menu() {
      $items['mypath/%/%/ajax'] = array(
      'title' => 'My title',
      'page callback' => 'mymodule_ajax_callback',
      'page arguments' => array(1,2),
      'access arguments' => array('access content'),
      'type' => MENU_CALLBACK,
      );
    
      ...
    }
    
    function mymodule_ajax_callback($id, $status) {
      //Validation[...]
    
      //Node Update using $id as the nid and $status as the field value[...]
    
      // Define a new array to hold our AJAX commands.
      $ajax_commands = array();
    
      // Create a new AJAX command that replaces the #div.
      $replacedivid = '#status'.$id;
      $replacestring = '<div id="status'.$id.'"><a data-url="'.base_path().'mypath/'.$id.'/'.$new_status.'/ajax" title="This item is marked as '.$status_text.'" id="statuslink'.$id.'" class="midui">'.$status_text.'</a></div>';
    
    
      $ajax_commands[] = ajax_command_replace($replacedivid, $replacestring);
    
    
      return drupal_json_output($ajax_commands);
    }
    _
  2. JavaScript

    _(function ($) {
      Drupal.behaviors.mymodule = {
        attach: function(context, settings) {
          var $uilink = $('.midui'); //find all links
    
          for (var i=0;i<$uilink.length;i++) { //Loop
            var $link = $('#' + $uilink[i].id);
            if (!$link.hasClass("middone")) {
    
              new Drupal.ajax('#' + $uilink[i].id, $link, {
                url: $link.attr('data-url'),
                effect: 'fade',
                settings: {},
                progress: {
                  type: 'throbber'
                },
                event: 'click tap'
              });
    
              $link.addClass("middone"); //add class when we're done
    
            }
          }
        }
      }
    })(jQuery);
    _
  3. これまでに試したこと:

(a)_$.fn.mymodule_関数と組み合わせた$ ajax_commands配列にajax_command_invoke(NULL, 'mymodule');を追加します

(b)$('body').ajaxSuccess(Drupal.attachBehaviors);をJavaScriptに追加します。 ajaxCompleteも試しました。ドキュメントでも試してみました。

(c)ここで説明するようにカスタムコマンドを作成します http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

注:挿入または変更される新しいhtmlを「ajaxify」するためにクリックするたびにattachBehaviorsをトリガーするだけの問題であることはわかっています。リンクをクリックして、コンソールにDrupal.attachBehaviors()と入力すると、「middone」クラスが追加されたことからわかるように、リンクはJavaScriptによって再び処理され、再度クリックできるようになります。

注:また興味深いことに、コールバック関数の最後で_$ajax_commands_を空のままにしてそれ(空の配列)を返すと、1回目以降のクリックでリンクがクリック可能なままになります。私が探している機能(トグル)があります。ただし、クリックするたびにhtmlは変更されないため、ユーザーがトグルがオンかオフかを知る方法はありません。

どんなポインタでも大歓迎です。

================================================== =====

部分的な答え:

Drupalのajax.js成功関数は、フォームの動作のみを再アタッチします(私はそう思いますか?)

_    if (this.form) {
      var settings = this.settings || Drupal.settings;
      Drupal.attachBehaviors(this.form, settings);
    }
_

そこで、すべてのajaxオブジェクトの成功関数をハックすることにしました。

Javascriptは次のようになります

_    (function ($) {
      Drupal.behaviors.mymodule = {
        attach: function(context, settings) {
          var $uilink = $('.midui'); //find all links

          for (var i=0;i<$uilink.length;i++) { //Loop
            var $link = $('#' + $uilink[i].id);
            if (!$link.hasClass("middone")) {

              myAjax = new Drupal.ajax('#' + $uilink[i].id, $link, {
                url: $link.attr('data-url'),
                effect: 'fade',
                settings: {},
                progress: {
                  type: 'throbber'
                },
                event: 'click tap'
              });

              myAjax.options.success = function (response, status) {
                //Trigger Attach Behaviors
                setTimeout(function(){Drupal.attachBehaviors($(myAjax.selector))}, 0);
                // Sanity check for browser support (object expected).
                // When using iFrame uploads, responses must be returned as a string.
                if (typeof response == 'string') {
                  response = $.parseJSON(response);
                }

                return myAjax.success(response, status);
              }

              $link.addClass("middone"); //add class when we're done

            }
          }
        }
      }
    })(jQuery);
_

成功関数は、動作を再接続するための行が追加されたajax.jsからのデフォルトのコピーペーストです。何らかの理由で、_Drupal.attachBehaviors_はタイマー内にある必要があります。私が無視する理由のために、それだけでそれを手に入れることはできません。

誰かがよりエレガントな解決策を見つけたり、タイマーの奇妙さを説明したりできる場合に備えて、この質問はほとんど公開しません。

どうもありがとう

10
JSL

いくつかのデバッグの後、問題は自分のコードにあるのではないことに気付きました。

問題は別のモジュール(私の場合はcolorboxモジュール)にありました。これは、独自の動作関数のjsエラーの原因でした。エラーが原因で動作のアタッチプロセスが停止したため、自分の動作関数は再アタッチされませんでした。エラーはコンソールで確認できます。

カラーボックスエラー:7.24

Uncaught TypeError: Cannot read property 'transition' of undefined colorbox_inline.js?

そして7.25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

私の解決策は、カラーボックスモジュールを無効にすることでした。

助けてくれたすべての人に感謝します。

1
JSL

コメントできません 最初の回答 ですが、設定でカラーボックスのプロパティを設定できます。例えば:

myAjax = new Drupal.ajax('#' + $uilink[i].id, $link, {
  url: $link.attr('data-url'),
  effect: 'fade',
  settings: {
    colorbox: {
      mobiledetect: false
    }
  },
  progress: {
    type: 'throbber'
  },
  event: 'click tap'
});
1
Ilya Krigouzov

Ajaxリクエスト自体から返されるコンテンツにajaxビヘイビアーをアタッチするのは難しい場合があります。ただし、可能です。

あなたのhook_menuコードスニペットは、それが正しいと仮定して不完全に見えますが($ itemsを返し、関数は閉じています)-あなたの場合、配信コールバックを「ajax_deliver」に調整する必要があるだけかもしれません

つまり:

/**
 * Implements hook_menu
 */
function mymodule_menu() {

  $items['mypath/%/%/ajax'] = array(
    'title' => 'My title',
    'page callback' => 'mymodule_ajax_callback',
    'page arguments' => array(1,2),
    'access arguments' => array('access content'),
    'delivery callback' => 'ajax_deliver',
    'theme callback' => 'ajax_base_page_theme',
    'type' => MENU_CALLBACK,
  );

  return $items;

}
1
David Thomas