Theming ajaxified view/view block

Last updated on
1 December 2016

Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites

Views module provides powerful end flexible tools to create custom template files for each element, but as it is using jQuery in few places, it is necessary to keep template structure in order, to make sure all JS and Ajax facilities will work correctly. This document describes relation between markup of Views and jQuery code which is attached to view which is using Ajax.


Required class for view container view-dom-id-{name/md5} - why and what for?

view-dom-id-{name/md5} - provided to our template with $classes variable is a main selector inside of ajax_view.js, which means that is required for views module to run ajax properly:

/**
 * Javascript object for a certain view.
 */

var selector = '.view-dom-id-' + settings.view_dom_id;
this.$view = $(selector);

The reason why this class sometimes contains weird md5 hash instead of view name is explained in views_block_info() function.

block.module has a delta length limit of 32, but our deltas can unfortunately be longer because view names can be 32 and display IDs can also be 32. So for very long deltas, change to md5 hashes.

And here’s PHP code responsible for it:

foreach ($keys as $delta) {
    if (strlen($delta) >= 32) {
        $hash = md5($delta);
        $hashes[$hash] = $delta;
        $items[$hash] = $items[$delta];
        unset($items[$delta]);
    }
}

In conclusion: always output $classes variable to make sure ajax will init properly!

Markup for views exposed filters

When view will be successfully targeted via DOM Id, it will attempt to find exposed filters using jQuery children(); method, and standard view classes:

/**
 *  Add the ajax to exposed forms.
 */ 

this.$exposed_form = this.$view.children('.view-filters').children('form');
this.$exposed_form.once(jQuery.proxy(this.attachExposedFormAjax, this));

This forces us to keep nesting of this element in one proper way only,
.view-filters element must be a children of .view-dom-id-{name/md5} element, and the
must be rendered inside of .view-filters element. Next thing is submit button - it just needs to be placed anywhere inside of
element:

Drupal.views.ajaxView.prototype.attachExposedFormAjax = function() {
  var button = $('input[type=submit], button[type=submit], input[type=image]', this.$exposed_form);
  button = button[0];

  this.exposedFormAjax = new Drupal.ajax($(button).attr('id'), button, this.element_settings);
};


Pagination

/**
 * Attach the ajax behavior to each link.
 */
Drupal.views.ajaxView.prototype.attachPagerAjax = function() {
  this.$view.find('ul.pager > li > a, th.views-field a, .attachment .views-summary a')
  .each(jQuery.proxy(this.attachPagerLinkAjax, this));
};

Requirement for pagination is much simpler, because it is targeted with jQuery find(); method, so it just needs to be anywhere inside of .view-dom-id-{name/md5} wrapper, ul must have .pager class, li must be a child of ul, a must be a child of li. That’s all.


Template/markup

To make sure Ajax will work properly we don’t need to output entire view markup, this is all we need:

<div class="<?php print $classes; ?>">
    <div class="views-filters">
        <?php 
            // our exposed form must be wrapped with .views-filters class
            print $exposed; 
        ?>
    </div>
    <div class="view-content">
        View content goes here, or anywhere. 
    </div>
    <?php 
        // pager can be placed anywhere inside of main view wrapper 
        print $pager; 
    ?>
</div>

And this is sample of our HTML output:

<div class="views-dom-id-{this-is-view-dom-id}">
    <div class="views-filters">
        <form>
            <input type="submit" />
        </form>
    </div>
    <div class="view-content">
        <p>VIEWS CONTENT</p>
    </div>
    <ul class="pager">
        <li>
            <a>Page 1</a>
        </li>
    </ul>
</div>

Hope I didn't missed anything and it will help a little to all Themers :_)

Help improve this page

Page status: No known problems

You can: