Why isn't RequireJS passing jQuery into the functions alias? - javascript

I downloaded the sample-project for the latest-release of RequireJS. Their documentation implies anything loaded is passed-into the parameter list of the associated function (in corresponding order).
So I decided to try it...but it doesn't seem to work!
Firebug (net tab) shows jQuery as being loaded: so RequireJS obvioulsy did that part successfully
Firebug (console tab) shows '$ is not a function'
My question is: Why isn't the alias getting populated?
MY CODE LOOKS LIKE:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="Scripts/require.js" type="text/javascript"></script>
<script type="text/javascript">
require(["scripts/jQuery/Core/jquery-1.7.2.min"], function ($) {
// jQuery is not passed-into the function, so the alias fails!
$(function () {
var stop = "";
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
</form>
</body>
</html>
THIER SAMPLE LOOKS LIKE:
//Inside scripts/main.js
require(["some/module", "a.js", "b.js"], function(someModule) {
//...
});

jQuery should be loaded through the special name "jquery", otherwise it won't register itself (since jQuery uses a named define).
// create an alias that points to proper file
require.config({
paths : {
jquery : "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min"
}
});
// require jquery usign the path config
require(["jquery"], function ($) {
console.log($);
});
That is the main reasons why named define is considered an anti-pattern and should be used only when needed (when you have multiple modules inside same file).

Be sure to read the "README.md" for the RequireJS+jQuery sample project. There are many complications with using jQuery that you need to decide on how best to tackle it for your project during the initial setup. Once you've figured out what's best for you and implemented it, though, it shouldn't be a problem again.
Much of the complication also comes from the fact that jQuery isn't a true AMD module, they just have a hack in the codebase to do a define if it detects the define function is available. For example, this means the jQuery module name will always be "jquery" (note the lowercase 'q') unless you wrap it yourself, so if you define the path for it in your config you MUST have the key named "jquery" (again, with a lowercase 'q') or there will be a mismatch. That bit us when first setting up RequireJS on our project (we named the key "jQuery").

Is your scripts folder 'Scripts' or 'scripts'?
You're making a request for "Scripts/require.js" as well as for "scripts/jQuery/Core/jquery-1.7.2.min". Take a look at the Net tab of Firebug... I bet you're generating a 404 there.

Related

React - Using external js from CDN

Sorry, I put this again since the old post got merged into some post that doesn't relate to my question ... I'm new to React and trying to convert a php website into react components. However, in old website there are some function in pure jquery and from CDSNJS. The external javascripts function are not binding well with my component and I cannot figure out how to. Please can anyone give me some advice.
Case 1:
I got a an external function like this:
;(function ($) {
/* Global variables */
var prty, flickr;
$.fn.flickrGallery = function(flickrID) {
//Defaults settings
var opts = $.extend({}, {
Key:prty.settings["Key"],
Secret:prty.settings["Secret"],
User:prty.settings["User"],
PhotoSet:flickrID,
Speed:400,
navigation:1,
keyboard:1,numberEl:1 });
//Setup
prty.Setup($(this), opts);
}; //End FN
prty = {
.... Internal code
};
})(jQuery);
And this is my component's code:
async componentDidMount() {
//$('#gallery').flickrGallery(2); // Not work
//const el = ReactDOM.findDOMNode(this.display); Not work
//$(el).vectorMap({map: 'world_mill_en'});
//$(el).flickrGallery(2);
//const el = ReactDOM.findDOMNode(this.domRef); Not work
//window.$('#addSupModal').modal('show')
//$(el).flickrGallery(2);
window.$(this.productIntro).flickrGallery(2); Not work
}
Every time I run, an error like this appears:
Unhandled Rejection (TypeError): window.$(...).flickrGallery is not a function
Case 2:
Beside the case above, I'm also using a lib from CDNJS
<!-- jQuery 1.8 or later, 33 KB -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Fotorama from CDNJS, 19 KB -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.js"></script>
I have tried including these links into index.html but the same error as above happens when I run ... Please help
Try to access the flickrGallery function via window.jQuery instead of window.$.
The plugin add the flickrGallery function to jQuery. In most of the time, jQuery should be the same as $. However, in some cases, multiple version of jQuery are loaded and jQuery may no longer be equals to $.
The following suggestions were told to be not solving the problem. I will keep them below in case someone find it useful.
It looks like your react component script is executed and rendered before the external scripts is being executed. There are many causes to it and one of the reasons is the ordering of your script tags.
In the document head, make sure the ordering of your script tag is as follow.
<script src="path/to/external/library.js"></script>
<script src="path/to/your/react/script.js"></script>
These script tags do not have the defer nor async attribute, suggesting they should be downloaded, parsed and executed in order. The external script is executed first.
In other cases, where there are defer, async, etc. attributes are in the script tag, you can understand the order of execution by reading this cheat sheet.
If you are using plugin which adds its functionality to some global variable, your bundler may tree-shake it away because it does not detect any usage of its exports and thinks the module is not needed. In this case, you have to add side effect import (Doc).
In your entry module, add this at the very top:
import 'some-jquery-plugin'

Using jQuery and RequireJS at start of processing

I often start my JavaScript apps like this:
jQuery(function($) {
... code for the app ...
});
I'm just starting to use RequireJS, and will start the app like this:
define(['jquery'], function($) {
... code for the app ...
});
Now, as I don't want the app to start processing until all the HTML has been loaded, I've combined the two like this:
require(['jquery'], function($) {
$(function($) {
... code for the app ...
});
});
Is that the way to do it?
The RequireJS documentation touches on this and offers has a slightly more convenient option:
require(['domReady!'], function (doc) {
//This function is called once the DOM is ready,
//notice the value for 'domReady!' is the current
//document.
});
Note that you will need to download the domReady plugin, and if you have a very complex page you may wish to use the "explicit function call" method that they also show... Although then it looks an awful lot like what you're already doing with jQuery.
So the main diferences between define and require in this scenario is, one declare a module and the second one call this defined module, then if it is not loaded, the browser download the js library.
To take control about when your require files will download, you need to use the domReady plugin.
You need to put the js library at you require.config, I usually put at the same directory as declared at the baseUrl property, for example:
require.config({
baseUrl: "js/lib",
paths:{
filter:"../src/filter",
addPanel: "../src/edit-panel"
}
}
I put the domReady.js at the js/lib/ folder.
So, then you can use the require method at any place of you html file:
require(['jquery!'], function ($) {
});
Note that I use the symbol ! to indicate that this library is load after the completely page load.
As the box at the top of the page, my question is answered here:
Requirejs domReady plugin vs Jquery $(document).ready()?
The other answers here essential repeat what's in the above link. But, thanks!

how should I write my define to work with curl.js?

I'm reading Addy Osmani's excellent blog post about writing AMD modules. I start with a simple chunk of js that I lifted from his post:
define('modTest', [],
// module definition function
function () {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
}
);
I took out the dependencies on foo and bar. Just want a simple object that logs to the console.
So I save that in /js/modTest.js and then try to load it:
curl(['/js/modTest.js'])
.then(function(mt) {
console.log("Load complete");
console.log("mt:");
console.log(mt);
mt.doStuff()
}, function(ex) {alert(ex.message);})
Result: error: Multiple anonymous defines in URL. OK that didn't work. Tried adding in a namespace: define('myCompany/modTest', [],, same result. Tried adding an empty string in the dependency array, same result.
Also tried curl(['modTest.js'], function(dep){console.log(dep)}); with the same result.
Is the code in Addy's blog post incorrect? Am I doing something wrong? Maybe a bug in curl?
Update 5/24: I ditched curl.js in favor of require.js. Zero odd errors, very little work to change over. I did have to deal with amdefine a bit to get my code running client and server side (one object is in both places, so grunt had to be configured to take care of that). My defines generally look like:
define(->
class AlphaBravo
...
And never have any trouble loading.
You asked curl() to fetch a module called "/js/modTest.js". It found the file and loaded it and found a module named "modTest", so it complained. :) (That error message is horribly wrong, though!)
Here's how you can fix it (pick one):
1) Remove the ID from your define(). The ID is not recommended. It's typically only used by AMD build tools and when declaring modules inside test harnesses.
2) Refer to the module by the ID you gave it in the define(). (Again, the ID is not recommended in most cases.)
curl(['modTest'], doSomething);
3) Map a package (or a path) to the folder with your application's modules. It's not clear to me what that would be from your example since modTest appears to be a stand-alone module. However, if you were to decide to organize your app's files under an "app" package, you packages config might look like this:
packages: [ { name: 'app', location: 'app' } ]
Then, when you have code that relies on the modTest module, you can get to it via an ID of "app/modTest".
curl(['app/modTest'], doSomething);
I hope that helps clear things up!
Fwiw, Addy's example could actually work with the right configuration, but I don't see any configuration in that post (or my eyes missed it). Something like this might work:
packages: [ { name: 'app', location: '.' } ]
-- John
I've just had a similar problem which turned out to be the include order I was using for my other libraries. I'm loading handlebars.js, crossroads.js, jquery and a few other libraries into my project in the traditional way (script tags in head) and found that when I place the curl.js include first, I get this error, but when I include it last, I do not get this error.
My head tag now looks like this:
<script type="text/javascript" src="/js/lib/jquery.js"></script>
<script type="text/javascript" src="/js/lib/signals.js"></script>
<script type="text/javascript" src="/js/lib/crossroads.js"></script>
<script type="text/javascript" src="/js/lib/handlebars.js"></script>
<script type="text/javascript" src="/js/lib/curl.js"></script>
<script type="text/javascript" src="/js/main.js"></script>
You have a problem with your define call. It is NAMED
See AMD spec for full story on how to write defines, but here is what I would expect to see in your js/modTest.js file:
define(/* this is where the difference is */ function () {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
}
);
Now, the boring explanation:
CurlJS is awesome. In fact, after dealing with both, RequireJS and CurlJS, I would say CurlJS is awesome-er than RequireJS in one category - reliability of script execution ordering. So you are on the right track.
On of the major things that are different about CurlJS is that it uses "find at least one anonymous define per loaded module, else it's error" logic. RequireJS uses a timeout, where it effectively ignores cases where nothing was defined in a given file, but blows up on caught loading / parsing errors.
That difference is what is getting you here. CurlJS expects at least one anonymous (as in NOT-named) define per loaded module. It still handles named defines fine, as expected. The second you move the contents of "js/modTest.js" into inline code, you will have to "name" the define. But, that's another story.

How can I get my jasmine tests fixtures to load before the javascript considers the document to be "ready"?

I am fairly certain that the issue is that the jquery bindings set to run on $(document).ready do not have the fixture html available to them. So when my events occur that are intended to make a change to the DOM via a jquery function, nothing happens, and my tests fail. I saw a "solution" to this problem here, but that solution which did work for me, required changing my working jquery function to bind with the .live method instead of the .click method. I have two issue with this. First I do not want to have to change my working code so that the tests will pass properly. The testing framework ought to test whether the code will work in the app, where the DOM load and the javascript bindings occur in the correct order. The second issue I have with the solution is that .on and .delegate both did not work for some reason and the only thing that ended up working was to use the .live method which is currently in the process of being deprecated. In conclusion, I would like to figure out how to change either my tests or the testing framework itself, such that the fixtures are loaded before the functions that run in $(document).ready.
I am working with rails 3.2.8 and I have two different branches set up to experiment with jasmine testing. One of the branches uses the jasminerice gem and the other uses the jasmine-rails gem. The Javascript and jQuery(when using the .live method) tests all pass properly in both of these set-ups.
Here is a description of the branch using jasminerice:
Here are the lines from my Gemfile.lock file describing the jasmine and jQuery set-up:
jasminerice (0.0.9)
coffee-rails
haml
jquery-rails (2.1.3)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
Jasminerice includes the jasmine-jquery extension by default. The jasmine-jQuery extension provides the toHaveText method I am using in the tests.
The test file jasmine_jquery_test.js which is located directly within the spec/javascripts directory contains this content:
#= require application
describe ("my basic jasmine jquery test", function(){
beforeEach(function(){
$('<a id="test_link" href="somewhere.html">My test link</a>').appendTo('body');
});
afterEach(function(){
$('a#test_link').remove();
});
it ("does some basic jQuery thing", function () {
$('a#test_link').click();
expect($("a#test_link")).toHaveText('My test link is now longer');
});
it ("does some the same basic jQuery thing with a different trigger type", function () {
$('a#test_link').trigger('click');
expect($("a#test_link")).toHaveText('My test link is now longer');
});
});
describe ('subtraction', function(){
var a = 1;
var b = 2;
it("returns the correct answer", function(){
expect(subtraction(a,b)).toBe(-1);
});
});
My javascript file tests.js which is located in the app/assets/javascripts dir has this content:
function subtraction(a,b){
return a - b;
}
jQuery (function($) {
/*
The function I would rather use -
$("a#test_link").click(changeTheTextOfTheLink)
function changeTheTextOfTheLink(e) {
e.preventDefault()
$("a#test_link").append(' is now longer');
}
*/
$("a#test_link").live('click', function(e) {
e.preventDefault();
$("a#test_link").append(' is now longer');
});
});
My application.js file located in the same app/assets/javascripts dir has this content:
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require vendor
//= require_tree .
And the description of the jasmine-rails branch can be found in the content of my first jasmine test related stackoverflow question.
So if anyone has an idea how to manipulate the tests such that the $(document).ready functions are run after the fixtures are loaded I would very much like to hear your thoughts?
Adding the jQuery directly to the html fixture worked for me to get the desired behavior. It is not exactly an answer to this question, but I am starting to believe it's the best solution currently available. My changes where made in the jasmine-rails gem set-up and I haven't yet tried it in the jasminerice branch.
Here is my test file:
describe ("my basic jasmine jquery test", function(){
beforeEach(function(){
loadFixtures('myfixture.html');
});
it ("does some basic jQuery thing", function () {
$('a#test_link').click();
expect($("a#test_link")).toHaveText('My test link is now longer');
});
it ("does the same basic jQuery thing with a different event initiation method", function () {
$('a#test_link').trigger('click');
expect($("a#test_link")).toHaveText('My test link is now longer');
});
});
describe ('substraction', function(){
var a = 1;
var b = 2;
it("returns the correct answer", function(){
expect(substraction(a,b)).toBe(-1);
});
});
And here is my fixture file:
<a id="test_link" href="somewhere.html">My test link</a>
<script>
$("a#test_link").click(changeTheTextOfTheLink)
function changeTheTextOfTheLink(e) {
e.preventDefault()
$("a#test_link").append(' is now longer');
}
</script>
Personally, I consider this to be a bug jasmine-jquery. I "solved" this by making my fixtures part of the SpecRunner.html. Not ideal but it works in simple cases.
Have you tried jasmine-jquery?
https://github.com/velesin/jasmine-jquery
From it's github page,
jasmine-jquery provides two extensions for Jasmine JavaScript Testing Framework:
a set of custom matchers for jQuery framework
an API for handling HTML, CSS, and JSON fixtures in your specs
I used dom_munger to automatically generate the fixture for me, so adding the jquery code manually inside the fixture isn't an option for me. I've been searching for the same answer, and the best solution I can think of right now is to use event delegate in jQuery.
For example, instead of writing this:
$('#target').click(function(){
// Do work
});
Do this:
$(document).on('click', '#target', function(){
// Do work
});
In this way, the listener is attached to the document, which is present before the fixture is loaded. So when the click event happens on #target, it bubbles up to document. Document checks if the origin matches the second argument - '#target'. If it matches, the handler function will be called.
I know there are limitations to this, such as initializing plug-ins, but it does solve part of the problem.
I took a slightly different approach to those described here to solve this limitation.
Disclaimer: I work for Microsoft so I cannot post my actual source code here without legal approval, so instead I'll just describe an approach that works well.
Rather than trying to change how document.ready works, I modified the jasmine-jquery source to support a function called fixturesReady that takes a callback.
Essentially this is defined inside an IIFE, and holds an array of callbacks per event name privately, that are iterated over on trigger.
Then on this chunk you can put the trigger:
jasmine.Fixtures.prototype.load = function() {
this.cleanUp()
this.createContainer_(this.read.apply(this, arguments))
fixturesReady.trigger("loaded", arguments); // <----- ADD THIS
}
So in your tests now you can code against:
fixturesReady(yourCallback)
And you know that when yourCallback is invoked you can safely query the DOM for your fixture elements.
Additionally, if you're using the async.beforeEach jasmine plugin you could do this:
async.beforeEach(function(done){
fixturesReady(done);
...
loadFixtures("....");
});
Hope that helps, and serves to give you some ideas about solving this problem.
NOTE: Remember in your plugin to clear any callbacks in an afterEach block if necessary :)
It has been a while since this question was asked (and an answer accepted).
Here is a better approach to structure your test and load the script for testing with jasmine.
templates/link.tmpl.html
<a id="test_link" href="somewhere.html">My test link</a>
js/test-link.js
$("a#test_link").click(changeTheTextOfTheLink)
function changeTheTextOfTheLink(e) {
e.preventDefault()
$("a#test_link").append(' is now longer');
}
specs/link-test.spec.js
describe ("my basic jasmine jquery test", function(){
jasmine.getFixtures().fixturesPath = ''
var loadScript = function(path) {
appendSetFixtures('<script src="' + path + '"></script>');
};
beforeEach(function(){
loadFixtures('templates/link.tmpl.html');
loadScript('js/test-link.js');
});
it ("does some basic jQuery thing", function () {
$('a#test_link').click();
expect($("a#test_link")).toHaveText('My test link is now longer');
});
it ("does the same basic jQuery thing with a different event initiation method", function () {
$('a#test_link').trigger('click');
expect($("a#test_link")).toHaveText('My test link is now longer');
});
});
Spec Runner
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Spec Runner</title>
<link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.3/jasmine.css">
<script type="text/javascript" src="lib/jasmine-2.0.3/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-2.0.3/jasmine-html.js"></script>
<script src="lib/jasmine-2.2/boot.js"></script>
<script type="text/javascript" src="lib/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="lib/jasmine-jquery.js"></script>
<script type="text/javascript" src="specs/link-test.spec.js"></script>
</head>
<body>
</body>
</html>

RequireJS Flawed By Example?

Looking into RequireJS but unlike Head.JS which downloads in undetermined order but evaluates in a determine order, RequireJS seems different
Normally RequireJS loads and evaluates scripts in an undetermined order.
Then it shows how to prefix order! to the script names for explicit ordering etc..
Then in the examples:
require(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});
So if jquery.alpha is downloaded and evaluated before jquery then surely this would cause a problem? Forgetting any client code usage such as function body above, if like most plugin they attach to jQuery.fn then at stage of evaluation then jQuery will undefined in this scenario.
What am I missing here?
RequireJS is not designed to load plain javascript, but to load defined modules. The module format looks something like:
define(['a', 'b'], function(a, b) {
return { zzz: 123 };
});
The important thing to note is that all of the module code is inside an anonymous function. So if the file is run in an arbitrary order, it doesn't matter, because all it does is register the module. The module code is then run in dependency order, with the return value becoming the module object, which is passed as a parameter to code that uses the module.
If you are trying to load plain files, this will not work correctly for you. There is the order plugin to force load order in that case.
It should be noted that that example uses the custom made version of "requirejs and jquery" packaged together, which I believe means that jquery will always be available first.
If you have problems, you can always wrap your plugins within a module definition and make sure they depend on jquery themselves, again ensuring the order is correct:
/* SPECIAL WRAPPING CODE START */
define(['jquery'], function(jQuery) {
// .... plugin code ....
/* SPECIAL WRAPPING CODE END */
});
You are correct, without something to aid in the order an exception will occur. The good news is RequireJS has an Order plug-in to help in this.
I'm currently evaluating RequireJS...
And Here Is An Example of One of My Files:
The 'order!' command will load files for you sequentially. You can (then) use the callback to load other (support) files.
<script src="Loaders/RequireJS/requireJS.js" type="text/javascript"></script>
<script src="Loaders/RequireJS/order.js" type="text/javascript"></script>
<script type="text/javascript">
require(["Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery-1.3.2.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery.tools.min.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tmpl.js"], function() {
require(["././Includes/JavaScript/jQuery/jGeneral.js",
"././Includes/JavaScript/jQuery/autocomplete.js",
"././Includes/JavaScript/jQuery/jquery.ErrorWindow.js",
"././Includes/JavaScript/jQuery/jquery.ValidationBubble.js",
"././Includes/JavaScript/jQuery/jquery.Tootltip.js",
"././Includes/JavaScript/jQuery/jquery.Extensions.js",
"././Includes/JavaScript/jQuery/jquery.Toaster.js"], null);
require(["././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.dimensions.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jQuery.Color.Animations.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.corners.min.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js"], null);
});
</script>
In All Honesty:
I'm looking at various asynchronous resource-loaders and I'm having a hard-time finding one that does everything I need. I'm also finding the documentation in each one lacking.

Categories

Resources