jQuery UI API failing to load properly with LABjs
Asked Answered
A

1

13

I've recently switched to using LABjs to load scripts in SharePoint Webparts (2010). The main reason for this was to avoid loading the same library (like jquery and jquery.ui) to the page more than once if multiple Webparts were added to the same page. This way, each of them can specify its dependencies individually, without needing to police which other Webparts have been, or might be added.

Both LABjs and an another file, which contains the script chains, are loaded via <script> tags at the bottom of the Webpart's markup.

9 times out of 10, the Javascript executes without any issues. Every once in a while though, an exception will be thrown, stating TypeError: $(...).button is not a function.

This occurs even if there is only one Webpart on the page and seems to be browser independent (Tested in FireFox 38, Chrome 43 and IE 11/IE 8 forced by page).

The chain looks like this (edited for clarity):

$LAB.setOptions({Debug:true})
.script("../js/jquery-1.11.3.min.js").wait()
.script("../js/jquery-migrate-1.2.1.min.js").wait()
.script("../js/jquery-ui.min.js").wait()
.script("../js/core.js")
.wait(function(){ 
    jQuery(function() {
        init();     // The jQuery UI .button() call
    });
})
.script("../js/jquery.multiselect.min.js").wait()
.script("../js/jquery.multiselect.filter.min.js")
.script("../js/rte/jquery.rte.js").wait()
.script("../js/rte/jquery.rte.tb.js")
.script("../js/rte/jquery.ocupload-1.1.4.js")
.wait(function () {
    jQuery(function() {
        // Some DOM-dependant code lives here
    });
});

This is what the debugger outputs (also edited for clarity):

start script load (ordered async): ../js/jquery-1.11.3.min.js
start script load (ordered async): ../js/jquery-migrate-1.2.1.min.js
start script load (ordered async): ../js/jquery-ui.min.js
start script load (ordered async): ../js/core.js
start script load (ordered async): ../js/jquery.multiselect.min.js
start script load (ordered async): ../js/jquery.multiselect.filter.min.js
start script load (ordered async): ../js/rte/jquery.rte.js
start script load (ordered async): ../js/rte/jquery.rte.tb.js
start script load (ordered async): ../js/rte/jquery.ocupload-1.1.4.js
script execution finished: ../js/jquery-1.11.3.min.js
script execution finished: ../js/jquery-migrate-1.2.1.min.js
script execution finished: ../js/jquery-ui.min.js
script execution finished: ../js/core.js
$LAB.wait() executing: function (){ jQuery(function() { init(); }); }
$LAB.wait() error caught:  TypeError: $(...).button is not a function
    ...
script execution finished: ../js/jquery.multiselect.min.js
script execution finished: ../js/jquery.multiselect.filter.min.js
script execution finished: ../js/rte/jquery.rte.js
script execution finished: ../js/rte/jquery.rte.tb.js
script execution finished: ../js/rte/jquery.ocupload-1.1.4.js
$LAB.wait() executing: function () {
        jQuery(function() {
            ...
        });
    }
$LAB.wait() error caught:  TypeError: $(...).multiselect is not a function
    ...

This error is almost always accompanied with long load times for the jquery.ui library.

At the same time, however, it's clear from the debugger's output that it has already finished executing before the .button() call.

I've been fighting with this for a while now and any help/insight into what the issue might be and how to fix it would be greatly appreciated. I've been crawling the LABjs documentation for a clue as to something I may be doing wrong, but nothing seems to be popping out at me.


Note: There does exist a <script> reference to jquery in the header, however this reference cannot be removed (I do not have access to the master page) and I have already tried removing jquery from the chain, to no avail.


Edit: Someone has suggested that the issue may be due to the fact that the SharePoint server is behind a load balancer, which might be the cause for the exceptionally long load times on the jquery.ui library. While that is a possibility, I don't see how or why that would effect LABjs's load/execute functionality.

---

Update

After quite some digging, I found that, for some reason that is still unknown to me, the jquery.ui library was binding to jquery and not $ as my code was expecting. To try and fix this, in core.js I created a variable core.$ which was instantiated with jQuery.noConflict(), wrapped my DOM dependent code with

(function ($) {
    ...
})(core.$);

and moved the .script(".../js/core.js") call to the end of the chain (to make sure all plugins were rolled back properly.)

While this didn't fix the problem, the occurrences have dropped to somewhere around 1 in 50.

Astound answered 16/6, 2015 at 17:6 Comment(9)
If the Sharepoint is load-balanced - make sure all the js files (particularly jquery-ui) exist on all servers.Zolly
I've tested it while pointing at each server individually (as opposed to the load balancer) and all the files load correctly. Additionally, the error doesn't seem to occur when not pointing towards the load balancer.Astound
I should also mention that the error only occurs on the development server. The production server (also load-balanced) works fine.Astound
Does it work everytime if you do NOT use LABjs?Zolly
It depends. If there is only one such webpart on the page, than yes, simply loading the libraries synchronously using <script> tags does not cause the error.Astound
This sounds like a race condition. Is it possible that sometimes scripts are getting invoked before the DOM is ready? Or something similar?Hutto
Theoretically, the jQuery calls should make sure that the script content is bound to the DOM-ready event.Astound
@Astound do you really need to use LABjs?Pufahl
@Pufahl it's the most robust library I found to dynamically load javascript files, while preventing duplicate loadings across webparts. And even if you suggest something else - and by all means, please do - at this point I'm much more curious as to why this is happening at all over fixing my specific problem.Astound
D
1

@LdTrigger "Additionally, the error doesn't seem to occur when not pointing towards the load balancer" This tells you your solution will not be in code. Please try to use "persistent connections" / "sticky sessions", This likely occurs because you do not have enough "permission" to fetch the file contents from another server then you are on, since they are both behind the load balancer

Decadence answered 29/9, 2015 at 18:30 Comment(3)
The system administrator just informed me that the production environment uses the same connection settings and the error only occurs in the development environment, so this feels unlikely.Astound
BUT since you stated this only happens when a load balancer is in play, then there is a difference, your environments might be the same but that doesn't mean the load balancer does the same thing. I am 100% sure that there is no issue you can solve in code when the code works as a standalone system. Then your firewall/loadbalancer, internal network will always be the cause, a solution would be starting logs of all calls made. Check your network tab if needed, and please persist the calls and see what your results are and compare the "endpoints" for your dev against the prod, then look at all..Decadence
responses from the same calls and make sure they match, if this fails please try to check if your dev can point to production dependencies and see if that makes it work.Decadence

© 2022 - 2024 — McMap. All rights reserved.