This is going to be a problem that very few if any people have, but it was time consuming and difficult to solve and i figured it out, so here is the solution, one other person in the world who has this problem.
Are you getting all kinds of weird "this.getOnOffValueFromModelValue is not a function" kinds of errors from guideRuntime.js, guide.js , or guidelib -- or other adobe frontend libraries that you do not control?
These may not apply to you directly but if they do definitely keep reading:
Are you using webpack and including custom code on the page elsewhere (perhaps via a data-sly-use or something)?
Does your project use lodash? or perhaps another library that uses a "_" global variable?
Or perhaps jQuery? or other frontend library?
Then you may be asking questions like:
Why is my form not working properly?
Why is some stuff on the form just not working?
Some rules are just not working... why not and how do i fix them?
Oh I'll feed you, baby birds.
( can someone with a higher reputation add the tags adobe-form, aem-form to this, please)
TLDR:
If you're using Webpack, add this to your module rules:
module: {
rules: [
{ parser: { amd: false } }
// ... your other rules
]
}
or if you're not using webpack, make sure your own variables are not leaking into the global scope, because adobe's are and yours may overwrite theirs or vice-versa.
The explanation that may be applicable even if you're not using webpack that may get you in the right direction:
Adobe's client libraries (like guide.js and guideRuntime and the like) aren't particularly good at dependency injecting their stuff. Their code leaks global variables a lot. For example (see picture below) they use underscore's _.each a lot. if you're using lodash, the function signatures are different-- underscores' allows you to define a "this" context as the third parameter, whereas lodash's doesn't.
So, in our case, our lodash was overwriting their underscore causing a bunch of weird issues... EVEN THOUGH we were NOT declaring lodash globally anywhere. WEBPACK WAS defining lodash globally
So moral of the story, open up console, check to see if any of your libraries are defined globally, and if they are, figure out how to make them not global until Adobe decides to fix their stuff (don't hold your breath).
I'm looking at some javascript code and trying to understand how it works.
It contains underscores against some of the functions but I can't see Lodash or Underscore included so I'm confused about how that is working. Here's an example...
theme.Sections.prototype = _.assignIn({}, theme.Sections.prototype, {
_createInstance: function(container, constructor) {...
Can anyone help me understand how that is working?
Here's a link to the site that's using the code so that you can see the whole thing working...
https://debut-demo.myshopify.com/
Edit: It is _.assignIn that I'm confused about. I can't see Lodash loaded so not sure how that is working?
As far as I'm aware, it's generally used to indicate a private variable (but doesn't actually provide any privacy, just a convention).
It's discussed briefly here, though they're advised against: http://javascript.crockford.com/code.html
I know that's it's best practice to isolate your javascript code into IIFEs. This also allows me to make use of the "use strict" magic string.
However, Adding this to every file by hand is not only cumbersome but prone to human error (aka forgetting).
It seems like the sprockets preprocessing would be ideal but the only example I could find was from 2 years ago and it doesn't appear to work:
http://eviltrout.com/2013/02/25/iife-in-rails.html
Does anyone have a working solution? Is the a gem I can use?
I think it did work and I missed a small detail:
One caveat – if you change the IIFE code, you’ll have to clear your tmp directory in order to get your assets to recompile.
Once I clear that out it worked beautifully.
I've came across this situation a few times before and always found a tricky way to make it work but I'd like to know if there's a best practice for that:
Sometimes you have to use several JavaScript SDKs on a page example: Google jsapi and jQuery.
Google calls this function when the SDK is ready to be used:
google.setOnLoadCallback(MyFunction);
jQuery does everything in this callback:
document.ready();
What if I want to manipulate the dom using jQuery AFTER Google's callback.
What's the best way to tell the browser: "Wait for jQuery AND Google to be ready and do the stuff..."
Is it best to have the jQuery callback nested inside Google callback? Or the other way round? I'm a bit confused.
You can do this in different ways, one of which is to use a global variable;
var googleLoaded = false;
google.setOnLoadCallback(function(){
googleLoaded = true;
mainCallback();
});
document.ready(mainCallback);
function mainCallback(){
if(googleLoaded){
...
...
}
}
As a general solution, you can do as given below
var jsLibsToLoad = 5;
jsLib1.onLoad(mainCallback);
jsLib2.onLoad(mainCallback);
jsLib3.onLoad(mainCallback);
jsLib4.onLoad(mainCallback);
jsLib5.onLoad(mainCallback);
function mainCallback(){
if(!(--jsLibsToLoad)){
...
...
}
}
I would recommend you to use some AMD tool like RequireJS. RequireJS is a JavaScript file and module loader, and it is really good with dependancy management. In your particular case (using of some traditional/legacy "browser globals" scripts) you should additionally use Shim Config.
At the start using AMD is a little bit tricky, but it gave a great benefits when you get used to it. It will improve the speed and quality of your code.
I know very little about JavaScript but despite this I'm trying to cobble something together on my wordpress blog. It's not working, and I don't know how to resolve it, and hey, that's what StackOverflow is for, right?
Firstly, the error message is:
Error: element.dispatchEvent is not a function
Source File: http://.../wp-includes/js/prototype.js?ver=1.6
Line: 3936
It happens on page load. My page load handler is registered thusly:
Event.observe(window, 'load', show_dates_as_local_time);
The error goes away if I disable some other plugins, and this (plus googling) led me to conclude that it was a conflict between prototype and jQuery (which is used by some of the other plugins).
Secondly I'm following the wordpress recommended practice of using wp_enqeue_script to add a dependency from my JavaScript to the Prototype library, as follows:
add_action( 'wp_print_scripts', 'depo_theme_add_javascript' );
function depo_theme_add_javascript() {
wp_enqueue_script('friendly_dates', 'javascript/friendly_dates.js', array('prototype'));
}
Now I'm also aware that there are some potential conflicts between jQuery and Prototype which are resolved using the jQuery noConflicts method. I've tried calling that from various places but no good. I don't think this is the problem because a) the noConflict function relates solely to the $ variable, which doesn't seem to be the problem here, and b) I would expect wordpress to sort it out for me because it can...
Lastly, using the Venkman debugger I've determined that the element referenced in the error message is indeed an HTMLDocument but also does lack a dispatchEvent. Not sure how this could happen, given it's a standard DOM method?
There is a nasty trick many libraries do that I've taken a distinct liking to, and it looks like prototype is one of these.
Mootools does this, If I am right, and it involves overloading many of the prototypes on the basic classes, monkey patching them.
And likewise, I similarly encountered strange behaviour when mootools and jQuery were present, usually jQuery dying because it was calling some object method which had been somehow overloaded/monkey patched by Mootools.
Also, mysteriously, taking mootools out of the script usage list, resulted in everything running much faster, which I concluded was due to less object pollution.
Now I could be wrong, but I concluded from my experience such libraries just simply don't like to co-exist with each other, and seeing how mootools code seemed to me to degrade speed at which normal things were done, I sucked up and ported all mootools based code to jQuery ( A time consuming deal I assure you ), and the result, was code that was fast and didn't have weird errors that were unexplainable.
I recommend you consider migration as at least One of your options.
One More thing, when writing:
I tend to use this syntax with all my jQuery driven code, for a bit of safe encapsulation in the event somebody breaks '$' somehow.
Runtime Code
This waits for document.ready before executing:
jQuery(function($){
code_with_$_here;
});
jQuery Plugins
(function($){
code_with_$_here;
})(jQuery);
Using these will make it easier for people using any jQuery you happen to write to be able to use it without much of a conflict issue.
This will basically leave them to make sure their code isn't doing anything really magical.
Its worth reading this article on the JQuery site about Using JQuery With Other Libraries. It deals with more than just the noConflict option.
I think you should search well because all jQuery plugins has a prototype version and all prototype plugins has a jQuery version.
If you really don't find what you look and you can't use only one library, take a look here at
jQuery.noConflict();
But again, i think it make no sense to load over 15-20kb for each library :)
Thanks for the suggestions all. In the end I think Kent's explanation was the closest, which basically amounted to "Prototype is broken". (Sorry if I'm summarizing you incorrectly :)
As for the jQuery.noConflict option - I already mentioned this in the question. It makes a difference when you run this method, and I have very little control over that. As I said, I have tried running it in a couple of different places (specifically the page header and also from my script file), to no effect. So, much as we'd all like it to be, "just use noConflict" is not an answer to this question, at least not without additional information.
Besides, jQuery.noConflict seems to be about the $ variable, and the code around the error point does not deal with that variable at all. Of course they could be related indirectly, I haven't tracked it down.
So basically I ended up rewriting the script using jQuery instead of Prototype, which actually had its own problems. Anyway I've published the whole war story on my blog, should you be interested.