Why is my global requirejs var undefined? - javascript

I have two seperate applications. Both use jQuery an RequireJS. I want to embed application A into application B, so I transfer the required HTML to application B. Application B is an instance of edx-platform (https://github.com/edx/edx-platform).
So far so good, but the second app won't load. First I had both script tags with data-main, but it doesn't work. So I searched and I found this: https://stackoverflow.com/a/10839885
I looks good so far, but my global requirejs variable is undefined. In the HTML edx-platform calls RequireJS with this code:
<script>
window.baseUrl = "/static/";
(function (require) {
require.config({
baseUrl: window.baseUrl
});
}).call(this, require || RequireJS.require);
</script>
<script type="text/javascript" src="/static/lms/js/require-config.js"></script>
<script type="text/javascript">
(function (require) {
require.config({
paths: {
'js/courseware/courseware_factory': 'js/courseware/courseware_factory',
'draggabilly': 'js/vendor/draggabilly',
'js/courseware/toggle_element_visibility': 'js/courseware/toggle_element_visibility',
'js/courseware/course_home_events': 'js/courseware/course_home_events',
'js/courseware/link_clicked_events': 'js/courseware/link_clicked_events',
'moment': 'common/js/vendor/moment-with-locales',
'moment-timezone': 'common/js/vendor/moment-timezone-with-data',
'js/student_account/logistration_factory': 'js/student_account/logistration_factory',
'js/groups/views/cohorts_dashboard_factory': 'js/groups/views/cohorts_dashboard_factory',
'js/dateutil_factory': 'js/dateutil_factory',
'js/courseware/accordion_events': 'js/courseware/accordion_events',
'js/bookmarks/views/bookmark_button': 'js/bookmarks/views/bookmark_button',
'js/views/message_banner': 'js/views/message_banner',
'js/student_profile/views/learner_profile_factory': 'js/student_profile/views/learner_profile_factory'
}
});
}).call(this, require || RequireJS.require);
</script>
My code is included later. I tried to run a simple console.log(requirejs) but it didn't work. requirejs is also undefined when calling it from the developer console.

OK I found out why it is undefined. edX also loads the file which undefined all of those variables.
Now I need to find a way to get my code running.

Related

How to properly configure requireJS

Hi I'm trying to make starting template for SPA project mainly using:
RequireJS, KnockoutJS, TypeScript, etc.
I'm having hard time figuring out how to configure paths and folder structure for RequireJS to work properly...
here is my folder structure:
Scripts
app
components
main.js
lib
knockout.js
jquery.js
here is my RequireJS config file:
var config = {
waitSeconds: 15,
paths: {
app: '../app',
'knockout': '/lib/knockout-3.4.2.',
sammy: '/lib/sammy-0.7.5.',
jquery: '../scripts/lib/jquery-1.10.2.'
}
};
This is my attempt for main.js:
define(['jquery', 'PageOne', 'PageTwo'], function ($, pageOne, pageTwo) {
$(document).ready(function () {
var app = Sammy('#main', function () {
this.get('#/pageOne', function () {
pageOne.activate();
});
this.get('#/pageTwo', function () {
pageTwo.activate();
});
});
app.run();
});
});
Here is my Index.cshtml script tag:
<script src="~/Scripts/lib/require.js" data-main="scripts/app/components/main"></script>
I saw in different project that config is called in header so this is in html header:
<script src="~/Scripts/app/config/require.config.js"></script>
My problem is that in main.js it looks for jquery under path defined in data-main (scripts/app/components/), but my jquery is in scripts/lib folder.
I'm trying to figure out by reading online the whole day but it's too much time for me I need someone to give me some hints how is this supposed to work?
Seriously having hard time figuring this out and RequireJS website just isn't helping me atm.
Note: I am beginner in JavaScript based projects, first SPA attempt,
never used RequireJS...
Your configuration file does not do anything. I'm assuming from your description that the script element that loads it is located before the script element that loads RequireJS. That's one valid way to configure RequireJS, but if you want RequireJS to pick up the configuration, you need to set the global variable require before you load RequireJS, and RequireJS will use the value of require as its configuration. Right now you are setting config, which is ignored by RequireJS. So:
var require = {
waitSeconds: 15,
// etc...
And once the configuration is in effect, you should be able to reduce your data-main to data-main="components/main".
I see some of your paths in the paths configuration end with a dot. That's most likely a mistake on your part, or you have some very strange file names.

Can we use requirejs in an angular application to manage/modularize only a part of the application?

I have an existing angular web app which doesn't use require.js. I have to create a new business module in the existing application. Can I use require.js for the new module only? So that I don't have to touch the existing code?
The existing index.html looks like this:
<html>
<head>
...
</head>
<body>
...
<script src="http://cdn.gse.site/angular/1.2.9/angular.js"></script>
<script src="js/angular-ui-router.js"></script>
<script src="js/services/angDashboardService.js"></script>
<script src="js/controllers/angDashboardController.js"></script>
<--- More custom scripts here --->
</body>
</html>
I tried including require-main.js in the existing index.html file without removing any of the existing script tags.
The require-main.js looks like this :
require.config({
baseUrl: 'js',
paths:{
'angular' : '...'
},
shim: {
'angular': {export: 'angular' },
'new-module': {
deps: ['angular'], export: 'new-module'
}
}
});
require(['new-module'], function(){});
I am getting the error as following:
Uncaught Error: [ng:btstrpd] App Already Bootstrapped with this Element '<body class="preload ng-scope" ng-app="angDashboard">'
Can we use requirejs in an angular application to manage/modularize only a part of the application?
Yes you can (but why...?). You will be hits by some serious headache if you are not ware of what are you doing
Anyways to able to do this you must be fully understand the concept of angularJS and requireJS .
<script src="http://cdn.gse.site/angular/1.2.9/angular.js"></script>
<script src="js/angular-ui-router.js"></script>
<script src="js/services/angDashboardService.js"></script>
<script src="js/controllers/angDashboardController.js"></script>
This mean you already had an angular app running. So you will not (should not) config or load angular anymore with requireJS
require.config({
baseUrl: 'js',
paths:{
'async-module' : '...'
},
// You won't use 'shim' with this structure
// shim: {}
});
async-module.js
// assuming somewhere you have did this
// var app = angular.module([...]);
//
// NOW you need to convert this 'app' to global variable. So you can use it it requirejs/define blocks
// window.app = angular.module([...]);
define(function(){
window.app.controller('asyncCtrl', function($scope){
// controller code goes here
});
});
Then somewhere inside your app, when you want to load this async-module
requirejs(['async-module'], function(){
console.log('asyncCtrl is loaded!');
});
SUMARY >>
It is possible to do what you asked but it does not very effective. And will be like hell in code management.
If this answer took you lesser than 5 mins to understand, you can give it a try.
If it took you longer than 5 mins to understand. I am highly not recommending you to do this. Using requireJS with angularJS in common way (everything loaded by requireJS) is already complicated and tricky. And this use case even beyond that.

require.js, am I doing it right?

I'm new to require.js and found the documentation quite hard to understand. After a while I got my project up and running with the following setup.
project
|
|--js
|--vendor
|--require.js
|--modernizr.js
|--jquery.js
|--modules
|--module1.js
|--module2.js
|--main.js
|--index.html
index.html:
<!DOCTYPE html>
<html>
<head></head>
<body>
<script data-main="/js/main.js" src="/js/vendor/require.js"></script>
</body>
</html>
main.js
define([
"vendor/modernizr",
"modules/module1",
"modules/module2"
]);
modules/module1.js
define(['vendor/jquery'], function () {
// Some module code like
$('#button').on('click', function(){});
});
Is this a good setup if I like to have one import file (main.js) like in a less setup for CSS?
This setup is generally in the right direction, just some slight modifications need to be made.
For the modules, you need to pass in a matching number of arguments for each dependency of the module. In this case, you would want to assign $ to what is returned by the jQuery module, so that you can actually use $ within the module:
define(['vendor/jquery'], function ($) {
// Some module code like
$('#button').on('click', function(){});
});
For main.js, the define() call should be a require() call so that you will be executing whatever's in the module instead of simply registering it a module for some other module to execute:
require([
"vendor/modernizr",
"modules/module1",
"modules/module2"
], function(Modernizr, module1, module2) {
// do something with Modernizr, module1, module2
});

Adding RequireJS module that uses jquery on a page that already has jquery as a global

I have an add-on to an application (call it appX) that allows users to create their own customizations using javascript, css and appX's webservices api.
Usually customizations are small and do not involve a lot of external libraries/plugins but when they do have external libs the typical users' library of choice is jQuery.
In the next version of appX they are using jQuery natively which I know is going to break some of the customizations.
So I have a need to modularize this situation. I have some other problems that are coming up and RequireJS seems like a good solution to these issues. I just need to figure out how to apply RequireJS properly for this situation
In my POC I'm loading require.js as follows:
<!--A bunch of other script including jQuery (but not require) are loaded already -->
<script type="text/javascript" src="/custom/js/require.js"></script>
<script type="text/javascript" src="/custom/js/dostuff.js"></script>
We'll call the jQuery loaded with appX jqueryx and the one I want to load jqueryp (p for private)
jQuery utilizes AMD and by default uses this definition internally:
define( "jquery", [], function () { return jQuery; } );
But in this case RequireJS is loaded AFTER jQuery (jqueryx) so there will be no default 'jquery' definition correct?
Some more background before I show you my problem... the file structure is like this:
appx
/js:
jqueryx.js
other.js
appx
/custom/js:
jqueryp.js
dostuff.js
Looking at the RequireJS api it seems that I should be doing something like this:
require.config({
baseUrl : 'custom/js',
paths : { 'jquery' : 'jqueryp'},
map: {
'*': { 'jquery': 'jquery-private' },
'jquery-private': { 'jquery': 'jquery' }
}
});
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
require(['jquery'], function(jq){
console.log(jq.fn.jquery);
});
But when I do this I get an error:
Mismatched anonymous define() module: function (jq)...
I've played around with switching references to jquery, jquery-private as it's kind of confusing but with no progress.
How should I be applying RequireJS to this situation?
Almost a year late but better than no answer at all...
The following part should be moved into a "jquery-private.js" file:
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
You can't define a module in your main entry point. Even if you could, the module has no name so how would you reference it?

play 2.2 webjars requirejs jquery integration

After upgrade to play 2.2, I cannot make requirejs work as before.
It seems to me that the requirejs is not initialized or configured correctly. I tried to follow https://github.com/mariussoutier/play-angular-require-seed, but I cannot even make the simplest case to work.
jquery can be located correctly in main.js, but require(['jquery'].....) does not work in tag.
If someone could help me with this, it would be appreciated a lot.
webjars definition
libraryDependencies ++= Seq(
javaJdbc,
javaEbean,
cache,
"org.webjars" % "jquery" % "1.10.2",
"org.webjars" % "requirejs" % "2.1.1",
"org.webjars" % "webjars-play_2.10" % "2.2.0"
)
resolvers += "typesafe" at "http://repo.typesafe.com/typesafe/repo"
requireJs += "main.js"
requireJsShim += "main.js"
main.js
(function(requirejs) {
"use strict";
// -- PROD RequireJS config --
requirejs.config({
shim: {
"jquery": { exports: "$" }
},
paths: {
"jquery": ["/webjars/jquery/1.10.2/jquery.min"]
}
});
// It works fine here
require(["jquery"], function($) {
console.log($);
});
})(requirejs);
index.scala.html
#(title: String)
<html>
<body>
<script src='/lib/require.js' type='text/javascript' data-main="/assets/javascripts/main"></script>
<script type="text/javascript">
require(["jquery"], function($) {
console.log($);
});
</script>
</body>
</html>
main.js is loaded, and the error message in the console is
Uncaught TypeError: Property 'require' of object [object Object] is not a function
Edit
The key here is to understand the AMD concept. Although two snippets in tag are placed one after the other, they are not guaranteed execute in order. Therefore, when the second snippet runs, the requirejs may not be configured yet.
<script src='webjars/requirejs/2.1.8/require.js' type='text/javascript' data-main="javascripts/main"></script>
<script type='text/javascript'>
// Second snippet
require(['jquery'], function($) {return $;});
</script>
To fix this, we have two different approaches:
Include the javascript code of the second snippet in main.js (specified in data-main) and Use require(['dependencies'], function() {// do second.js})
Do not specify data-main field when including requirejs, and do all the configuration in the second part.
IMHO, the first approach is preferred and is the exact one used in the sample project https://github.com/mariussoutier/play-angular-require-seed
Qualifying my reply, definitely not an expert...
In your index.scala.html page, you're trying to use a script that's loaded asynchronously. That will give you random results, because it might very well not be loaded in time.
From the RequireJS site:
Note: the script tag
require.js generates for your data-main module includes the async
attribute. This means that you cannot assume that the load and
execution of your data-main script will finish prior to other scripts
referenced later in the same page.
For example, this arrangement will fail randomly when the
require.config path for the 'foo' module has not been set prior to it
being require()'d later:
<script data-main="scripts/main" src="scripts/require.js"></script>
<script src="scripts/other.js"></script>
// contents of main.js:
require.config({
paths: {
foo: 'libs/foo-1.1.3'
}
});
// contents of other.js:
// This code might be called before the require.config() in main.js
// has executed. When that happens, require.js will attempt to
// load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js'
require( ['foo'], function( foo ) {
});
Also of note... in the example you linked to, this problem is avoided, because all the usage of "require" happens in main*.js
So what I believe you need to do, is to wrap JavaScript code contained within your second script in an event handler which is listening for an event such as window.onload or DOMContentLoaded event, to delay the execution until those events have fired (and all will be present and correct).
References:
http://requirejs.org/docs/api.html#data-main
Javascript async loading and order of execution
https://github.com/mariussoutier/play-angular-require-seed/blob/master/app/views/index.scala.html

Categories

Resources