Login Register

Elegant way of bypassing "Tried to register widget but that id is already registered" ?

I have a ContentPane which contains several dijit widgets (created declaratively: <div id="23" dojoType="dijit.Dialog"/> for instance), each with its own id. The content of the ContentPane is initially provided in ajax-fashion by setting the href property.

Certain user-related events are likely to require an update of the content that should be displayed by the ContentPane. When one of those events is published, the ContentPane's refresh() method is triggered. That works mostly fine, except for the following exception:

Couldn't create widgets in contentPane from /myapp/contentPane.action
Error: Tried to register widget with id==23 but that id is already registered

I see why that would be happening. But is there an elegant way of avoiding it?
I am not infinitely bothered by this, since the changes in the ContentPane (requiring the refresh) don't relate to the already existing widgets. In other words, I don't mind not being able to re-create the already existing widgets.

Would it be better to destroy the whole ContentPane (with its children) and then re-create it from scratch (which is decidedly more involved than merely calling the refresh method on the object)? Is that too extreme?

Dialogs, tooltips and popups create this problem...

The ContentPane actually does destroy all the widgets that are inside it. However, Dialogs, tooltips and popups are created and attached to the body of the page they are on. So, the ContentPane doesn't clean those up unfortunately. (It seems like it should be it doesn't for me in 1.1)

The best thing to do is see if you can declare the dialog outside the content pane, in a place where it will only get created once.

The other thing you can do (and we had to do this in our app) is to register an unload handler with the content pane and make sure to destroy any dialogs, tooltips and popups that you create.

If you have a handle to the content pane, you can do...

contentPane.onUnload = function(){
dijit.byId( "23" ).destroyRecursive();
}

This will make sure the dialog gets cleaned up in the ContentPane refresh.

Of course, you can use dojo.connect or use the unLoad property on the html declaration of the ContentPane as well.

Hope this helps.

Thank you, it does help. The

Thank you, it does help.

The first option you mention (creating the dialogs outside the ContentPane) is a little unfortunate. The content of my ContentPane is generated by a JSP script that includes a loop over a list; one Dialog is created for each iteration of that loop. If the dialogs were created elsewhere (say, in dojo.addOnLoad()), I would have to mimick that loop at a point in the code where the loop information is not readily available... :(

Your second suggestion is involved but definitely feasible in our setup.

However, I just thought of a third option: what if instead of the declarative <div id="23" dojoType="dijit.Dialog"/>, I used the programmatic equivalent (within my JSP loop), but adding a conditional test? Something like:

<script>
if(dojo.byId("23")==null){
new dijit.Dialog({params}, /* code for creating a new DIV with id "23" */);
}
</script>

That would seem to do the job, wouldn't it?

That should work...

Those dialogs will hang out there, so that should work. If they are dialogs you really want to use dijit.byId instead of dojo.byId...

What is in each of these

What is in each of these dialogs? Using the premise a dijit.Dialog is modal, and currently only one can be shown on screen at a time, would it not be feasible to simply create one master dialog and manipulate the content in whatever handler is calling dialog.show() ?

I agree if....

You thought of that before you built all your code. (I am only speaking for my code as an example, I don't know what the original person who asked the question's answer would be) We have a large system with 64 different dialogs. If we had written a DialogManager or something like that that everyone used to create their dialogs and maniuplate them, we'd be onto something. As it stands now, these dialogs are created all over the place and manipulated all over the place. If we could do it again, we'd have...

1. A common dialog class that extends Dijit.Dialog and adds in our funcationality (we actually went back and did this which was great)
2. A DialogManager class that everyone calls to show/hide/maniuplate the dialogs. This would allow us to use a singleton dialog and manipulate the contents
3. In the dialogManager decide to lazy load some of our dialogs only when needed.

In fact, this would be a great utility to add to dojo that would make enterprise level architectures easier to maintain...

The things we put in our subclass of dijit.Dialog are:

1. The ability to have dialogs on top of dialogs. The dijit.Dialog doesn't work like this and has lots of tabbing problems and display problems with dialogs on top of dialogs. We added this ability.
2. We added a MVC architecture to dijit.Dialog. You have to pass in a controller class and a set of actions. These actions are placed at the bottom of the dialog (our look and feel) and the controller class is wired into these actions. When the actions are called, the controller gets notified and maniuplates the dialog. This worked out really well. If anyone wants to control a dialog, they can simply do a dijit.byId( 'myDialog' ).controller.whateverCall on it.

Thanks both for those extra

Thanks both for those extra replies. Funny thing is, just after posting my previous post, I started wondering why we needed all those dialogs... (Frankly, unless I'm overlooking something, they differ only in their href property.) So both your posts are perfect food for my intuition of the problem!

As far as using dojo dialogs, this really is our first attempt. So everything is quite new. Therefore most everything is still adaptable!

As an addendum, I thought it

As an addendum, I thought it might be worth quoting a reference to the comment at the bottom of this page concerning the setContent method of the ContentPane object.