Recommended pattern for setting initialization parameters to custom widget - dojo

I'm creating my own template based widgets and I was trying to pass some objects through the constructor on creation like this
var widget = new myWidget(obj1, obj2, obj3);
where my constructor of the widget looks like
constructor: function(param1, param2, param3)
However I was getting some errors and found they were due to _WidgetBase functionality (specifically the create method) that is expecting something special in the first and second parameters.
create: function(params, srcNodeRef)
So in order to avoid my parameters nuking the params, and srcNodeRef that was expected in position one and two, I had to move my parameters to after the second position like this
constructor: function (params, srcNodeRef, myParam1, myparam2, myParam3)
But naturally this is not an expected way to solve this compared to the usual way to instantiate objects in normal object oriented languages (ex. c#)
My question is, is there a recommended pattern for passing initialization parameters to a custom widgets constructor, that avoids this issue of having to remember the first and second parameter positions are reserved?
NOTE:
An important note is that whatever parameters I send into the widget, must be acted on or made available before postCreate executes, just like it is if I passed them to the constructor.

Actually, there is a "dojo" way to pass parameters into your widget:
var widget = new myWidget({obj1: obj1, obj2: obj2});
In instance of your widget these object will refer to
this.obj1, this.obj2. You don't have to override constructor.
Some comments from dojo source of _WidgetBase on this topic:
//////////// INITIALIZATION METHODS ///////////////////////////////////////
/*=====
constructor: function(params, srcNodeRef){
// summary:
// Create the widget.
// params: Object|null
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
// and functions, typically callbacks like onClick.
// The hash can contain any of the widget's properties, excluding read-only properties.
// srcNodeRef: DOMNode|String?
// If a srcNodeRef (DOM node) is specified:
//
// - use srcNodeRef.innerHTML as my contents
// - if this is a behavioral widget then apply behavior to that srcNodeRef
// - otherwise, replace srcNodeRef with my generated DOM tree
},
=====*/

I +1'd Kirill's answer as that's the easiest. But from the other comments it sounds like you might need to massage the input or initialize other variables based on the input.
If so, take a look at the postMixinProperties lifecycle method and override it in your widget. If your widget is templated and the template expects the massaged data, you'll need this. In here you refer to your properties with this as you expect.
postMixInProperties: function(){
// summary:
// Called after the parameters to the widget have been read-in,
// but before the widget template is instantiated. Especially
// useful to set properties that are referenced in the widget
// template.
// tags:
// protected
},
Don't forget to invoke this.inherited(arguments); in here as you should in all of the dijit lifecycle methods.
Defining setters for you properties is another way to massage these properties. You'll want this if a template will use these properties. Example of a setter from the Writing Widgets page. So here 'open' would be the name of the parameter as passed to the contructor, or in a widget template.
_setOpenAttr: function(/*Boolean*/ open){
this._set("open", open);
domStyle.set(this.domNode, "display", open ? "block" : "none");
}

Related

What is difference between global methods and instance methods in Vue.js?

Vue.js official docs about plugins describes global methods and properties and Vue instance methods.
// 1. add global method or property
Vue.myGlobalMethod = function () {
// some logic ...
}
// 4. add an instance method
Vue.prototype.$myMethod = function (methodOptions) {
// some logic ...
}
But it isn't clear which of this approach is better fit to define global functionality? Can someone explain difference or indicate some resource about different use cases of this two approaches?
An instance method will have an instance (this) to be called from an operate on. A global-on-Vue function would have Vue itself as its this, which probably means you wouldn't want to use this in it.
So: instance method if it should operate on an instance, global function if it is some sort of utility that doesn't operate on a Vue instance.

mimicking MVC DisplayExtensions methods (fun and confusion with lambdas)

I'm trying to develop my own editable data grid for MVC in a fluent interface usable in a View. My question is really about using lambdas, not about data grids, but the context might help for understanding my question. Anyway, I have some code that looks like this:
#model IEnumerable<AdamOneilSoftware.Models.Something>
#{
var firstItem = Model.FirstOrDefault();
}
#(Html.DataGrid(Model)
.CssClass("data")
.TextBox(model => firstItem.Text)
.TextBox(model => firstItem.Position)
.Render())
This much compiles okay. You can see that I want to use lambdas to setting up columns of my data grid. The thing I don't understand is how to do anything with those lambdas in my data grid class. I have surmised that I need to compile/invoke the expression, but I'm stuck on the Invoke part. Here's what I have:
public DataGridBuilder<TModel> TextBox<TValue>(Expression<Func<TModel, TValue>> expression)
{
var del = expression.Compile();
// invoke the delegate?
var result = del.Invoke(); // but this expects a TModel argument
return this;
}
The Invoke call expects a TModel argument (according to the Func declaration -- I understand that). But this doesn't work--and rightly so:
var result = del.Invoke(TModel);
How do I form the TModel argument in the Invoke call? Or am I heading the wrong direction completely? The goal is to do something like what the DisplayFor and EditorFor methods do--render some HTML with some awareness of the target property's metadata (DataFormatString, Display label, and so on).
You need to get the view's Model instance to pass as the parameter.
You can find that in Html.ViewData.Model.

