How to dispatch events globally and inside requireJS objects? - javascript

I am looking for a way to dispatch events globally and inside requireJS modules using javascript or jquery.
I would like to be able to say within my js files:
dispatchEvent(myCustomEventWithSomeData);
and then in some other part of the application add a listener like so:
addEventListener(“type Of Event”, executeThisFunction);
is this possible using jquery? Or any other means? And will a potential solution work within requireJS modules which are not global javascript objects?
Also, How can I create an event that bubbles. So that if I want an event to execute only in a specific section of the code it is not dispatched globally?

Yes, this is something I typically setup very early within my own applications. Now, how you deal with your events is going to be very dependent on what library or techniques you decide to use, but the core concepts will remain the same.
Personally, I think PostalJS is the cock of the walk, so I'm going to use that as an example here. I'm not going to include too much code because it would be mostly ceremony and boilerplate, but I hope you'll get the idea.
One, you'll want to create something like a global App object for your events to rest on. Overall this is a good practice when modularizing your JS code - you'll want something which acts as a broker between modules. It can be very plain and basic:
define(function() {
var App = {};
return App;
});
Now, this module should be loaded into something which begins to populate it. You can get away with not doing this, for a while, but I find eventually circular dependencies tend you bite you in the ass. So I recommend including this in something akin to your "main" module. From there, include your event system and add it to App.
define(['app', 'events'], function(App, Events) {
App.events = new Events();
});
Now you have a nice, lightweight object you can include in other modules which shares the same Events object. So lets say you have a sidebar:
define(['app'], function(App) {
// User has clicked the sidebar
App.events.publish('sidebar.clicked'); //
});
And, oh I don't know, perhaps clicking the sidebar makes a dinosaur appear, so in your dinosaur module, you'd listen/subscribe by doing the following:
define(['app'], function(App) {
App.events.subscribe('sidebar.clicked', showDinosaur);
});
Having a lightweight object you can share between modules I've found is key to a successful modularized JS architecture. I use this in my own projects as a global object store, a container for my WebSocket messaging layer, and other things I don't want to need to explicitly include individually in each module.

Related

JS: Best practice on global "window" object

Following a rapid-prototyping approach, I am developing an application in Marionette.js/backbone.js and heavily used the window-object to bind collections and views to the global stack (e.g. window.app.data, window.app.views).
Of course, it is always better (smoother!) to encapsulate objects in a single class and pass them as parameters where needed. However, this has some limitations when an app and its potential use-cases become really big. And as the data I deal with comes from an API and therefore would be anyway accessible to anybody interested, does that justify storing data in the window-object? Or are there other best-practices in ES6 (or especially Marionette.js) to achieve the same results, but in a more private manner?!
I already go into details about a simple namespacing pattern in JavaScript in another answer. You seem to be already close to this with window.app.data etc.
But it looks like you have a lot of misconceptions about how JavaScript works.
a namespace-based solution that integrates nicely with Browserify/AMD-modules
Then why not use RequireJS? Browserify? or Webpack? There's nothing that a global ridden spaghetti code can do that a modular approach can't do better.
such would be read-only
No. While not impossible to set an object property to read-only, you must explicitly do it with something like Object.seal or Object.freeze.
I do not want to attach objects to the namespace, but actual instances
JavaScript do not have "namespaces" as part of the language, it's just a pattern to scope all your code within literal objects (key-value).
You can put whatever you'd like.
const MyNamespace = {
MyType: Backbone.Model.extend({ /*...*/ }),
instance: new Backbone.Model(),
anyValue: "some important string",
};
Ideally, you would define the namespace within an IIFE to avoid leaking any variable to the global scope.
const app = app || {};
app.MyModel = (function(app){
return Backbone.Model.extend({
// ...
});
})(app);
[...] data I deal with comes from an API and therefore would be anyway accessible to anybody interested
Even if the data is contained within a module that do not leak to the global scope, anybody can access the data. That's how JavaScript works, it's in the user's browser, he can do whatever he wants with the code and the data.
does that justify storing data in the window-object?
No.
Or are there other best-practices in ES6
ES6 has nothing to do with the architecture and patterns you take for your app.
but in a more private manner?!
Like I said earlier, privacy in JavaScript can't be expected.
[encapsulate objects in a single class and pass them as parameters where needed] has some limitations when an app and its potential use-cases become really big.
That's just incorrect. It's the other way around. Software patterns exist solely to help alleviate any limitations that arise as a project grows in scope.
There are multiple patterns you can use that will help deal with the complexity of a bigger app, like:
Modular approach with components
Dependency injection
Service containers
Factories
Events
etc.
I didn't read specifically this book, but JavaScript Design Patterns seems to be a good way to learn more and it demonstrates specific implementations of software patterns in JS.

