Search code examples
dojorequirejsamd

Swap an AMD Module Dependency in Dojo


Here is a widget class declared in a MyWidget.js module.

define(["dojo/Foo","myapp/Bar"], function(Foo, Bar) { return declare('MyWidget', [], {
   postCreate:function() {
      var bar = new Bar();
      bar.sayHello();
   }
})});

In this theoretical example, "myapp/Bar" is a class defined similarly by returning a declare call. Now let's assume that I have created "myapp/SpecialBar" by extending "myapp/Bar".

In another widget, I want to tell MyWidget to use "myapp/SpecialBar" instead of "myapp/Bar" like so:

require(["myapp/MyWidget","myapp/SpecialBar"], function(Foo, SpecialBar) { 
   //Now swap "myapp/Bar" module dependency of "myapp/MyWidget" to "myapp/SpecialBar"
   var myWidget = new MyWidget();
});

I know ways to do this. For example, I could add a Bar attribute to "myapp/MyWidget" and assign the value of the Bar module. This would allow me to instantiate like this: new MyWidget({ Bar:SpecialBar }). However, this seems like too much ceremony. Is there a clean way to just swap an AMD dependency without any special treatment to the module definition?


Solution

  • That is the clean way. You cannot change the modules that a widget/module depends on, well, you could map them, but that's done globally, so then it always maps to a specific module.

    If you could do that, you could break a lot of stuff as well, besides, such a feature does not exist in any language. Comparing require() with imports in Java and .NET, you will see a similar trend.

    The only way to change the module, is by changing the behavior/state of the module, which means by overriding properties or functions. When a module is "swappable" it's often used as a property, examples where this occur:

    • The dojo/dnd/Moveable class allows you to set a custom dojo/dnd/Mover through the mover property. In this case the constructor is added as a property to the Moveable (reference guide)
    • All widgets with a dropdown inherit from dijit/_HasDropDown, which adds the dropdown widget itself as a property to the parent widget