Ext.Create returning classes that are already instantiated

I'm making use of the extjs class objects through Ext.define (... and Ext.create (.... When I have multiple instances of classes stored within another class I'm seeing some strange behavior: the classes are not unique and it looks like Ext.create is returning my previous instantiation.
Checkout the JSFiddle of my problem here. Make sure you view the console log in your browser to see the output and weirdness.
You're setting an array in Ext.define. That implies that you're setting into the object's prototype which is shared among all instances of a class. Therefore this is not an unexpected behaviour. Create the array within the constructor, like here:
Ext.define ('Sunglasses', {
brand : '',
constructor : function (args) {
this.lenses = [];
this.brand = args.brand;
},
addLenses : function (lenses) {
this.lenses.push (lenses);
}
});

How can you iterate over an object (associative array) in Dojo?

Does Dojo have a method similar to jQuery's each() that allows you to pass an object to iterate over? jQuery.each() allows you to pass either an array or an object. In the latter case, the callback function receives both a key and the value. Is there something that allows you to do this in Dojo?
Looks like you are looking for dojox.lang.functional.object.forIn.
There's no actual documentation page in dojo reference, only a small example in article Functional fun in JavaScript with Dojo:
Module dojox.lang.functional.object defines important object helpers:
df.forIn(object, callback[, thisObject])
If you have something against using that module you can also easily make your own variant:
function objEach(obj, f, scope){
for(var key in obj){
if(obj.hasOwnProperty(key)){
f.call(scope, obj[key], key);
}
}
}
For arrays there is already dojo.forEach() in the base library.

Using dojo.require() without dojo.declare()

I'm quite confused from Dojo's documentation. How can I use dojo.require() without actually using dojo.declare()? The reason I don't want to use dojo.declare() is that it exposes declared class as global variable.
Right now my code looks like this:
HTML file:
dojo.require('module.test');
Module/test.js:
dojo.provide('module.test');
function test() {
return 'found me';
}
I just can't get Dojo to return test() method anywhere. What's the correct pattern for using dojo.require() without declaring?
I think you are confusing dojo.provide/dojo.require with dojo.declare. They are completely different concepts.
Things that relate to modules
dojo.provide defines a module.
dojo.require requires that a module be defined before running any code later.
Things that relate to JavaScript classes
dojo.declare is something completely different. It declares a Dojo-style class.
You can have multiple classes in a module, or several modules making up one class. In general, modules !== classes and they are completely unrelated concepts.
dojo.provide defines the code module so that the loader will see it and creates an object from the global namespace by that name. From that point, you can anchor code directly to that global variable, e.g.
Module/test.js:
dojo.provide('module.test');
module.test.myFunc = function() {
return 'found me';
}
There are various patterns you can use, such as creating a closure and hiding "private" function implementations, exposing them via the global reference you created in dojo.provide:
dojo.provide('module.test');
function(){
// closure to keep top-level definitions out of the global scope
var myString = 'found me';
function privateHelper() {
return myString;
}
module.test.myFunc = function() {
return privateHelper();
}
}();
Note that the above simply puts methods directly on an object. Now, there's also dojo.declare, which is often used with dojo.provide to create an object with prototypes and mixins so that you can create instances with the 'new' keyword with some inheritance, even simulating multiple inheritance vai mixins. This sort of OO abstraction is often overused. It does approximate the patterns required by languages like Java, so some folks are used to declaring objects for everything.
Note that as of Dojo 1.5, dojo.declare returns an object and does not necessarily need to declare anything in the global scope.
Here's a pattern I sometimes use (this would be the contents of test.js):
(function() {
var thisModule = dojo.provide("module.test");
dojo.mixin(thisModule, {
test: function() {
return "found me";
}
});
})();
Now you can reference module.test.test() in your HTML page.