Creating Cycle.js reusable modules

Let's imagine, in a OO world, I want to build a Torrent object which listens to the network and lets me interact with it. It would inherit an EventEmitter and would look something like this:
var torrent = new Torrent(opts)
torrent.on('ready', cb) // add torrent to the UI
torrent.on('metadata', cb) // update data in the UI
and I can also make it do things:
torrent.stop()
torrent.resume()
Then of course if I want to do delete the torrent from memory I can call torrent.destroy().
The cool thing about this OO approach is that I can easily package this functionality in its own npm module, test the hell out of, and give users a nice clean reusable API.
My question is, how do I achieve this with Cycle.js apps?
If I create a driver it's unclear how I would go about creating many torrents and having their own independent listeners. Also consider I'd like to package functionality in a way that others get to easily reuse it in other Cycle.js apps.
It seems to me that you are trying to solve a problem thinking about it as you would write "imperative code".
I think creating Torrent instances with their own listeners is not something you should be using in cycle components.
I would go about it differently - creating Torrent module and figuring out what would be its sources and sinks. If this module should be reusable and published, you can create it as a function that would receive streams as arguments. Maybe something similar to TodoMVC Task component (which is then used in its parent component).
Since this module can be created as a pure function, testing it should be at least just as easy.
This implementation of course depends on your requirements but communication with the module would then be done only with streams and since it would be declarative there would be no need for methods like stop() and destroyed() which you would call from elsewhere.
How do I test it?
In cycle.js you'd write a component with intent model and view functions.
You'd test intent(), for given input Streams, produces Streams of actions that you want. For models, you'd test that given http and action streams, you get the state you want, and for view, you test that given a state you get the VDom you want.
One tricky bit with cycle.js is that since it passes functions around, normal JavaScript objects that use the 'this' keyword are not worth the trouble due to 'this' context problems. If you are working with cycle.js and you think you might write a JS class for use with Isolate, Onionify, or Collections most likely, you are going in the wrong direction. See MDN docs about 'this'
how I would go about creating many torrents
The Cycle.js people have several ways to deal with groups of things like this.
This ticket describes some things that might work for that:
Wrap subapp in Web Component
Stanga and similars.
Cycle Collections
Cycle Onionify

Javascript module pattern - page bindings

