How to include script that includes jQuery without conflicting - javascript

I need to load an external application that contains the complete jQuery 3.2.1 library inside of it. Because it is an externally hosted app, it's not realistic to modify the code. However, when I add the script to my page, I end up with lots of errors due to conflicts with other scripts already loaded. As an experiment, I've tried downloading the app and wrapping the contents in an anonymous function, thinking that this would keep the new version of jQuery scoped locally within the app but it didn't make any difference.
Is there a simple way to include this app without modfying it's contents or relying on jQuery.noConflict() which would require many changes to my existing code?

you can use jQuery.noConflict() in your code with limited changes by simply wrapping all of your code that uses jQuery in an IIFE and passing in the instance of jQuery you are using
try something like
<script src="path-to-your-jquery.js"></script>
<script>var $jQ = jQuery.noConflict();</script>
<script>/* your plugins */</script>
<script>
(function($){
/* your code using `$` works fine here*/
})($jQ);
</script>
<script> /* other app code */</script>

Related

Adding WFFM-form - Jquery issue

I'm using Sitecore 8 Update 2 to make a page where people can leave some personal information. If the user is logged in the information is filled in for them.
( Standard mvc 5 form )
I added a WFFM ( 8.0 rev 141217 ) login form ( if succesfull the page is reloaded and all the fields get filled in) but when this code is included it messes up Jquery.
#Html.Sitecore().Placeholder("form")
I can still see that the jquery file is loaded in the browser but the "Jquery" variable is now undefined. ( and i have a bunch of Jquery running on that page )
What can i do to prevent this from happening or how can i find out what causes this ?
EDIT:
I found the code where it all goes bad.
After this function is finished the Jquery variable is undefined. But this code is added as part of the WFFM as far as i can tell. ( inline with the html elements )
<script type="text/javascript">
if (typeof ($scw) === "undefined") {
window.$scw = jQuery.noConflict(true);
}
$scw(document).ready(function () {
$scw("#LVn73Spq0EGYvPQZ7-bA5Q").eventTracking({ pageId: "{55D3F49D-6EDA-43FB-81F1-191D34F896D4}", rules: "{"*":"{844BBD40-91F6-42CE-8823-5EA4D089ECA2}","regex":"{F3D7B20C-675C-4707-84CC-5E5B4481B0EE}","length":"{F3D7B20C-675C-4707-84CC-5E5B4481B0EE}","required":"{7E86B2F5-ACEC-4C60-8922-4EB5AE5D9874}"}" });
});
</script>
You need to include the WFFM script bundles in your forms. You can do this by registering the scripts in /Views/Form/Index.cshtml
#Scripts.Render("~/bundles/wffm/jquery")
#Scripts.Render("~/bundles/wffm/scripts")
#Styles.Render("~/content/wffm/jquery")
#Styles.Render("~/content/wffm/themes")
You only need to include the first two, the others adds default styling using jQuery UI themes, which you can then override (or not include them and style them yourself).
The reason for the js error is jQuery.noConflict(true) resets the jQuery name from scope. The WFFM noConflict call removes the last loaded jQuery library, which in this case is your manually loaded script earlier in the page and since it is the only jQuery library it has nothing to fall back to.
If necessary, you can free up the jQuery name as well by passing true
as an argument to the method. This is rarely necessary, and if you
must do this (for example, if you need to use multiple versions of the
jQuery library on the same page)
See jQuery.noConflict() and this blog post for more details about loading two versions of jQuery
If you are sure the version if jQuery you loaded is compatible with the WFFM loaded version then you could simply set window.$scw = jQuery; but you will still need to load the scripts bundle since it includes form specific functionality.
I had the exact same error occurring on a site. The error occurred due to the fact that I had included all the wffm jquery references at the bottom of the <body> element. After moving the wffm jquery references into the <head> element and reloaded the page I had no errors in my console.
Regarding the order of loading JavaScript files while bundling:
Preferably your project makes use of properly closured js files, (scoped usage of jQuery or $). If that's the case, you can simply load the WFFM scripts as the last library, even after your own custom application code.
That way these scripts will ommit the global jQuery variable while your closures keep reference to jQuery locally. Hence this is a great example why using an IIFE is encouraged.
(function($){
// $ = reference to jQuery remains intact
}(window.jQuery))
I can now savely load my bundle from the head with the async property enabled (eliminates render-blocking JavaScript to increase page loading speed).
<head>
...
#Scripts.RenderFormat("<script src='{0}' async='async'></script>", Sitecore.Context.PageMode.IsPageEditor
? "/scripts/sdw.editor.bundle.js"
: "/scripts/sdw.web.bundle.js");
...
</head>
A bundle example in order (In bold the WFFM requirements for the Experience Editor):
jQuery (bower updated version inside Experience Editor works usually fine)
jQuery-UI (WFFM dependency)
Bootstrap
jQuery validation (WFFM dependency)
jQuery unobtrusive validation (WFFM dependency)
My custom JS (still applicable for the editor?)
WFFM Scripts (sitecore modules > Web > Web Forms for Marketers > scripts > mvc > Fields > *.js)
On the other hand, jQuery dependant code from inline scripts or external js files, loaded before the closing </body>, don't know about jQuery anymore once the WFFM scripts are loaded. Either split them up or define $scw before loading WFFM scripts.
An example of bundling while mixing inline scripts:
<head>
...
#Scripts.Render("~bundles/libraries") // jQuery, jQuery-UI, Bootstrap, jQuery validation, ...
<script>window.$scw = jQuery.noConflict(false);</script>
#Scripts.Render("~bundles/wffmJs")
</head>
<body>
...
<script type="text/javascript">
if (typeof ($scw) === "undefined") {
window.$scw = jQuery.noConflict(true);
}
$scw(document).ready(function () {
$scw("##Model.ID.ToShortGuid()").eventTracking({ pageId: "#Model.PageId", rules: "#TrackingValidationErrorsProvider.Current.GetValidationRulesMap()" });
});
</script>
...
#Scripts.Render("~bundles/myCustomJs")
</body>
Conclusion:
Avoid synchronous loading from the head tag since that will block rendering and result in slower page loading.
Avoid inline script tags because they force you to load libraries from the head tag synchronously.
Define $scw = jQuery to bypass jQuery.noConflict(true) if needed.
Preferably one bundle asynchronously from the head tag.
Use closure to keep libraries referenced.

