Adding WFFM-form - Jquery issue - javascript

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.

Related

How to include script that includes jQuery without conflicting

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>

JavaScript file dependend on JavaScript code block in Yii2 (for dojo configuration)

I'm trying to register the dojo javascript files with Yii 2.0.
According to the dojo documentation, the code block for dojo config must be loaded before the actual dojo.js in order to be considered. However, in the HTML output my custom javascript code is always loaded after dojo.js.
This is my code:
$this->registerJs('dojoConfig="async:true,isDebug:true";', $this::POS_HEAD,'dojoconfiguration');
$this->registerJsFile('/dojo_toolkit/dojo/dojo.js', ['depends' => [\yii\web\JqueryAsset::className()], 'position' => yii\web\View::POS_HEAD]);
And in HTML it looks like this:
<script src="/dojo_toolkit/dojo/dojo.js"></script>
<script type="text/javascript">dojoConfig="async:true,isDebug:true";</script>
Any advise?
For the same position Yii2 always puts the inline scripts first and then the actual external files. So you can't fix this by adding them both to the <head>.
Its best to give the registerJsFile() call a POS_END to load it at the very end. It will still be loaded before the document.ready() call is made.
That way you can be sure that the configuration in the header is parsed before the load. Worst case scenario you can use POS_BEGIN to load it right after the body tag is opened, but since loading javascript is blocking I would try to avoid that.

YepNope - Waiting until dependencies loaded

In a ASP.NET Masterpage I am using YepNope to unconditionally and asynchronously load jQuery (from the Google CDN, with local fallback) and some scripts which are used on all pages in the site. In the MasterPage I have created a ContentPlaceHolder before the closing body tag (and below the YepNope script that loads those used on all pages) which is used for scripts used on individual page. As jQuery should be available on every page in the site it should not be loaded individually on those pages where there are specific scripts that use it.
The problem I have is that I can't use the callback or complete functions in the yepnope script where jQuery is loaded, as this is on the MasterPage and these are individual page scripts which are only used or added on that page, yet I need to be able to delay the execution of the individual page scripts until yepnope (which appears above the page scripts) has finished loading any dependencies (such as jQuery) used in them.
I can think of two options-
1- Make the script used on the page an external file and load that using the syntax -
yepnope('/url/to/your/script.js');
or
yepnope({ load: '/url/to/your/script.js' });
I'm not sure I like this idea as it introduces an extra HTTP request for a few lines of javascript which isn't going to be used on any other page.
2- Load jQuery again in another yepnope test object block, with the complete function wrapping up the page scripts (calling complete without a test seems to execute the function immediately, before the previous scripts are loaded) and relying on the following-
I am requesting a file twice and it's only loading once? By popular
demand, in yepnope 1.5+ we added the feature that scripts that have
already been requested not be re-executed when they are requested a
second time. This can be helpful when you are dealing with less
complex serverside templating system and all you really care about is
that all of your dependencies are available.
In the page I could presumably load the same version of jQuery from the Google CDN, which based on the above would not actually be loaded twice, and then load the page scripts in an anonymous function called from the complete function of the yepnope test object.
On the plus side this would mean that the page is no longer dependent on jQuery being loaded from the MasterPage, but a negative would be that (even assuming YepNope does not load the script twice now) we would be loading multiple versions of jQuery should the version in the MasterPage be changed without the same happening in the page in the future. From a maintenance point of view I don't feel this is a good idea, especially on the assumption (which I feel you should always make) that another developer would be the one making the changes.
It also does not seem especially elegant.
On balance I will almost certainly use the first option but I would like to know if there is a way to delay or defer scripts on a page until asynchronous loading is completed, and this cannot be done as part of the YepNope test object loading the resources.
How do other developers approach this problem?
I have come up with this as a solution I rather like.
In the MasterPage YepNope test object add the code-
complete: function() {
if (window.pageFunctions !== null && typeof (window.pageFunctions) === "function") {
window.pageFunctions();
}
}
If I want to add any JavaScript code or functions that rely on the dependencies loaded in the MasterPage I just wrap them in a function named "pageFunctions" like so-
<script type="text/javascript">
function pageFunctions() {
$(document).ready(function () {
...
});
}
</script>
I'm still interested in other (possibly better) solutions so I'm going to leave the question open for a couple of days.
I'd also appreciate comments on this as a solution.