I am working out how to make my code more manageable and readable in a large application. I've read many posts and blogs about the module pattern and module revealing pattern but one thing which always seems to be missing is pages and bindings.
People show examples of modules, but I haven't found any good real work examples.
For example, lets say I have a page, which has a calculator on it.
All the examples I've seen show the calculator and how to create a module for that, but what I am looking for is how to get the page and the calculator to talk to each other.
Do people create a module for every page eg; CalculatorPage, do they have a binding or init method, and inside there they setup the calculator module? Here is some (invalid js) to sort of get the picture.
var Calculator
settings: { resultElement },
add (x, y) function to add and set resultElement to
subtract (x,y) function to subtract and set resultElement to
then
var CalculatorPage
....
bind (or init) = function() {
this.calculator = new Calculator(.results);
$('.add-button').on('click', this.calculator.add($('.x-field'.val(), $('.y-field').val());
$('.subtract-button').on('click', this.calculator.subtract($('.x-field'.val(), $('.y-field').
Should each page have a module?
A nicer way to deal with bindings?
If someone had some better examples of modules in pages / real world applications I would really appreciate it..
I guess the question here is around the semantics of 'page'. If only a JS calculator is displayed then sure you could justifiably name the module 'calculatorPage'. For me though the word 'page' refers to the DOM. Personally I wouldn't couple the naming to the scenario that this must be the only thing on the page unless I felt sure that was the case and wanted to highlight it.
Setting up the bindings is a question of design. If you are using jQuery alone then you would want to set event handlers inside a DOM ready callback. If you want more of an MV* structure then you could use a framework like AngularJS or Backbone etc. which have their own abstractions. Basically though it comes down to the same thing, setting event listeners once the DOM is ready.

Durandal (knockout) app with multilanguage support

I am building multilingual support for the app I'm working on. After doing some research and reading SO (internationalization best practice) I am trying to integrate that in a 'framework-friendly' way.
What I have done at the moment is following:
Created .resource modules formatted like so:
resources.en-US.js
define(function () {
return {
helloWorlLabelText: "Hello world!"
}
});
On the app.start I get the resource module with requirejs and assign all data to app.resources. Inside of each module specific resource is assigned to observables and bonded with text binding to labels and other text related things. Like so:
define(function (require) {
var app = require('durandal/app'),
router = require('durandal/plugins/router')
};
return{
helloWorldLabelText: ko.observable(app.resources.helloWorldLabelText),
canDeactivate: function () {
}
}
});
On the view:
<label for="hello-world" data-bind="text: helloWorldLabelText"></label>
The resources are swapped just by assigning new module to app.resources.
Now the problem is when the language is changed and some of the views have been already rendered, the values of previous language are still there. So I ended up reassigning observables inside of activate method. Also tried wrapping app.resources into observable, but that didn't work either.
I don't think I ended up with the most clean way and maybe anybody else had some other way that could share. Thanks.
For those who are still confused about best practices, those who feel that something is lacking, or those who are simply curious about how to implement things in a better way with regard to Durandal, Knockout, RequireJS, and client-side web applications in general, here is an attempt at a more useful overview of what's possible.
This is certainly not complete, but hopefully this can expand some minds a little bit.
First, Nov 2014 update
I see this answer keeps being upvoted regularly even a year later. I hesitated to update it multiple times as I further developed our particular solution (integrating i18next to Durandal/AMD/Knockout). However, we eventually dropped the dependent project because of internal difficulties and "concerns" regarding the future of Durandal and other parts of our stack. Hence, this little integration work was canceled as well.
That being said, I hopefully distinguished generally applicable remarks from specific remarks below well enough, so I think they keep offering useful (perhaps even well needed) perspectives on the matters.
If you're still looking to play with Durandal, Knockout, AMD and an arbitrary localization library (there are some new players to evaluate, by the way), I've added a couple of notes from my later experiences at the end.
On the singleton pattern
One problem with the singleton pattern here is that it's hard to configure per-view; indeed there are other parameters to the translations than their locale (counts for plural forms, context, variables, gender) and these may themselves be specific to certain contexts (e.g. views/view models).
By the way it's important that you don't do this yourself and instead rely on a localization library/framework (it can get really complex). There are many questions on SO regarding these projects.
You can still use a singleton, but either way you're only halfway there.
On knockout binding handlers
One solution, explored by zewa666 in another answer, is to create a KO binding handler. One could imagine this handler taking these parameters from the view, then using any localization library as backend. More often than not, you need to change these parameters programmatically in the viewmodel (or elsewhere), which means you still need to expose a JS API.
If you're exposing such an API anyway, then you may use it to populate your view model and skip the binding handlers altogether. However, they're still a nice shortcut for those strings that can be configured from the view directly. Providing both methods is a good thing, but you probably can't do without the JS API.
Current Javascript APIs, document reloading
Most localization libraries and frameworks are pretty old-school, and many of them expect you to reload the entire page whenever the user changes the locale, sometimes even when translation parameters change, for various reasons. Don't do it, it goes against everything a client-side web application stands for. (SPA seems to be the cool term for it these days.)
The main reason is that otherwise you would need to track each DOM element that you need to retranslate every time the locale changes, and which elements to retranslate every time any of their parameters change. This is very tedious to do manually.
Fortunately, that's exactly what data binders like knockout make very easy to do. Indeed, the problem I just stated should remind you of what KO computed observables and KO data-bind attributes attempt to solve.
On the RequireJS i18n plugin
The plugin both uses the singleton pattern and expects you to reload the document. No-go for use with Durandal.
You can, but it's not efficient, and you may or may not uselessly run into problems depending on how complex your application state is.
Integration of knockout in localization libraries
Ideally, localization libraries would support knockout observables so that whenever you pass them an observable string to translate with observable parameters, the library gives you an observable translation back. Intuitively, every time the locale, the string, or the parameters change, the library modifies the observable translation, and should they be bound to a view (or anything else), the view (or whatever else) is dynamically updated without requiring you to do anything explicitly.
If your localization library is extensible enough, you may write a plugin for it, or ask the developers to implement this feature, or wait for more modern libraries to appear.
I don't know of any right now, but my knowledge of the JS ecosystem is pretty limited. Please do contribute to this answer if you can.
Real world solutions for today's software
Most current APIs are pretty straightforward; take i18next for example. Its t (translate) method takes a key for the string and an object containing the parameters. With a tiny bit of cleverness, you can get away with it without extending it, using only glue code.
translate module
define(function (require) {
var ko = require('knockout');
var i18next = require('i18next');
var locale = require('locale');
return function (key, opts) {
return ko.computed(function () {
locale();
var unwrapped = {};
if (opts) {
for (var optName in opts) {
if (opts.hasOwnProperty(optName)) {
var opt = opts[optName];
unwrapped[optName] = ko.isObservable(opt) ? opt() : opt;
}
}
}
return i18next.t(key, unwrapped);
});
}
});
locale module
define(function (require) { return require('knockout').observable('en'); });
The translate module is a translation function that supports observable arguments and returns an observable (as per our requirements), and essentially wraps the i18next.t call.
The locale module is an observable object containing the current locale used globally throughout the application. We define the default value (English) here, you may of course retrieve it from the browser API, local storage, cookies, the URI, or any other mechanism.
i18next-specific note: AFAIK, the i18next.t API doesn't have the ability to take a specific locale per translation: it always uses the globally configured locale. Because of this, we must change this global setting by other means (see below) and place a dummy read to the locale observable in order to force knockout to add it as a dependency to the computed observable. Without it, the strings wouldn't be retranslated if we change the locale observable.
It would be better to be able to explicitly define dependencies for knockout computed observables by other means, but I don't know that knockout currently provides such an API either; see the relevant documentation. I also tried using an explicit subscription mechanism, but that wasn't satisfactory since I don't think it's currently possible to trigger a computed to re-run explicitly without changing one of its dependencies. If you drop the computed and use only manual subscription, you end up rewriting knockout itself (try it!), so I prefer to compromise with a computed observable and a dummy read. However bizarre that looks, it might just be the most elegant solution here. Don't forget to warn about the dragons in a comment.
The function is somewhat basic in that it only scans the first-level properties of the options object to determine if they are observable and if so unwraps them (no support for nested objects or arrays). Depending on the localization library you're using, it will make sense to unwrap certain options and not others. Hence, doing it properly would require you to mimic the underlying API in your wrapper.
I'm including this as a side note only because I haven't tested it, but you may want to use the knockout mapping plugin and its toJS method to unwrap your object, which looks like it might be a one-liner.
Here is how you can initialize i18next (most other libraries have a similar setup procedure), for example from your RequireJS data-main script (usually main.js) or your shell view model if you have one:
var ko = require('knockout');
var i18next = require('i18next');
var locale = require('locale');
i18next.init({
lng: locale(),
getAsync: false,
resGetPath: 'app/locale/__ns__-__lng__.json',
});
locale.subscribe(function (value) {
i18next.setLng(value, function () {});
});
This is where we change the global locale setting of the library when our locale observable changes. Usually, you'll bind the observable to a language selector; see the relevant documentation.
i18next-specific note: If you want to load the resources asynchronously, you will run in a little bit of trouble due to the asynchronous aspect of Durandal applications; indeed I don't see an obvious way to wrap the rest of the view models setup code in a callback to init, as it's outside of our control. Hence, translations will be called before initialization is finished. You can fix this by manually tracking whether the library is initialized, for example by setting a variable in the init callback (argument omitted here). I tested this and it works fine. For simplicity here though, resources are loaded synchronously.
i18next-specific note: The empty callback to setLng is an artifact from its old-school nature; the library expects you to always start retranslating strings after changing the language (most likely by scanning the DOM with jQuery) and hence the argument is required. In our case, everything is updated automatically, we don't have to do anything.
Finally, here's an example of how to use the translate function:
var _ = require('translate');
var n_foo = ko.observable(42);
var greeting = _('greeting');
var foo = _('foo', { count: n_foo });
You can expose these variables in your view models, they are simple knockout computed observables. Now, every time you change the locale or the parameters of a translation, the string will be retranslated. Since it's observable, all observers (e.g. your views) will be notified and updated.
var locale = require('locale');
locale('en_US');
n_foo(1);
...
No document reload necessary. No need to explicitly call the translate function anywhere. It just works.
Integration of localization libraries in knockout
You may attempt to make knockout plugins and extenders to add support for localization libraries (besides custom binding handlers), however I haven't explored the idea, so the value of this design is unknown to me. Again, feel free to contribute to this answer.
On Ecmascript 5 accessors
Since these accessors are carried with the objects properties everywhere they go, I suspect something like the knockout-es5 plugin or the Durandal observable plugin may be used to transparently pass observables to APIs that don't support knockout. However, you'd still need to wrap the call in a computed observable, so I'm not sure how much farther that gets us.
Yet again, this is not something I looked at a lot, contributions welcome.
On Knockout extenders
You can potentially leverage KO extenders to augment normal observables to translate them on the fly. While this sounds good in theory, I don't think it would actually serve any kind of purpose; you would still need to track every option you pass to the extender, most likely by manually subscribing to each of them and updating the target by calling the wrapped translation function.
If anything, that's merely an alternative syntax, not an alternative approach.
Conclusion
It feels like there is still a lot lacking, but with a 21-lines module I was able to add support for an arbitrary localization library to a standard Durandal application. For an initial time investment, I guess it could be worse. The most difficult part is figuring it out, and I hope I've done a decent job at accelerating that process for you.
In fact, while doing it right may sound a little complicated (well, what I believe is the right way anyway), I'm pretty confident that techniques like these make things globally simpler, at least in comparison to all the trouble you'd get from trying to rebuild state consistently after a document reload or to manually tracking all translated strings without Knockout. Also, it is definitely more efficient (UX can't be smoother): only the strings that need to be retranslated are retranslated and only when necessary.
Nov 2014 notes
After writing this post, we merged the i18next initialization code and the code from the translate module in a single AMD module. This module had an interface that was intended to mimick the rest of the interface of the stock i18next AMD module (though we never got past the translate function), so that the "KO-ification" of the library would be transparent to the applications (except for the fact that it now recognized KO observables and took the locale observable singleton in its configuration, of course). We even managed to reuse the same "i18next" AMD module name with some require.js paths trickery.
So, if you still want to do this integration work, you may rest assured that this is possible, and eventually it seemed like the most sensible solution to us. Keeping the locale observable in a singleton module also turned out to be a good decision.
As for the translation function itself, unwrapping observables using the stock ko.toJS function was indeed far easier.
i18next.js (Knockout integration wrapper)
define(function (require) {
'use strict';
var ko = require('knockout');
var i18next = require('i18next-actual');
var locale = require('locale');
var namespaces = require('tran-namespaces');
var Mutex = require('komutex');
var mutex = new Mutex();
mutex.lock(function (unlock) {
i18next.init({
lng: locale(),
getAsync: true,
fallbackLng: 'en',
resGetPath: 'app/locale/__lng__/__ns__.json',
ns: {
namespaces: namespaces,
defaultNs: namespaces && namespaces[0],
},
}, unlock);
});
locale.subscribe(function (value) {
mutex.lock(function (unlock) {
i18next.setLng(value, unlock);
});
});
var origFn = i18next.t;
i18next.t = i18next.translate = function (key, opts) {
return ko.computed(function () {
return mutex.tryLockAuto(function () {
locale();
return origFn(key, opts && ko.toJS(opts));
});
});
};
return i18next;
});
require.js path trickery (OK, not that tricky)
requirejs.config({
paths: {
'i18next-actual': 'path/to/real/i18next.amd-x.y.z',
'i18next': 'path/to/wrapper/above',
}
});
The locale module is the same singleton presented above, the tran-namespaces module is another singleton that contains the list of i18next namespaces. These singletons are extremely handy not only because they provide a very declarative way of configuring these things, but also because it allows the i18next wrapper (this module) to be entirely self-initialized. In other words, user modules that require it will never have to call init.
Now, initialization takes time (might need to fetch some translation files), and as I already mentioned a year ago, we actually used the async interface (getAsync: true). This means that a user module that calls translate might in fact not get the translation directly (if it asks for a translation before initialization is finished, or when switching locales). Remember, in our implementation user modules can just start calling i18next.t immediately without waiting for a signal from the init callback explicitly; they don't have to call it, and thus we don't even provide a wrapper for this function in our module.
How is this possible? Well, to keep track of all this, we use a "Mutex" object that merely holds a boolean observable. Whenever that mutex is "locked", it means we're initializing or changing locales, and translations shouldn't go through. The state of that mutex is automatically tracked in the translate function by the KO computed observable function that represents the (future) translation and will thus be re-executed automatically (thanks to the magic of KO) when it changes to "unlocked", whereupon the real translate function can retry and do its work.
It's probably more difficult to explain than it is to actually understand (as you can see, the code above is not overly long), feel free to ask for clarifications.
Usage is very easy though; just var i18next = require('i18next') in any module of your application, then call i18next.t away at any time. Just like the initial translate function you may pass observable as arguments (which has the effect of retranslating that particular string automatically every time such an argument is changed) and it will return an observable string. In fact, the function doesn't use this, so you may safely assign it to a convenient variable: var _ = i18next.t.
By now you might be looking up komutex on your favorite search engine. Well, unless somebody had the same idea, you won't find anything, and I don't intend to publish that code as it is (I couldn't do that without losing all my credibility ;)). The explanation above should contain all you need to know to implement the same kind of thing without this module, though it clutters the code with concerns I'm personally inclined to extract in dedicated components as I did here. Toward the end, we weren't even 100% sure that the mutex abstraction was the right one, so even though it might look neat and simple, I advise that you put some thoughts into how to extract that code (or simply on whether to extract it or not).
More generally, I'd also advise you to seek other accounts of such integration work, as its unclear whether these ideas will age well (a year later, I still believe this "reactive" approach to localization/translation is absolutely the right one, but that's just me). Maybe you'll even find more modern libraries that do what you need them to do out of the box.
In any case, it's highly unlikely that I'll revisit this post again. Again, I hope this little(!) update is as useful as the initial post seems to be.
Have fun!
I was quite inspired by the answers in SO regarding this topic, so I came up with my own implementation of a i18n module + binding for Knockout/Durandal.
Take a look at my github repo
The choice for yet another i18n module was that I prefer storing translations in databases (which ever type required per project) instead of files. With that implementation you simply have a backend which has to reply with a JSON object containing all your translations in a key-value manner.
#RainerAtSpirit
Good tip with the singleton class was very helpful for the module
You might consider having one i18n module that returns a singleton with all required observables. In addition a init function that takes an i18n object to initialize/update them.
define(function (require) {
var app = require('durandal/app'),
i18n = require('i18n'),
router = require('durandal/plugins/router')
};
return{
canDeactivate: function () {
}
}
});
On the view:
<label for="hello-world" data-bind="text: i18n.helloWorldLabelText"></label>
Here is an example repo made using i18next, Knockout.Punches, and Knockout 3 with Durandal:
https://github.com/bestguy/knockout3-durandal-i18n
This allows for Handlebars/Angular-style embeds of localized text via an i18n text filter backed by i18next:
<p>
{{ 'home.label' | i18n }}
</p>
also supports attribute embeds:
<h2 title="{{ 'home.title' | i18n }}">
{{ 'home.label' | i18n }}
</h2>
And also lets you pass parameters:
<h2>
{{ 'home.welcome' | i18n:name }}
<!-- Passing the 'name' observable, will be embedded in text string -->
</h2>
JSON example:
English (en):
{
"home": {
"label": "Home Page",
"title": "Type your name…"
"welcome": "Hello {{0}}!",
}
}
Chinese (zh):
{
"home": {
"label": "家",
"title": "输入你的名字……",
"welcome": "{{0}}您好!",
}
}

dojo style developement

I'm having difficulty wrapping my head around dojo style of coding. The reason I am drawn to it is because of its class style coding. I have done AS developement and some java so it makes sense to me to be drawn to it. I have done some jquery style DOM work but I require a more framework based setup for a project I'm starting.
My question is should I be creating everything as classes with the declare and then requiring them when needed. Or could I write closure type functions with namespaces just like regular javascript modules. I'm confused.
Example I want to have a group of methods that take care of managing data. Then I want to have another collection of methods that handle special ajax calls. Would I create a class with declare for each of these groups of methods, in separate js files. Then in my app.js which is my application class where I'm handling the initialization of all my classes, would I require both those classes before dojo.ready(){}
then once the ready method is called I can start to use those classes.
Can someone set me straight here before I dojo out.
Does require make a load request for that js file and if so do you always have to use the ready method. If so is it best to require a bunch of your classes up front at the start of your application initialization.
Technically for what you're wanting to do, you could go either way - using dojo.declare or simply creating an object with function members. I'd be inclined to do the latter, since dojo.declare's elaborate inheritance considerations will be total overkill that you won't be making use of in this case, and it doesn't generally make sense to be instantiating anything when you just want to group some utility methods together.
For modules that simply group utility methods together, I'd be inclined to do something along these lines:
dojo.provide('my.utils');
my.utils = {
doSomething: function(){
/* do something... */
},
doSomethingElse: function(){
/* do something else... */
}
};
RE loading, if I'm reading you right, then yes, you have the right idea. In your web page, you would dojo.require(...) the modules your page requires (perhaps just one, if you have all your other dependencies further required within it). Then, any code in the page that expects these modules to be loaded should be within a function passed to dojo.ready. This ensures that even in cases where modules are asynchronously loaded (i.e. using the cross-domain loader), your code will still work. dojo.ready specifically waits for (1) the DOM to be ready and (2) all dojo.required modules up to that point to be loaded.
Note that within modules themselves, you do NOT need to enclose code in dojo.ready for the sake of waiting for dojo.required modules to load; this is figured out by the loader automatically. (However, if some logic in your module needs to wait for the DOM to be ready, you would still rely upon dojo.ready.)
I've written more about dojo.ready in the past; maybe it'll be a helpful read: http://kennethfranqueiro.com/2010/08/dojo-required-reading/

Categories

Resources