2

I have a large form that is often used but takes 2-3 seconds to load. To get around this, I have it loaded by clicking the <a id="doc_ready_link" class="use-ajax" link with JS on page load.

document.querySelector('#doc_ready_link').click();

Module

function custom_ajax_page_st_form_menu() {
  $items['class-content-form'] = array(
    'page callback' => 'ajax_content_response',
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

On faster machines like my laptop or phone, this is fine and I have a fast page load and a spinner on the form link.
But on slower laptops and phones, other JS stuff like the menu doesn't work until it's loaded giving a bad UX.

How do I get that form loaded with ajax after page load without locking up the browser? For a normal click, the UX is ok but when it's all hidden like what I'm doing, the clunkiness is jarring.

Thanks.

EDIT:

I have tried the other methods below for clicking the link but the locking of other JS remains on slower devices. I'm still looking for some other method, most likely a snippet of $.ajax code that can call my module's code just like class="use-ajax" does.

PS for anyone wondering how to click Flags etc. in Drupal:

document.querySelector('#').click(); works when $('#').click(); usually doesn't.

Edit: For what it's worth, this is the module that the "use-ajax" link calls but I don't think it matters much.

<?php

function custom_ajax_page_st_form_form_init()
{
    drupal_add_js('misc/jquery.form.js');
    drupal_add_library('system', 'drupal.ajax');
}

/**
 * Implements hook_menu().
 */
function custom_ajax_page_st_form_menu()
{
    // A menu callback is required when using ajax outside of the Form API.
    $items['class-content-form'] = array(
        'page callback' => 'ajax_content_response',
        //   'access callback' => 'user_access',
        'access arguments' => array(
            'access content'
        ),
        'type' => MENU_CALLBACK
    );
    return $items;
}

function ajax_content_response($type = 'ajax', $nid = 0, $node_type = "", $home_nid)
{

    $output = _custom_page_st_form_loader();
    if ($type == 'ajax') {
        $commands   = array();
        $commands[] = ajax_command_replace('#class_form_load', '<div id="class_form_load">' . $output . '</div>');
        //    $commands[] = ajax_command_invoke('.add_menu', 'show');
        // Remove Spinner
        $commands[] = ajax_command_invoke('html', 'trigger', array(
            'remove_ajax_spinner'
        ));
        // Set Groups Audience
        if ($nid != 0) {
            $commands[] = ajax_command_invoke('#edit-og-group-ref-und-0-default', 'val', array(
                $nid
            ));
            $commands[] = ajax_command_invoke('#edit-og-group-ref-und-0-default', 'trigger', array(
                "chosen:updated"
            ));
        }
        // Set Home
        if ($nid != 0) {
            if ($node_type == "homepage_group") {
                $commands[] = ajax_command_invoke('.form-item-field-home-und input', 'prop', array(
                    "checked",
                    true
                ));

            } // $(".form-item-field-home-und input").prop("checked", true)
        }
        // Set Homepage Audience
        $commands[] = ajax_command_invoke('#edit-field-homepage-audience-und-0-default', 'val', array(
            $home_nid
        ));
        $commands[] = ajax_command_invoke('#edit-field-homepage-audience-und-0-default', 'trigger', array(
            "chosen:updated"
        ));


        $page = array(
            '#type' => 'ajax',
            '#commands' => $commands
        );
        ajax_deliver($page);
    } else {
        $output = '<div id="class_form_load">' . $output . '</div>';
        return $output;
    }
}

function _custom_page_st_form_loader()
{
    module_load_include('inc', 'node', 'node.pages');
    $form = node_add('class_content');
    return drupal_render($form);

}

And the reason this is a big deal for my site. There are 8 JS buttons that users click very quickly on the site and all break on slow devices.

Top of site

  • By page load do you mean window or document load? – Stefanos Petrakis Jun 9 '17 at 12:13
  • jQuery(document).ready(function($){ – Niall Murphy Jun 9 '17 at 18:06
  • you've completely changed the question !!! :( . it's more better revert it to the start question and ask this as another question, this is a type of disregard our effort and care for people question, this means our time is not important for you. – Yusef Jun 11 '17 at 17:33
  • Hi @zhilevan, I think you've misunderstood my original question. It hasn't changed but now, I'm just giving what I think is probably the way to do it with $.ajax. It's also more generic which is good for SE. My original question was How to replace a "use-ajax" link that's auto-clicked on page load?. I thought I made it clear that I wanted that functionality replaced and that I had a working solution very similar to the two provided. They still lock the browser on slower machines because they still use the "use-ajax" link I want replaced with something else. – Niall Murphy Jun 11 '17 at 18:05
  • Please check the original question which I updated literally on your advice below. I don't know why you'd suggest that I have disregard for your efforts when I also contribute a lot to this community. I will look at all of this again tomorrow. It's 1am here. – Niall Murphy Jun 11 '17 at 18:09
1
+50

Hi everybody I coming back ;)

According to

Events

$(document).on('ready', handler) binds to the ready event from jQuery. The handler is called when the DOM is loaded. Assets like images maybe still are missing. It will never be called if the document is ready at the time of binding. jQuery uses the DOMContentLoaded-Event for that, emulating it if not available.

$(document).on('load', handler) is an event that will be fired once all resources are loaded from the server. Images are loaded now. While onload is a raw HTML event, ready is built by jQuery.

Functions

$(document).ready(handler) actually is a promise. The handler will be called immediately if document is ready at the time of calling. Otherwise it binds to the ready-Event.

Before jQuery 1.8, $(document).load(handler) existed as an alias to $(document).on('load',handler).

Further Reading

The @Stephan solution is not wrong but it's better you don't wait for all resources ( I mean all images etc ) load when your Menu Item ( DOM objects) loaded So

(function ($) {    
  Drupal.behaviors.yourModule = {
    attach: function(context, settings) {
        $('#doc_ready_link').click();
    }
  };
})(jQuery);

NOTE1: As you know Drupal.behaviors acts like $(document).ready on Drupal so imagine Bind on windows.load event in document.ready event binding.

NOTE2 if you have some ajax call it cause duplication calling of this form and for preventing duplication triggering(although in your case not required because you redirect page to another page immediately ) So

(function ($) {    
  Drupal.behaviors.yourModule = {
    attach: function(context, settings) {
        $('body', context).once('myModule', function () {
        $('#doc_ready_link').click();

});
    }
  };
})(jQuery);
  • Drupal.behaviors is not at all like document ready. Document ready is just the first time behaviors are invoked (on the whole document). It's an API for attaching functionality to any arbitary chunk of DOM. It's invoked any time new elements are inserted into the DOM, possibly a lot of times over the lifetime of the page. – Sam152 Jun 10 '17 at 8:55
  • @Sam152 Any function defined as a property of Drupal.behaviors will get called when the DOM has loaded. drupal.js has a $(document).ready() function which calls the Drupal.attachBehaviors() function, which in turn cycles through the Drupal.behaviors object calling every one of its properties, these all being functions declared by various modules as above, and passing in the document as the context. ref : drupal.org/docs/7/api/javascript-api/javascript-api-overview – Yusef Jun 10 '17 at 19:16
  • @Sam152 another reference lullabot.com/articles/… – Yusef Jun 10 '17 at 19:16
  • Hi @zhilevan, great answer and I feel awful for saying that while the code works, the locking remains while the form is loaded. I think I need a totally different approach to the "use-ajax" link. Just some regular $.ajax on page load. $.ajax({url: $('#doc_ready_link').attr('href'), success: function(result){ console.log( "yes" ); }}); successfully prints "yes" but the form doesn't get loaded. I feel like there has to be a way to do this without the specific link. – Niall Murphy Jun 11 '17 at 4:38
  • @NiallMurphy maybe .click doesn't redirect to another page. maybe on('click' , ... is a better option, by the way, you can ask it as another question or update your question with extra section and describe this issue, I'll help you. – Yusef Jun 11 '17 at 13:42
1

You should use window.onload if you want to have your code run after other javascript code (and DOM and CSS) have been loaded. window.onload is triggered after document.onready.

The ready event occurs after the HTML document has been loaded, while the onload event occurs later, when all content (e.g. images) also has been loaded.

The onload event is a standard event in the DOM, while the ready event is specific to jQuery. The purpose of the ready event is that it should occur as early as possible after the document has loaded, so that code that adds functionality to the elements in the page doesn't have to wait for all content to load.

[quoted from https://stackoverflow.com/a/3698214/5875098]

As an example (and to be more Drupal-specific), the following javascript should cover what you need:

(function ($) {    
  Drupal.behaviors.yourModule = {
    attach: function(context, settings) {
      $('body').once('bind-window-load', function(){
        $(window).bind('load', function() {
          $('#doc_ready_link').click();
        });
      });
    }
  };
})(jQuery);

Good luck!

  • Binding to window load inside a behavior is incorrect. Behaviors add functionality to the markup in "context", this will needlessly bind events to window every time Drupal.attachBehaviors is called, possibly a lot of times for each page load. – Sam152 Jun 10 '17 at 8:53
  • Hey @Sam152, thanks for having a look, I updated the supplied code using once(), to avoid binding multiple times. – Stefanos Petrakis Jun 10 '17 at 9:20
  • Hi Stefanos, thanks for the answer but this snippet didn't actually click the link as needed whereas zhilevan's did. But even then, the performance issue remains and JS gets locked up until the form is loaded. Now I'm not sure if it's a site issue or something with the way these links work. Also, it seems you need document.querySelector('#').click(); to click use-ajax links in Drupal. I can use that for Flags / Rules links when jQuery doesn't work. Thanks again. – Niall Murphy Jun 11 '17 at 4:23
  • Hey @NiallMurphy, there was an error - late addtion - to the code, that I corrected, I called once() on the window, but it should be called on a DOM object. I tested it and it should work for you too know, have another try. Cheers – Stefanos Petrakis Jun 11 '17 at 7:52
0

I don't really know what your form is doing, but perhaps the request and delivery callback is doing too much work. In my comment I had mentioned changing the delivery callback to ajax deliver. Here is an example:

https://gist.githubusercontent.com/kevinquillen/4c5df0e5f9c586182117/raw/1190acbc27b3192c33b87788f5a1f1c35f98b3c6/dynamic-reveal.example.php

function user_alert_menu() {
  $items = array();

  $items['js/user-alert/get-message/%'] = array(
    'page callback' => 'user_alert_display_alert',
    'delivery callback' => 'ajax_deliver',
    'page arguments' => array(3),
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );

  return $items;
}

function user_alert_display_alert($nid) {
  $output = '';

  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'node');
  $query->entityCondition('bundle', 'user_alert');
  $query->propertyCondition('nid', $nid);
  $query->propertyCondition('status', 1);
  $query->propertyOrderBy('nid', 'DESC');
  $query->range(0, 1);

  $result = $query->execute();

  if ($result['node']) {
    $record = reset($result['node']);
    $wrapper = entity_metadata_wrapper('node', $record->nid);
    $output = theme('user_alert', array('node' => $wrapper->value()));
  }

  $commands = array();
  $commands[] = ajax_command_html('div#user-alert-message', $output);
  $commands[] = ajax_command_invoke('div#user-alert-message', 'foundation', array('reveal', 'open'));
  return array('#type' => 'ajax', '#commands' => $commands);
}

On the front end, there are link(s) with the use-ajax class that trigger this behavior. The callbacks only function is what you see above, and despite doing an EFQ and a theme call, it was pretty quick. The end result here is the themed output is injected to a hidden div, and then a modal plugin opens that div.

You can also use $.ajax too, since you are just hitting a menu item route.

  • I will have to look at this later today and write a delivery callback function and change up my code (which I added to the original question). Thanks. – Niall Murphy Jun 14 '17 at 4:59

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.