Showing posts with label dijit. Show all posts
Showing posts with label dijit. Show all posts

Saturday, November 14, 2009

Disabling Tabs in a dijit.layout.TabContainer

I've started using tab containers a little more recently. Looking through the dojocampus articles and dojo api docs, it looks like there isn't an API for disabling clicks on a particular tab. I'm not sure why this is the case - perhaps it has something to do with accessibility (I've always had intentions of learning more about accessibility on the web, but I've never really had the time)

At any rate, here's a quick and simple solution to disabling tabs in a tab container:
dojo.forEach(dijit.byId("myTabContainer").tablist.getChildren(), dojo.hitch(this, function(item, index, array) {
dojo.attr(item, "disabled", true);
item.onClick = function() {};
}));

Unfortunately, there doesn't seem to be a simple way to re-enable these clicks. Also, it'd be really sweet if you could simply hide some of the tabs in a tab container, but it sounds like you can only add/remove them.

Tuesday, April 14, 2009

Connecting labels to inputs using dojo

When using dijit, you have to be careful not to include any id elements in your template HTML file. Otherwise, you can end up with elements with the same id in your document which can lead to a lot of head scratching. Having been bitten by the "multiple elements having the same id in my document" bug, I started stripping out all ids from my template files, replacing them with dojoAttachPoint attributes.

All was going fine and I wasn't getting mixed up in id clashing anymore. However, there was one drawback - my labels wouldn't work anymore. Code which previously looked like this:

<li>
<input id="simple" type="radio" dojoattachevent="onclick: simpleClicked"/>
<label for="simple">${statics.i18n.simple}</label>
</li>

no longer worked because it had changed to this:

<li>
<input dojoAttachPoint="simple" type="radio" dojoattachevent="onclick: simpleClicked"/>
<label for="simple">${statics.i18n.simple}
</li>

The label's for attribute expects to reference an id and not a dojoAttachPoint. Previously I was able to toggle the 'simple' checkbox input by clicking on the label. I always tend to click on labels instead of radio/checkboxes (mostly because they're bigger and easier to click), so I saw this move away from id-based inputs as a degradation in the usability of the web application.

So, I hacked together a piece of code which is invokable after every widget is set up and appended to the dom:

connectLabelsToInputs: function(query, widget) {
dojo.query(query, widget.domNode).forEach(function(item, index, array) {
if(widget[item.getAttributeNode("for").value] && (widget[item.getAttributeNode("for").value].type == "checkbox" || widget[item.getAttributeNode("for").value].type == "radio")) {
var attrs = widget[item.getAttributeNode("for").value].attributes;
for(var i = 0; i < attrs.length; i++) {
if(attrs[i].value.indexOf("onclick") != -1) {
dojo.addClass(item, "clickable");
dojo.connect(item, 'onclick', widget, dojo.trim(attrs[i].value.substring(attrs[i].value.indexOf(":") + 1, attrs[i].value.length)));
}
}
if(!dojo.hasClass(item, "clickable")) {
dojo.addClass(item, "clickable");
dojo.connect(item, "onclick", dojo.hitch(widget, function() {
widget[item.getAttributeNode("for").value].checked = widget[item.getAttributeNode("for").value].checked == false ? true : false;
}));
}
}
}, widget);
}

This code makes the assumption that you have a class called 'clickable' which looks something like this:

.clickable {
cursor: pointer;
}

So, if I know that a widget I just created contains labels and checkboxes or radio buttons, all I need to do is invoke:

common.connectLabelsToInputs("fieldset ol li label", this);

and my labels are clickable again.

Monday, March 2, 2009

Catching dijit's Dialog close event

I tend to use dijit Dialogs whenever I need the user to make a decision before proceeding with any other actions. They're especially useful for server error conditions and asking the user how they'd like to react to something like an API failure.

However, popping up dialogs can be annoying to users. I know I'm guilty of scanning dialog text and just hitting the 'x' button and ignoring the message. There are two ways you can prevent the user from doing this with dojo.

1. The most obvious solution: Hide the 'x' button. This is easily done with some simple CSS:


#myDialog .dijitDialogTitleBar .dijitDialogCloseIcon {
display:none;
}


The one drawback to this is that the user can hit the escape button and that'll close the dialog.

2. Attach the following two callbacks to your dialog:


this._userClosedDialogHandle = dojo.connect(dijit.byId("myDialog"), "hide", this, "_handleCloseDialog");
this._userClosedEscDialogHandle = dojo.connect(dijit.byId("myDialog").containerNode, 'onkeypress', function (evt) {
key = evt.keyCode;
if(key == dojo.keys.ESCAPE) {
this._handleCloseDialog();
}
});


The one caveat with this method is that you need to disconnect both handles in the _handleCloseDialog method. Otherwise, you'll find yourself in an infinite loop pretty quickly.