views:

26

answers:

1

I have this bit of code. It is used to update the form after a select element changes. onChange an "ajax" call is made and this bit of code takes care of the response.

The first time everything works as expected. However it the dojo.parser.parse fails to return about 50% of the time.

At first it looked like this:

var targetNode = dojo.byId(node);
targetNode.innerHTML = data;
dojo.parser.parse(targetNode);

Then I read something about the objects existing. So I thought that maybe destroying them would help:

if(dojo.byId(node)) dojo.destroy(node);
dojo.create('div', { id: node }, afternode, 'after');
var targetNode = dojo.byId(node);
targetNode.innerHTML = data;
dojo.parser.parse(targetNode);

That didn't help any. What the h3ll is going on? Sometimes it parses some of the elements. Is this a known problem with the dojo.parser?

+3  A: 

If you create the dijits declaratively and use dojo.parser.parse to parse them on-the-fly and you specify the ID of the dijit, once you parse the same HTML fragment twice, you'll get an error says that the dijit's ID has been registered.

<div dojoType="dijit.form.Button" id="myButton" />

The cause is that the dijits have not been destroyed yet and you can not reuse the ID. If you don't specify the ID when declaring it, you won't get this error, but you actually have memory leaks.

The correct way is to destroy the dijits before parsing the HTML fragment again. The return value of dijit.parser.parse is an array list that contains the references of all the dijits it parsed from the HTML fragment. You can keep the list and destroy the dijits first.

if (dijits) {
  for (var i = 0, n = dijits.length; i < n; i++) {
      dijits[i].destroyRecursive();
  }
}
dijits = dojo.parser.parse(targetNode);
Alex Cheng
So I guess I would need to keep the list of parsed dijits to destroy later in a global array?
sims
Not necessarily in the global scope, choose the scope that suitable for you. You can also use `dijit.findWidgets` to find the dijits in a DOM node and destroy them. For example, `var dijits = dijit.findWidgets(targetNode); //destroy the dijits`
Alex Cheng
Man, that's fantastic! Thanks for your help! I don't know anything about dojo. I thought I could just do a node.empty or maybe node.destroyRecursive. But it doesn't work as I expected. Is that because the nodes are registered in memory as a dojo object of sorts that dojo itself is aware of? So, node.empty, gets rid of the node in the DOM, but not the dojo object in memory?
sims
Yes. dojo keeps all the dijits references in a global object `dijit.registry`. This object can be used to get dijit references by its id. When the dijit is destroyed, it's removed from the global registry. Destroying the DOM node only will not remove the dijit from the registry.
Alex Cheng
Excellent! Thanks for the clear explanation.
sims