Passing startup arguments to dojo toolkit when loading in meteor

I am trying to use the Dojo framework inside meteor js
According to the dojo documentation, you need to pass startup arguments inside the tag like so:
<script src="../dojo/dojo.js" data-dojo-config="async: true"></script>
specifically, the data-dojo-config argument
If i place dojo.js into the client/lib folder, a tag is autogenerated by the meteor internal logic, but i do no know how to modify or add arguments into this script tag. is there a proper way to do this?
You can also simply have a global variable called "dojoConfig" which does the same thing.
It must be defined before the dojo.js script is parsed by the browser.
<script type="text/javascript">
var dojoConfig = {
async: true
};
</script>
This will do the trick.
I've got what i just posted and a regular dojo.js script tag right after that, and dojo works just fine in my meteor client.
In this case you might want to place the dojo kit in the /public folder so meteor won't touch its javascript, then you can manually add the tag as you want.
At the moment the generation is automated so its not possible to tell meteor to give a special rule for dojo.
You could also use jquery or some js dom to modify the script tag meteor might add if you want to leave your stuff in /client/lib
$(function() {
$('script[src=../dojo/dojo\\.js]').attr({data-dojo-config:true});
})

How do I enable JS library auto completion in PhpStorm?

In an HTML file, I included jQuery via
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" ></script>
I downloaded the library via the context menu and now see it in the project folder under External Libraries. Yet, it seems jQuery is not recognized.
<script type="text/javascript">
$(document).ready(function() {
..
});
</script>
The $ is underlined and code hinting asks me to create a function or method called $. The code itself works though.
What am I supposed to do to make PhpStorm recognize the external JavaScript library?
As LazyOne pointed out in his comment I had to look up settings, and there I realized I had to download the library again, and made it global.

How to access jQuery after jQuery.noConflict(); - not namespaced