SignalR $.connection is undefined

I admit it, I don't know what I'm doing.
I'm attempting to learn how to use SignalR and I'm following various samples online almost verbatim and I can't get pasted $.connection being undefined. I'm working in MVC 4.0 and trying to use either nuget-downloaded signalR js files or those from sample projects. These are my script references.
#Scripts.Render("~/Scripts/jquery-1.7.2.min.js")
#Scripts.Render("~/Scripts/knockout-2.0.0.js")
#Scripts.Render("~/Scripts/jquery.signalR.js")
#Scripts.Render("~/signalr/hubs")
The scripts seem to load - I've even put alerts at the start of them which fire, but $.connection is always undefined.
In a bizarre turn of events, I have a different project where I'm trying to use a different jQuery library and it uses $. and that object is ALSO always undefined.
I'm just looking for any possible explanation of what I might be doing wrong. Thanks very much in advance.
I got the same problem today.
Your answer pointed me in the right direction, because I had the EXACT same setup for script loading.
I had all my script tags on the top of the page (head) in the following order.
JQuery
SignalR
/signalr/hubs
my-script.js
And of course, the #Layout.cshtml was so thoughtful to add #Scripts.Render("~/bundles/jquery") at the bottom of the <body> tag.
Here's what's happening.
In this configuration, when the page loads, it loads up all the scripts in the head tag, in the order they're specified.
so it loads JQuery, then SignalR, which setup $.connection then the auto-generated hubs script which sets up the $.connection.hubName,then the site's custom script.
At this point your custom code runs. BUT your code at some point, waits for the body.onload or document.onReady before accessing the $.connection
By the time this event fires, the script bundle which the Layout template added for you at the end of body tag also downloads and executes. This bundle has the jquery library again.... which resets everything SignalR setup on $ and now your $.connection is not defined anymore.
How to Solve It
Easy fix, make sure you don't load JQuery twice, once before SignalR and once after SignalR. I moved all my scripts to load after the bundle and it fixed the issue. Best practice here is to use the 'scripts' section provided by the template.
#section scripts{
#*/* load your scripts here. You can exclude jQuery,
coz it's already in the template */ *#
}
So this is not a SignalR error at all...
That's 2 hours of my life... I'll never get back ...
Hope This Helps.
I solved the problem. I know what I did but I don't know why it worked for sure.
I was referencing the main jquery library (version 1.7.2) at the top of the _Layout.cshtml view, but was not referencing any other jquery scripts. I noticed that by default in the layout view it was loading
#Scripts.Render("~/bundles/jquery")
at the bottom of the view and that a scripts section was located below that.
#RenderSection("scripts", required:false)
I further changed my script references as shown and put my script references shown in the question above inside a
#section scripts
{
#Scripts.Render("~/Scripts/jquery.signalR-0.5.1.js")
#Scripts.Render("~/Scripts/jquery.color.js")
#Scripts.Render("~/signalr/hubs")
#Scripts.Render("~/Scripts/blasht.signalr.js")
}
wrapper on my view so that they would be included after the bundles were loaded. I assume that I was not loading all the necessary jquery because now it works.
Now if I can figure out how this applies to my other projects.
The reason this works is because of the order in which the javascript files are loaded. If you try and load jquery.signalR-0.5.1.js before loading jquery, then you will face the $.connection undefined because for this to register the jquery should be loaded first. In the _Layout.cshtml template the scripts load in the order
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts", required: false)
So inside any of your views you can load signalr under the script section and this should work fine.
I have had same issue.
for me I have included jquery 2 times in page and later in layout.
Removed one of them fixed the issue.
Hope it helps
This happened to me because I dynamically loaded the ~/signalr/hubs script before loading the jquery.signalR-1.1.4.js script.
When dynamically loading, no error was present, however if I took the output of ~/signalr/hubs and pasted it into my chrome dev tools, I received an error message VM1047:18 Uncaught Error: SignalR: SignalR is not loaded. Please ensure jquery.signalR-x.js is referenced before ~/signalr/hubs.
at <anonymous>:18:15
at <anonymous>:300:2

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