So I have a small requirejs application that needs to create instances of a dynamic list of classes in runtime. Basically, reflection. I've done quite a bit of reading, but I've been finding a lot of references to Typescript, which I'm not using.
The principal idea is that before requirejs is ready, an array is loaded with a list of classes that will be required. This array is given to requirejs after its main entry point and I hope to create an instance for each entry.
I have done some reading of Ben Nadal's blog here http://www.bennadel.com/blog/2320-extending-classes-in-a-modular-javascript-application-architecture-using-requirejs.htm and I like his pattern and think this would work well for some of the modules I plan to dynamically create.
I had a thought that I could do something like this:-
_.each(loader, function(dep) {
require([dep.name]);
});
With loader being the global loaded with the array list. This doesn't create an instance of the dependency though, which is what I want in this case, like so:-
new Carousel('Delboy');
new Carousel('Rodney');
new Carousel('Grandad');
This, in this example, would create an instance of 3 new carousels, each with a name as passed in via the constructor. I think I am missing something in my understanding, help is appreciated.
Each resolved AMD dependency is an AMD module, which means that it's either a singleton object or a function. In the post by Ben Nadel which you referred to, a distinction is made between "definitions" and "instances". A definition is a singleton, and from a definition (function) you can create multiple instances. In Ben's terminology, RequireJS will only give you the definitions, and it is up to you to create the instances.
So, the following should work for what you're trying to do:
define('Carousel', [], function (name) {
this.name = name;
});
var loader = {};
var carousels = ['Delboy','Rodney','Grandad'];
carousels.forEach(function (carouselName) {
require(['Carousel'], function (Carousel) {
loader[carouselName] = new Carousel(carouselName);
});
});
Related
I'm building a fairly large node.js client library and I'd like to be able to 'namespace' portions of it to keep it more organized. For example:
var client = new Client(config);
client.activities.get(activityId, function(activity) {
...
});
...
client.user.get(userId, function(user) {
...
});
I'm currently trying to do something like this in the module:
function Client(config) {
this.config = config;
}
Client.prototype.activities = require('./activities');
Client.prototype.user = require('./user');
module.exports = Client;
but when 'get' is called in the activities 'submodule', the "this" is for the module, of course, and not the outer Client function. Basically, both of the submodules need access to the outer configuration information ('config' in this example). What is the best practice around doing this in node.js?
I think a modeling issue with the plan you have is that new X() copies each property reference of X.prototype to the new item; for instance, X.myFunction is the exact same reference as X.prototype.myFunction; but does NOT create a new copy of myFunction.
It sounds like if activities is a part of a Client (the same way StreetAddress might be), you actually want activities to be a Class, not a module, and for Client to create a new instance of it when it's constructed. That's not really something that prototype is useful for. If I'm wrong, maybe you could show an example of a basic operation activities would be used for.
Coming from Java/C# I struggle to understand what that actually means for me as a developer (I'm thinking too much object-oriented).
Suppose there are two html files that use the same Dojo module via require() in a script tag like so:
<script type="text/javascript">
require(["some/module"],
function(someModule) {
...
}
);
</script>
I understand that require() loads all the given modules before calling the callback method. But, is the module loaded for each and every require() where it is defined? So in the sample above is some/module loaded once and then shared between the two HTMLs or is it loaded twice (i.e. loaded for every require where it is listed in the requirements list)?
If the module is loaded only once, can I share information between the two callbacks then? In case it is loaded twice, how can I share information between those two callbacks then?
The official documentation says "The global function define allows you to register a module with the loader. ". Does that mean that defines are something like static classes/methods?
If you load the module twice in the same window, it will only load the module once and return the same object when you request it a second time.
So, if you're having two seperate pages, then it will have two windows which will mean that it will load the module two times. If you want to share information, you will have to store it somewhere (the web is stateless), you could use a back-end service + database, or you could use the HTML5 localStorage API or the IndexedDB (for example).
If you don't want that, you can always use single page applications. This means that you will load multiple pages in one window using JavaScript (asynchronous pages).
About your last question... with define() you define modules. A module can be a simple object (which would be similar to static classes since you don't have to instantiate), but a module can also be a prototype, which means you will be able to create instances, for example:
define([], function() {
return {
"foo": function() {
console.log("bar");
}
};
});
This will return the same single object every time you need it. You can see it as a static class or a singleton. If you require it twice, then it will return the same object.
However, you could also write something like this:
define([], function() {
return function() {
this.foo = function() {
console.log("bar");
};
};
});
Which means that you're returning a prototype. Using it requires you to instantiate it, for example:
require(["my/Module"], function(Module) {
new Module().foo();
});
Prototyping is a basic feature of JavaScript, but in Dojo there's a module that does that for you, called dojo/_base/declare. You will often see things like this:
define(["dojo/_base/declare"], function(declare) {
return declare([], {
foo: function() {
console.log("bar");
}
});
});
In this case, you will have to load it similarly to a prototype (using the new keyword).
You can find a demo of all this on Plunker.
You might ask, how can you tell the difference between a singleton/static class module, and a prototypal module... well, there's a common naming convention to it. When your module starts with a capital letter (for example dijit/layout/ContentPane, dojo/dnd/Moveable, ...) then it usually means the module requires instances. When the module starts with a lowercase letter, it's a static class/singleton (for example dojo/_base/declare, dijit/registry)
1) dojo require, loads the module once and then if you called it again require() will simply return if the package is already loaded. so the request will be called once and it will also call any dependencies once.
but all that if you are in the same HTML page if you leave the page and call the same module in a different page then it will be called from the server. you can also use cache in your config settings so things will be cached in the browser and the file will or not by setting the cacheBust to true if you want a fresh copy or false if you want things to be cached.
2) if you are in the same html page and domain, the module didn't change the module will be the same and you can share values and any change you make you can get it from anywhere unless you call a new instance. but that is not possible between different html pages.
3) not it is not like a static classes or methods from what I understand static methods A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields..
dojo work differently it is a reference for an object if you did it in that way :
define(function(){
var privateValue = 0;
return {
increment: function(){
privateValue++;
},
decrement: function(){
privateValue--;
},
getValue: function(){
return privateValue;
}
};
});
This means every bit of code loads that module will reference the same object in memory so the value will be the same through out the use of that module.
of course that is my understanding please feel free to tell me where I am wrong.
I have created a JavaScript library which can be used for logging purposes.
I also want to support the logging of requirejs.
Which functions/events of requirejs can I prototype/wrap so I can log when a module is initialized and when it is done initializing and returns the initialized object.
For instance if I call require(["obj1","obj2", "obj3"], function(obj1, obj2, obj3){}
I would like to know when requirejs begins on initializing each of the object, and I would like to know when each object is completely initialized.
I looked into the documentation/code, but could not find any usefull functions I can access from the requirejs object or the require object.
Note: I do not want to change the existing code of requirejs I wish to append functionality from the outside by either prototyping or wrapping.
What I have tried (problem is that this only accesses the begin and end of the entire batch of modules):
var oldrequire = require;
require = function (deps, callback, errback, optional) {
console.log("start");
var callbackWrapper = callback;
callbackWrapper = function () {
console.log("end");
var args = new Array();
for(var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
callback.apply(this, args);
};
oldrequire.call(this, deps, callbackWrapper, errback, optional);
};
This is a "better than nothing answer", not a definitive answer, but it might help you look in another direction. Not sure if that's good or bad, certainly it's brainstorming.
I've looked into this recently for a single particular module I had to wrap. I ended up writing a second module ("module-wrapper") for which I added a path entry with the name of the original module ("module"). I then added a second entry ("module-actual") that references the actual module which I require() as a dependency in the wrapper.
I can then add code before and after initialization, and finally return the actual module. This is transparent to user modules as well as the actual module, and very clean and straightforward from a design standpoint.
However, it is obviously not practical to create a wrapper per module manually in your case, but you might be able to generate them dynamically with some trickery. Or somehow figure out what name was used to import the (unique) wrapper module from within it so that it can in turn dynamically import the associated actual module (with an async require, which wouldn't be transparent to user code).
Of course, it would be best if requirejs provided official hooks. I've never seen such hooks in the docs, but you might want to go through them again if you're not more certain than me.
If I am using Require.js for managing modules in a project with Backbone.js (which also has underscore), when extending a module I can do something like this
require(['Home'], function(home) {
'use strict';
var view = home.View.prototype;
_.extend(view,{
anotherTitle: 'Welcome Jean Luc Picard';
});
});
or
require(['Home'], function(home) {
'use strict';
var view = home.View.prototype;
view.anotherTitle= 'Welcome Jean Luc Picard'; //this is a new attribute
});
what is the most approrpiate way to do it?
You should use extend.
Remember that modifying a prototype of a Backbone type (which is what I assume home.View to be) will extend/modify that prototype for all consumers, which might be unexpected behavior. Even when using require, you can modify those dependencies directly and impact subsequent require calls (this happens because you're modifying the dependency in the require cache, so subsequent requests to the same dependency don't need to occur).
Using .extend() is the best way to create your own extended/custom types. Behind the scenes, extend() does in fact modify the prototype, but it's the prototype of the new object type created and effectively uses the backbone type as a super.
So, to create your own type:
// Create a new object whose prototype is the combination of Backbone.View
// and the object passed to extend
var MyCustomView = Backbone.View.extend({ ... });
var instance = new MyCustomView();
If, however, home.View is a custom view type already, it's functionally probably equivalent to either do a .extend on it or adding things to the prototype manually. However, for consistency and clarity's sake, you should always use the handy dandy extend method to create a sub type.
var MySubCustomView = MyCustomView.extend({ ... });
var instance = new MySubCustomView();
I'm building an app that has a single global namespace like so:
var myApp = {};
I then have a bunch of different reusable "modules" comprised of models, views and controllers.
//Bar chart module code
org.example.chart.bar.module
org.example.chart.bar.model
org.example.chart.bar.view
org.example.chart.bar.controller
I also have a big dataSource singleton and a dataManager for loading data to the dataSource:
org.example.data.dataSource
org.example.data.dataManager //populates the dataSource with CSV data
And finally translation strings and settings that should be available across the app:
org.example.static.translations
org.example.static.settings
How would you (re-)organize this so that I have easy access to the application level singletons (such as dataSource, dataManager, translations etc.) and can easily instantiate reusable modules that get scoped under the current application instance?
(Would you for example, already from the beginning, use the same namespace for your "classes" and your app? Or would you perhaps make references like so: myApp.translations = org.example.static.translations?)
No we don't namespace. We write modular code and we use module loaders.
Example of a module loader would be require.js or browserify or seajs.
And an example module would be something like:
(function () {
var jQuery = require("jQuery");
var chart = require("chart");
...
define("moduleName", moduleObject);
})();
There is nothing stopping you adding another name to the class. For example.
org.ds = org.example.data.dataSource;
then you can call
org.ds.getDatasource();
instead of
org.example.data.dataSource.getDatasource();
but both will still work.
EDIT: You could also create other simpler functions that call it taking it out of the oo structure
var dataSource = function () { return org.example.data.dataSource.getDatasource(); };
Consider using something like RequireJS for organizing your modules.
Some excellent resources from Addy Osmani :
http://addyosmani.com/largescalejavascript/
http://addyosmani.com/blog/large-scale-jquery/
http://addyosmani.com/resources/essentialjsdesignpatterns/book/