I've got a main JS script which looks something like this..
;(function ($) {
<main javascript>
}(jQuery));
I've just created my own external library script which looks like this..
;(function ($) {
var myClass = function() {
<code>
};
}(jQuery));
What I want to do is pass my external library into the main JS script, to look something like this:
;(function ($, myClass) {
<main javascript>
}(jQuery, myClass));
However it says that myClass is undefined. How do I go about defining it?
(In terms of how I'm inserting the code it's using register/enqueue script with Wordpress. Both files are "active" so if I was to throw an alert into them both then they'd both get fired off, I'm just struggling with linking the two together so that I can use the scripts inside myClass whilst within my main JS file).
Thanks
myClass is defined within the scope of
(function ($) {
...
}(jQuery));
so unless the code in that library does
this.myClass = myClass;
or something else to explicitly export it into the global scope then there is no way to reference it from your main script.
How do I declare a namespace in JavaScript? has a lot of discussion on the pros & cons of various ways of exposing an interface to other code in JavaScript.
Related
I have two JS files. One is called common.js and it use $.getScript to include other file with my js code. Part of including looks like this:
jQuery.getScript(js_path + "table.js", function(){
generateTable(chartData, dataTypes);
});
This file (common.js) also contains function compare(a, b).
Now, the second one (table.js) has declared different function which uses the compare function from the first file. Something like this:
function someName() {
var a = 2,
b = 5;
var test = compare(a, b);
return test;
}
When I run the code it gives me:
Uncaught ReferenceError: compare is not defined
How can I use function from the first file.
jQuery.getScript first fetches the JS file from the server, then executes it. If you want to work with global functions (as it seems) you need to pay attention to the following:
Your compare function must be declared before the table.js file is executed.
The compare function must be declared on the global namespace of table.js.
Sorry but without more info this is all you can get.
If your main file, as something like:
(function() {
function compare(){...}
}());
Then the compare function is not declared in the global namespace.
did you check the order of imports? The file with 'compare' method should be first. It should solve the problem.
What I would suggest is to skip getScript if it's just for separating the code.
<script src="common.js"></script>
<script src="table.js"></script>
<script src="app.js"></script>
Where common functions go into common, your table stuff goes into table. This way you get the ordering right. This also clears out the circular dependency one might see a hint of if table depends on common that depends on table by extracting all but the 'common' parts into some form of 'app'.
My javascript project looks like this (Example A)
;(function (window, document, undefined) {
var func1 = function () {
// some code
};
var func2 = function () {
// some code
};
// ... some more functions
// lines of main code
// ...
})(window, document);
I want to place func1, func2, ..., code in separate files to make code like this (Example B):
;(function (window, document, undefined) {
var func1 = require ("func1.js");
var func2 = require ("func2.js");
// ... more requires
// lines of main code
// ...
})(window, document);
…and then somehow compile it to get the code as in Example A
Is there any particular way to do this? I tried to use require.js (r.js), but i've got require and define statements in compiled code (so I need require.js to run compiled code in browser). Is it possible to get flat static js-file without any dependencies with r.js? Maybe there is another way to do this? Thanx
Depending on how your code works, you can always just go cat *.js > all.js then run a minifier or something on it.
I have a page that is split into "widgets" that are loaded dynamically on the fly - JS with require.js, HTML & CSS with custom JS. This is especially handy because it allows each widget define it's own JS requirements.
For example:
define(['jquery', 'mustache'], function($, Mustache) { ...
However, in order to target the widget JS functionality into correct element, I need to pass the widgets root element to the javascript, that is loaded with require.js, which is something require.js doesn't support... :/
What I currently have is something like this, where the define call returns an function that does the rendering...
// Example.js
define(['jquery'], function($) {
return function($el) {
// Render the widget here to "$el"
$el.html('asdsadads');
}
});
... which is run by the require call...
require(['js/example'], function(render) { render($el); });
... which works ok with simple structures but with more complex widgets, the init function starts to bloat, which makes it less pretty and harder to read (also, more prone to bugs).
The optimal situation would be something like this...
// Example.js
define(['jquery'], function($) {
if() { // Check for route and/or other modifiers (is logged in etc)
$el.html('asdasdasd');
} else {
$el.html('qwerty');
}
});
...where the actual functionality is directly inside the define call. Unfortunately, as far as I understand, there is no way to pass the element with the require call, like so...
define(['jquery'], function($, $el) {
So, what is a man to do? Is there a pattern that I could use to somehow pass the element cleanly to the define call? Or do I have to resort into this ugly callback jungle?
The idea of a define block is to return a class or function that can be used in another part of your code. This encourages and re-usable, DRY, modular style of coding.
It doesn't make sense for the define module to be aware of $el at the point of creation. What does make sense is that you return a class that gets instantiated with the $el. This way your module is reusable and you return the burden of control to your application, and not the module itself.
Simple example of a module and its use:
define(['jquery'], function($) {
var MyClass = function(args){
this.initView(args.$el);
}
MyClass.prototype.initView($el){
//init your view
}
return MyClass;
});
Then when you can use this module like this:
define(['path/to/myClass'], function(MyClass) {
var myView = new MyClass({$el: $('.my-selector')}),
myOtherView = new MyClass({$el: $('.my-other-selector')});
});
I'm going to build a rather complicated application in html5 with some heavy javascripting.
In this I need to make some objects which can be pass around. But since there is no like #import foobar.js.
Then I assume that if my html page loads the scripts, then all the scripts can access eachother?
I read (here) that ajax somehow is able to load a .js file from within another .js file. But i dont think this is what I need?
Can go more into details if needed, thanks in advance.
In our projects, we do the following: Suppose you're going to call your project Foo, and have a module called Bar in it,
Then what we do is declare a file called Foo.js that just defines an equivalent to a Foo namespace:
Foo = (function(){
return {
};
})();
Then we create a file called Foo.Bar.js that contains the code for the Bar module:
Foo.Bar = (function(){
// var declarations here that should be invisible outside Foo.Bar
var p, q;
return {
fun1 : function(a, b){
// Code for fun1 here
},
fun2 : function(c) {
// Code for fun2 here
}
} // return
})();
Note that how it is a function that executes immediately, and returns an object that gets assigned to Foo.Bar. Any local variables, like p and q are available to fun1 and fun2 because they're in a closure, but they are invisible outside of Foo.Bar
The functions in Foo.Bar can be constructors for objects and so on.
Now in your HTML you simple include both files like so:
<script type="text/javascript" src="Foo.js"></script>
<script type="text/javascript" src="Foo.Bar.js"></script>
The result will be that you can call Foo.Bar's functions in the JavaScript of your main HTML file without any problems.
You should check out the module pattern:
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth/
This describes alternatives for creating modular code in javascript, how you can protect your code and share APIs and data among them.
You should also consider using and AMD. Require.js is quite popular, but I tend to prefer head.js for this. Keep in mind that these put some requirements on how you structur your code in files, and personally, I don't think it's worth it, compared to a concatenated and minified file included in the bottom of the page.
Then I assume that if my html page loads the scripts, then all the scripts can access eachother?
Yes.
Is there a preferred way to pass server data in a RequireJS module? Our current implementation looks like the following code snippets; using a 'page' object to hold any server/dynamic data and passing that to the main bootstrap. (We don't want to use ajax to populate any dependencies at this time)
From a server page :
<script data-main="scripts/main" src="scripts/require-jquery.js"></script>
<script type="text/javascript">
define("page", function () {
return { guid: "<%=Guid.NewGuid() %>" };
});
</script>
main.js
require(["jquery", "jquery.alpha", "page"], function ($, alpha, page) {
alpha.initialize(page);
});
jquery.apha.js
define(["jquery", "page"], function ($, page) {
return {
initialize: function () {
console.log(page.guid);
//logs guid as expected
}
}
});
I usually do something like this (using PHP on the back-end but anything works):
<script src="scripts/require-jquery.js"></script>
<script>
require(['scripts/main'], function(App) {
var myApp = new App({
param1: <?=json_encode($param1);?>,
param2: <?=json_encode($param2);?>
});
});
</script>
And then define my module as something that takes a config:
define(['jquery'], function($) {
var App = function(options) {
this.options = options;
//blabla
}
// add some stuff to App.prototype maybe
// and finally...
return App;
});
RequireJS says nothing about how to deal with server data, as it is a means to modularize your javascript. So in that regard there is no defacto standard and you can combine RequireJS with json, ajax, php, embedded xml etc however you want.
Two Approaches
There generally are two ways to go about this.
Model a 'dao' or 'service' module that gets the required data from the server and
makes it accessible to its users (similar to your current approach, see code sample below)
Define a global object to which all modules have access
The first approach adds parameters to your functions.
The second provides global access. This also requires your own initialization code to start fetching data.
It comes down to personal preference and how many of these 'dao's' you have. If you have more than one it might become poluting as you need a new parameter for each dao module. In that case making them global seems cleaner.
A problem with your approach
There is a problem with your current approach though, where you have the Page module as a definition (using define() instead of require()), because a define module is created for each object that depends on it. This potentially means multiple calls within the same page. Instead use:
// in seperate file page.js:
require([], function () {
return { guid: "<%=Guid.NewGuid() %>" };
});
This way RequireJS recognizes page as a module because it is a seperate file and it will go to your server only once per page.
If you have a JSON object, make an AJAX call like #yves mentioned in the comments.
There are other options if you don't want to do that. You could put the guid as a data attribute on the script tag. Also, you could try making the loader js file dynamic so the config is set in that.
Honestly though, I'd just make an AJAX call.
I just started today with RequireJS and prior to this I was used to just call the function I wanted to execute on page load like this:
<script>
my_method(<?php echo json_encode( array('opt1'=>true, 'opt2'=>false) );?>);
</script>
As #ziad-saab I've found that the most similar thing I can do is not using the data-main attribute and just define an inline module:
<script src="path/to/require.js"></script>
<script>
require(['my/module'],function(module){
module.my_method(<?php echo json_encode( array('opt1'=>true, 'opt2'=>false) );?>);
});
</script>
The data-main attribute instructs RequireJS to execute the module as soon as require.js and all module dependecies are loaded. Omitting it (the module) and just defining it as an inline module I'm able to throw in PHP variables.
This way I don't need to handle with modules that hold my configurations and the transition to use requirejs is easier in my environment.
I have found some of the answers confusing, so here are the exact steps you need to follow to make it work for you:
In my case I am doing this like so:
index.php
<script src="/js/crm/lib/require.js"></script>
<script>
// this is so called "named define"
define('dto', {
page: JSON.parse('{{ pageDTO | json_encode }}'),
flashMessages: JSON.parse('{{ this.flashSession.getMessages() | json_encode }}')
});
// note we are using relative path to public dir here
// order is also important, we need to define our dto module before bootstraping the application
require(['/js/crm/app.js']);
</script>
app.js
"use strict";
require.config({
// ...
baseUrl: '/js/crm/lib',
paths: { app: '../app' }
});
require(['app/bootstrap']);
some-module.js
(in this case layout.js that is required in app/bootstrap)
"use strict";
define([
'dto',
'jquery',
'lodash'
], function (dto, $, _) {
console.log(dto);
});
Note using data-main to bootstrap the application, without explicit call to require might work, but due to race condition. If defining dto for some reason would take more than it takes requirejs to call main module script will crash. We don't want to rely on that, so we do everything ourselves :)
So this would not work (sometimes):
<script data-main="/js/crm/app.js" src="/js/crm/lib/require.js"></script>
<script>
// this is so called "named define"
define('dto', {
page: JSON.parse('{{ pageDTO | json_encode }}'),
flashMessages: JSON.parse('{{ this.flashSession.getMessages() | json_encode }}')
});
</script>
Use window global variable to transfer server data into js application:
<script type="text/javascript">
window.server_data=parseJSON(<?php echo json_encode(array ("server_data"=>"it works!"));?>);
</script>
<script data-main="js/application" src="js/lib/require.js"></script>
in application.js:
requirejs(["app/main"],function (MyApp){
console.dir(window.server_data); //all our application need this global variable
var myApp=new MyApp();
myApp.init(window.server_data); //and your application now has server data
});