0

I am having some problems using ajax to trigger an views update (D7).

Basically there is a map (leafletMap) and when it is moved/changed/zoomed, a function gets a list of node ids and triggers a views ajax refresh. Those node ids are passed into a contextual filter, so only matching packages in that view are displayed below the map.

The problem with the ajax is it often fires multiple ajax requests. When I inspect the extra requests one or two will have the correct arguments, but one will have the old arguments and then the view will refresh with the wrong nodes.

I've tried using return false and binding what I can to this or context. As you can see I've tried unbind()ing the <div /> but nothing seems to help. Often the first set of ajax calls append the wrong view, but then the next one works. And so on. To be honest I'm a bit out of my depth.

Basically I need there to be one ajax call with the correct arguments, or at least multiple ajax calls that use the correct arguments.

Any hints, ideas or suggestions would be most welcome. Many thanks.

TLDR; The below code triggers an ajax refresh of a view. This view has a contextual filter. It is triggering multiple ajax requests, some of which retain the old ajax arguments & therefore refresh incorrectly. Thanks!

Drupal.behaviors.packageFilter = {
    attach: function (context, settings) {

      if (typeof window.leafletMap === 'undefined' || window.leafletMap.length == 0) {
        return;
      }
      this.leafletMap = window.leafletMap[0];
      this.leafletMap.$map.once(function () {
        this.leafletMap.map.on('moveend', this.refreshView.bind(this));
        return false;
      }.bind(this));
      // Reset arguments back to default when not filtering map.
      $.each(Drupal.settings.views.ajaxViews, function (key, value) {

        if (value.view_name === 'packages') {
          Drupal.settings.views.ajaxViews[key].view_args = '';
        }

      });
      $('.views-exposed-form-packages-search', context).attr('action', '/packages.json');
    },

    refreshView: function (context, settings) {

      Drupal.attachBehaviors('ViewsAjaxView');

      // This gets markers from the map and converts them to node ids
      var visibleMarkers = this.leafletMap.getVisibleMarkers();
      var totalMarkers = this.leafletMap.markers.length;

      // Do not run if map isn't filtered.
      if (visibleMarkers.length < totalMarkers) {

        var visibleMarkers = this.leafletMap.getVisibleMarkers();

        var nids = '';
        $.each(visibleMarkers, function (i, v) {
          nids += v.node.nid + '+';
        });
        nids = nids.slice(0, -1);

        // nids is an array of node ids for the view to return

        $.each(Drupal.settings.views.ajaxViews, function (key, value) {

          if (value.view_name === 'packages') {
            // this should add the node ids as an views ajax argument 
            // to a contextual filter
            Drupal.settings.views.ajaxViews[key].view_args = nids;
          }

        });

        var throbber = '<div class="ajax-progress ajax-progress-throbber"><div class="throbber">&nbsp;</div></div>';
        $('.views-submit-button').append(throbber);

        $.each(Drupal.settings.views.ajaxViews, function (key, value) {

          if (value.view_name == 'packages' && value.view_args == nids) {
            $('.view-id-packages').triggerHandler('RefreshView');
          }

        });

        $('.view-id-packages').unbind();

      }
    }
  }
0

For the sake of posterity & future visitors with this issue, here is how I eventually got it to work.

refreshView: function (context, settings) {
  // Unbind event to prevent multiple ajax refreshes.
  $('.view-id-packages').unbind();
  Drupal.attachBehaviors('ViewsAjaxView');

  // When map changes, update the grid of packages below the map.
  var visibleMarkers = this. leafletMap.getVisibleMarkers();

  // Get all the node IDs to pass into the views contextual filter.
  var nids = '';
  $.each(visibleMarkers, function (i, v) {
    nids += v.node.nid + '+';
  });
  nids = nids.slice(0, -1);

  // Update the Drupal ajax object to use our new set of node IDs.
  $.each(Drupal.settings.views.ajaxViews, function (key, value) {
    if (value.view_name === 'packages') {
      Drupal.settings.views.ajaxViews[key].view_args = nids;
    }
  });

  // Add the throbber on since it doesn't show automatically.
  var throbber = '<div class="ajax-progress ajax-progress-throbber"><div class="throbber">&nbsp;</div></div>';
  $('.views-submit-button').append(throbber);
  // Trigger the ajax.
  $('.view-id-packages').triggerHandler('RefreshView');
}

And then my view > advanced > contextual filter looks like:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.