In d3.js, how can I check if an item has been deleted without making a new selection?

I am using a d3 timer to animate an element, and I want the timer to stop when the element has been deleted. What is an easy way to do this?

Here is a JS script to illustrate my problem. What should I replace this line?

if (rect.empty()) { 

I understand that I can make it work by changing it to this:

  if (d3.select("rect").empty()) { 

However, making a new D3 selection based on element names or classes is a problem if I have many rect elements or reuse the same classes. Is it possible to simply update an existing D3 selection to make sure it is empty?

+5
source share
1 answer

There are two DOM features available to accomplish what you are looking for, which does not require D3 at all. They will work for you, but will differ in complexity and flexibility.

1. Use live HTMLCollection .

Both Document and Element provide similar methods for retrieving elements based on specified criteria:

All these methods will return live HTMLCollection , which means that the collection of elements will be kept updated even after its first search. You can verify the existence of an element by HTMLCollection.item() collection using HTMLCollection.item() or .namedItem() , or if the collection contains only one element, take a look at .length .

 var svg = document.getElementById("s"); // This is a live HTMLCollection. var rects = document.getElementsByTagName("rect"); console.log(rects.length); // 1: <rect> in collection svg.removeChild(rects.namedItem("r")); // remove <rect#r> console.log(rects.length); // 0: <rect> gone 
 <svg id="s"> <rect id="r"/> </svg> 

There are also some properties available that provide access to live HTMLCollection or NodeList , which can for further workaround:

Note, however, that NodeList not guaranteed to live on their own; You will need to check the documentation. The following two methods return an inanimate NodeList and thus cannot be used for this purpose.

If you need the flexibility they provide, you can choose option 2.

2. Use MutationObserver .

The little-known and greatly understated MutationObserver interface comes in handy when you are interested in changes to the DOM. This is a more complex approach that can significantly increase flexibility.

You create a new MutationObserver that provides a callback that must be called every time a corresponding DOM change occurs. When you start the observer, you indicate what changes matter by defining the element - and sub-tree - and passing the MutationObserverInit configuration object. In the callback, you can freely respond to these changes in any way.

 var svg = document.getElementById("s"); var rect = document.getElementById("r"); var observer = new MutationObserver(function(mutations) { // This callback will be called for all changes you configured it to listen to // and will provide information about every change in the array of // MutationRecords. You can use this to filter and react to the changes you are // interested in by providing an approriate callback function. var removed = mutations.filter(function(mutation) { return mutation.removedNodes.length > 0; }); console.log(`Observed removal of ${removed.length} node(s).`) }) // Listen for changes of the svg element to the child list only observer.observe(svg, { childList: true }); console.log("<rect> found: " + document.getElementById("r") != null); // <rect> found svg.removeChild(rect); // remove <rect> console.log("<rect> found: " + document.getElementById("r") != null); // <rect> gone 
 <svg id="s"> <rect id="r"/> </svg> 
0
source

Source: https://habr.com/ru/post/1210822/


All Articles