I am in big trouble at the moment. We have a huge JS library that I need to maintain. It uses internally jQuery 1.6.2.
The client where we installed the library uses jQuery 1.3.4 and the fancybox overlay plugin.
After loading these two, he simply throws in a
jQuery.noConflict();
but without saving his jQuery to a variable (namespacing).
Now I need to access his fancybox, but if I use
$.fancybox({...})
or
jQuery.fancybox({...})
I get in both cases an "is not a method error".
I can duplicate the error on my local machine and it would not appear without the jQuery.noConflict(); statement.
We are also doing a noConflict with our jQuery but we save it to another varieable, i.e.
jq162 = jQuery.noConflict();
The problem is the customer is of course unwilling to change anything of his code.
Is there any way how I can access his jQuery / Fancy after this statement and after loading our 1.6.2?
thanks in advance...
UPDATE
the scripts are loaded in the following order:
// client
jquery 1.4.2
jquery fancybox
<script type="text/javascript"> jQuery.noConflict(); </script>
jQuery 1.2.6 which seems to be necessary for Liferay
// now comes my library
jQuery 1.6.2
my scripts
i know, if we could change step 3 to
<script type="text/javascript"> $jq = jQuery.noConflict(); </script> it would work, but right now that is out of my influence.
in 6. myscripts I need to access the fancybox from 2.
any ideas?
It shouldn't be a problem. You must be loading your scripts after the client's scripts (if you're loading yours first, there shouldn't be any problem, your jquery is namespaced, and the clients version will be in jQuery along with the plugin).
So simply namespace his jQuery object before you load your script:
<script>
jq132 = jQuery;
</script>
<script src="yourScripts"></script>
<script>
jq162 = jQuery.noConflict();
console.log(jq132.fancybox);
</script>
UPDATE
As per your update, what you're trying to do is impossible. There is no longer a reachable reference to that jQuery/plugin instance (unless fancybox accidentally leaked a global reference, which I highly doubt). I don't know fancybox, although it's possible that the functionality isn't instance-specific. So it may be possible to just reattach fancybox to your version of jquery, and it will be able to perform all the necessary things. What I said about the reference however, remains true.
Obviously adding a few characters like you suggested (or other similar ways) would solve the problem. But if that is impossible, then your client will have to realise that. It should be proof enough if you simply ask them to access there own plugin under the same conditions - i.e. without changing code.
They should probably have a long and hard think about their entire project. Having to load three different versions of the same product is a sign that something is very very wrong.

Stub out the global namespace to enable for lazy script loading

I am using jQuery UI and a few other JS libs which in total make for quite a chunk of JS (even minified and combined). My idea is to not include a script tag in the page but to stub out all functions that I defined as well as the $ sign for jQuery so that my inline JS on the page can still call them but will hit the stub. The stub will then load the .js file and actually call the function. The question now is:
How can I redirect all function calls on the window object/global object to a custom function of mine?
I am not used to dynamic languages so a little advice on how to do this in JS will be appreciated.
As stated previously ... this is likely an exercise in futility. Unless you are a researcher and are being paid to do this (and only this), I'd spend my time just working on my actual product and/or refactoring so that the page requires fewer disparate JS libs (for example. use jquery only, rather than jquery + yui)
edit, though, I suppose in the interest of actually answering the question. You can easily replace any function by simply setting it in javascript. For example ...
$ = function(searchString) {
// if this method is called
// and jquery hasn't been loaded yet
// load jquery (which will overwrite all of your local jquery functions with its own
};
The method to lazy load .js files is well documented throughout the web, for example here:
http://ajaxpatterns.org/On-Demand_Javascript
Well the root of your problem is the usage of library dependent in-line JS. We had an old legacy site that had a bunch of in-line JS in the Smarty templates. I ended up modding Smarty so that I could capture the JS calls and then output them all in the footer. Looked something like this
<!-- mySubContent.inc.html -->
<div id="theTabs">
<ul><li><!--
...
--></li></ul>
<div id="tab1"><!--
...
--></div>
</div>
{capture_js}
$("#theTabs").tabs();
{/capture_js}
<!-- footer.inc.html -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
{render_captured_js}
</script>
</body>
</html>
Anyway, maybe that'll give you some idea about how to tackle your in-line JS problem if you can't refactor the codebase right now. Oh, and read this - http://developer.yahoo.net/blog/archives/2007/07/high_performanc_5.html .

Categories