0

I have a Views Slideshow on my site that works perfectly until I try to reload only part of the page (containing the slideshow among other stuff) via AJAX (using Ajax links API module). The content itself is reloaded properly but:

If the new content contains different blocks than the old content, I'm getting the following error:

Uncaught TypeError: Cannot set property 'targetId' of undefined

It's the following lines that cause the error:

var fullId = '#' + $(this).attr('id');
var settings = drupalSettings.viewsSlideshowCycle[fullId];
settings.targetId = '#' + $(fullId + " :first").attr('id');

An inspection of drupalSettings.viewsSlideshowCycle in Chrome DevTools shows that it doesn't contain the current block id ($(this).attr('id')) but contains the old block id, already gone, so drupalSettings.viewsSlideshowCycle[fullId] returns null. In other words, the AJAX-driven content update doesn't seem to update drupalSettings - is it supposed to? I checked the AJAX response and it contains correct settings but for some reason the script doesn't see them and uses the original settings that came with the initial page load.

If the new content has the same structure as the old one (same block name for the Views Slideshow) then I don't get the error and the slideshow sort of works but the slide counter shows funny numbers in funny sequence (like 6 of 2, then 2 of 2) and at funny times (not when the slides change but when they stand still too). It looks like there are two scripts running simultaneously interfering with each other.

I would expect the behaviors mechanism to somehow kill the old scripts and settings and replace them with new ones upon processing an AJAX response but it doesn't seem to happen and I can't find any documentation on this particular aspect.

Sorry for a possibly fuzzy description (must admit I don't know the inner workings of AJAX all too well) - will be happy to provide more info if needed!

2 Answers 2

0

I would expect the behaviors mechanism to somehow kill the old scripts and settings and replace them with new ones upon processing an AJAX response but it doesn't seem to happen and I can't find any documentation on this particular aspect.

The D7 Managing Javascript docs explains this well:

Drupal.behaviors will often be called multiple times on a page. For example, every time a form performs some Ajax operation, all Drupal behaviors will be executed again after page load, in order to attach any relevant JavaScript to the newly loaded elements. This can have the undesired affect of applying JavaScript to elements each time Drupal behaviors are executed, resulting in the same code being applied multiple times. To ensure that the JavaScript is applied only once, we can use the jQuery $.once() function. This function will ensure that the code inside the function is not executed if it has already been executed for the given element.

The D8 Javascript Overview docs tells you how to use $.once() in D8.


If your code is not recognizing the ajaxed in divs, then you need to attach the behaviors to the ajax wrapper, with drupal.attachBehaviors($('.ajax-wrapper'));

Ex:

$.ajax({
    url: '/some/url',
    type: 'GET',
    success: function (data) {
        var result = $(data).find('.some-wrapper').html();
        $('.ajax-wrapper').html(result);
        Drupal.attachBehaviors($('.ajax-wrapper'));

    }
});
7
  • Thank you - I have read that, of course, but it doesn't answer the question nor solve the problem. The Views Slideshow Cycle attach code does include a sort of "spelled-out" equivalent of $.once() (I even tried to replace it with $.once() to no effect) but it doesn't prevent the behavior I am encountering. And preventing the code from executing the second time is not quite what is desired here - I do need it to execute again to work with the new set of content, but I also need it to remove all remnants of old scripts still trying to run (or new scripts somehow accessing old settings?).
    – Marassa
    Commented May 24, 2018 at 13:49
  • @Marassa I have edited my answer, I hope it helps.
    – No Sssweat
    Commented May 24, 2018 at 13:57
  • I am feeling dumb today - may I ask you to spell out what you mean exactly by "If your code is not recognizing the ajaxed in divs"? First of all, there's no my code involved in what's happening (at least I hope so) - there is the Views Slideshow Cycle contrib module which doesn't do any AJAX by itself but its code (at first sight) seems to be properly wrapped around Drupal.behaviors and there's Ajax links API contrib module which converts internal links to Ajax calls but doesn't define any behaviors besides that. Do I get it right that you thnk than one (or both) of those modules are broken?
    – Marassa
    Commented May 24, 2018 at 14:14
  • @Marassa yes, one of these modules has a bug.
    – No Sssweat
    Commented May 25, 2018 at 0:02
  • Thank you for the clarification - I did some more reading on the subject and I now see I was being naive thinking popular contrib modules are supposed to just work out-of-the-box in ajax context - seems like I've got quite a bit of debugging and fixing to do...
    – Marassa
    Commented May 25, 2018 at 6:04
0

This is what I wound up doing:

Issue #1 (Uncaught TypeError): Added the following code to the Ajax links API ajaxAfter function right after pasting the AJAXed content into DOM:

$.extend(true, drupalSettings, JSON.parse($(selector).find("script[data-drupal-selector='drupal-settings-json']").html()));

This code should have probably been there from the start but who knows - it can break something for someone else.

Issue #2 (counter acting funny): Added the following code to the Ajax links API ajaxBefore function right before wiping the old content:

$('#views_slideshow_cycle_teaser_section_photo_slideshow-block_1').cycle('destroy');

As opposed to #1 this is a horrible site-specific kludge but will work for me until I find a more elegant and more generic solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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