133

I have the following dojo codes to create a surface graphics element under a div:

....
<script type=text/javascript>
....
   function drawRec(){
      var node = dojo.byId("surface");
      //   remove all the children graphics
      var surface = dojox.gfx.createSurface(node, 600, 600);

      surface.createLine({
         x1 : 0,
         y1 : 0,
         x2 : 600,
         y2 : 600
      }).setStroke("black");
   }
....
</script>
....
<body>
<div id="surface"></div>
....

drawRec() will draw a rectangle graphics first time. If I call this function again in an anchor href like this:

 <a href="javascript:drawRec();">...</a>

it will draw another graphics again. What I need to clean all the graphics under the div and then create again. How can I add some dojo codes to do that?

Bourbia Brahim
  • 14,459
  • 4
  • 39
  • 52
David.Chu.ca
  • 37,408
  • 63
  • 148
  • 190

8 Answers8

292
while (node.hasChildNodes()) {
    node.removeChild(node.lastChild);
}
Maurice Perry
  • 32,610
  • 9
  • 70
  • 97
  • 17
    Just to be pedantic --- removing DOM nodes without corresponding JS objects will lead to memory leaks. – Eugene Lazutkin Feb 10 '11 at 01:28
  • 2
    @Eugene: Could you say more about that? – Tom Anderson Aug 28 '11 at 15:39
  • 7
    @Tom: dojox.gfx creates JavaScript objects to communicate with the underlying graphics system, which may have DOM nodes (SVG, VML) or not (Silverlight, Flash, Canvas). Removing DOM nodes from DOM does not remove those JavaScript objects, and it **does not remove** DOM nodes either because JavaScript objects still have references to those DOM nodes. The correct way to handle this situation is described in my answer for this question. – Eugene Lazutkin Aug 29 '11 at 05:38
  • @Eugene: With correctly-designed APIs like Canvas, removing DOM nodes *will* free associated objects once there are no reachable references remaining. For example, once you discard an HTMLCanvasElement, any unreachable CanvasRenderingContext2D associated with it will also be freed. Canvas doesn't even give you a way to disassociate a context from a canvas. Perhaps Silverlight or Flash still have this problem, but everyone else solved it long ago. – Glenn Maynard Aug 07 '12 at 16:47
  • @Glenn You forgot IE with VML, but the overall description is pretty accurate, thanks. And see my answer to this question below. – Eugene Lazutkin Aug 07 '12 at 18:53
  • @Eugene: Certainly that would cause memory leaks in IE7, but AFAIK this problem has been fixed in IE8+. – robocat Jul 02 '13 at 00:40
  • 3
    @robocat It has nothing to do with IE: JS objects reference DOM objects keeping them in memory, underlying JS objects are kept in memory by references from other JS objects. For example: a gfx surface references all its children, a group references all its children too, and so on. Deleting just DOM nodes is not enough. – Eugene Lazutkin Jul 02 '13 at 22:16
  • 3
    @david-chu-ca - probably the later answer by Eugene (a primary author of the dojo GFX library) should be marked as the accepted answer. Eugene - thanks for clarification. – robocat Jul 24 '13 at 03:03
  • "If child is actually not a child of the element node, the method throws an exception. This will also happen if child was in fact a child of element at the time of the call, but was removed by an event handler invoked in the course of trying to remove the element (eg, blur.)" See https://developer.mozilla.org/en-US/docs/Web/API/Node.removeChild – Wottensprels Oct 07 '14 at 14:00
  • 1
    @EugeneLazutkin is this a "currently leads to memory leaks" or "will always lead to memory leaks" kind of thing. To my knowledge, it seems like a bug that removing a domNode would not... you know, remove it. – Seph Reed Jul 07 '17 at 16:12
  • Is there any advantage of removing the last child first over removing the first child first? – wastl Jul 28 '18 at 22:49
  • Nowadays you can just do [`node.replaceChildren()`](//developer.mozilla.org/en-US/docs/Web/API/ParentNode/replaceChildren). – Sebastian Simon Jul 08 '21 at 05:10
48
node.innerHTML = "";

Non-standard, but fast and well supported.

Chetan S
  • 23,637
  • 2
  • 63
  • 78
  • 2
    Not supported in IE. Check: http://www.theogray.com/blog/2009/06/internet-explorer-unknown-runtime-error – Rajat Mar 01 '10 at 17:35
  • 4
    Seems to be standard in HTML 5. The above blog entry was user error. https://developer.mozilla.org/en-US/docs/DOM/element.innerHTML – svachalek Dec 05 '12 at 23:49
  • I am fairly sure this can cause problems if the child DOM nodes are going to be reused, because it "clears out" (sets to blank) the child DOM nodes. – robocat Jul 02 '13 at 00:37
  • Also as per user stwissel: innerHTML only works if you are only dealing with HTML. If there is e.g. SVG inside only Element removal will work. – robocat Jul 02 '13 at 00:43
  • 6
    And *slower* compared to removing nodes: http://jsperf.com/innerhtml-vs-removechild/15 – robocat Jul 02 '13 at 01:43
  • Beside some possible drawbacks described in other comments, this can be a fine solution for most situations. – gitaarik Dec 30 '13 at 20:25
  • For me it was about 50 times faster than the accepted answer. – exebook Oct 30 '14 at 19:34
  • @rednaw: `node.innerHTML = ""` is effective if: * not using dojox.gfx, * not using any libraries, * not using events on child nodes, and * not using SVG (& probably some other caveats too). If you are using a library like dojo or jQuery, then you will likely "leak" memory, because references to child nodes from javascript are not cleared, so the dom node is never freed. Always use the appropriate library method (i.e. `surface.clear()` in this case, or possibly dojo `empty()`?) to clear the DOM so that it can release event registrations, node references e.g. jQuery: http://api.jquery.com/empty/ – robocat Nov 26 '14 at 23:04
24

First of all you need to create a surface once and keep it somewhere handy. Example:

var surface = dojox.gfx.createSurface(domNode, widthInPx, heightInPx);

domNode is usually an unadorned <div>, which is used as a placeholder for a surface.

You can clear everything on the surface in one go (all existing shape objects will be invalidated, don't use them after that):

surface.clear();

All surface-related functions and methods can be found in the official documentation on dojox.gfx.Surface. Examples of use can be found in dojox/gfx/tests/.

Eugene Lazutkin
  • 43,776
  • 8
  • 49
  • 56
20
while(node.firstChild) {
    node.removeChild(node.firstChild);
}
James
  • 109,676
  • 31
  • 162
  • 175
  • 1
    jQuery 1.x empty() works that way. In jQuery 2.x which only supports modern browsers, empty() uses `elem.textContent = "";` *however* just because jQuery does it doesn't mean it isn't buggy for example stwissel says "innerHTML only works if you are only dealing with HTML. If there is e.g. SVG inside only Element removal will work". Also see other relevant notes here: http://stackoverflow.com/questions/3955229/remove-all-child-elements-of-a-dom-node-in-javascript – robocat Jul 02 '13 at 00:53
18

In Dojo 1.7 or newer, use domConstruct.empty(String|DomNode):

require(["dojo/dom-construct"], function(domConstruct){
  // Empty node's children byId:
  domConstruct.empty("someId");
});

In older Dojo, use dojo.empty(String|DomNode) (deprecated at Dojo 1.8):

dojo.empty( id or DOM node );

Each of these empty methods safely removes all children of the node.

Gary Sheppard
  • 4,764
  • 3
  • 25
  • 35
Brian C
  • 447
  • 4
  • 10
3

From the dojo API documentation:

dojo.html._emptyNode(node);
Chase Seibert
  • 15,703
  • 8
  • 51
  • 58
2

If you are looking for a modern >1.7 Dojo way of destroying all node's children this is the way:

// Destroys all domNode's children nodes
// domNode can be a node or its id:
domConstruct.empty(domNode);

Safely empty the contents of a DOM element. empty() deletes all children but keeps the node there.

Check "dom-construct" documentation for more details.

// Destroys domNode and all it's children
domConstruct.destroy(domNode);

Destroys a DOM element. destroy() deletes all children and the node itself.

Rui Marques
  • 8,567
  • 3
  • 60
  • 91
  • 1
    He only wants the children to be removed, that means `domConstruct.empty()` would be better in this case. – g00glen00b Feb 18 '14 at 06:44
0
const wipeOut = elm => [...elm.childNodes].forEach(child => child.remove());

wipeOut(elm);
Eissa Saber
  • 161
  • 1
  • 8
  • @SebastianSimon Yes you are right, I updated my answer and I did realize that I need to convert the nodelist to array in order to wipeout all children of the passed parent, despite the foreach method works with nodelist ! – Eissa Saber Jul 10 '21 at 11:56
  • 1
    Yes, the reason is mentioned in [What do querySelectorAll and getElementsBy\* methods return?](/a/10693852/4642212). `.childNodes` is a live NodeList, so removing those nodes in a loop will throw off the loop. – Sebastian Simon Jul 10 '21 at 14:22