3

Let's say I have a div that's called Z.Zthat is a sub-sub-sub... child of adivcalledBwhich is a child of adivcalledA`.

All the block from B to Z are set to display=none (A is visible).

If I click on a anchor that links to the block Z, I want it to be displayed.

For that I need to set the display of block Zblock, but also its parent's display* to block, and its parents and all the way up to block B....

I don't want to "hard" code all the possible level because I could have 2, 4 or 10 levels. So I would like to find a way to do it automatically.

I simplified a bit the example above as I have to set the display=block every 2 "generations" (cf in my code the parentNode.parentNode)

So far this is my code (with 2 level down the rabbit hole!) and not automation:

function indexLink(link_to_anchor) {
    var x = document.getElementById(link_to_anchor);
    if (x.parentNode.parentNode.getAttribute("class") == "divcodebox") {
        if (x.parentNode.parentNode.parentNode.parentNode.getAttribute("class") == "divcodebox") {
            x.parentNode.parentNode.parentNode.parentNode.style.display = "block";
        }
        x.parentNode.parentNode.style.display = "block";
    }
    x.style.display = "block";
}

Using indexLink() recursively :

function indexLink(link_to_anchor) {
    var x = document.getElementById(link_to_anchor);
    x.style.display = "block";
    if (x.parentNode.parentNode.getAttribute("class") == "divcodebox") {
        x.parentNode.parentNode.style.display = "block";
        indexLink(x)
    }
}
MagTun
  • 5,619
  • 5
  • 63
  • 104
  • 1
    Just call `indexLink()` within itself with the parent of `link_to_anchor` (=x.parentNode) as long as its display is not block (or none depending on your scheme). – Lain May 08 '19 at 14:00
  • @Lain, thanks for your suggestion. I tried it (cf the edit at the bottom of my question), but I get this error ` Cannot read property 'style' of null`. Could you give me a code example please? – MagTun May 08 '19 at 14:21
  • First, you have to pass an element and not its `id` unless you want to guarantee that all elements on your site have indeed an `id`. Therefore just pass a HTMLElement and change `x` to `var x = link_to_anchor`. Then you call `x.parentNode && indexLink(x.parentNode)` instead of `indexLink(x)`. – Lain May 08 '19 at 14:29
  • Ok I didn't get that! Thanks ! – MagTun May 08 '19 at 14:33
  • Made you a little example just so you can see how it would have looked like for learning process. – Lain May 08 '19 at 14:35

3 Answers3

3

How about a simple for loop?

    var x = document.getElementById(link_to_anchor);
    for (parent = x.parentNode; parent; parent = parent.parentNode) {
      // do whatever
    }

You can of course keep a counter to check how many steps you've traversed, etc. The .parentNode reference from the document level will be null, so that ends the iteration. (You can break out of the loop early too.)

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Thanks @Pointy, It's working but I don't understand the for condition. I try to related it to `for (var i = 0; i < 100; i++) {` but I don't understand how the middle `parent` don't stop everything right at the first step. Unless this `parent` gets updated at each loop ? – MagTun May 08 '19 at 14:28
  • 1
    @MagTun yes, it gets updated by the third clause in the loop header: `parent = parent.parentNode`. The middle expression will be "truthy" unless `parent` is `null`, which it will be if the iteration makes it up to the `document` level. – Pointy May 08 '19 at 14:29
1

This is just to show how your recursive function should look like based on your code and not a finished example.

;function indexLink(element){
    //REM: Change the parameter to the actual element instead of its id
    //var x = document.getElementById(link_to_anchor);

    //REM: Check if the element exists and the style does not equal block
    //REM: If the styles are set by class you need to change this to computed style
    if(element && element.style.display !== 'block'){
        //REM: Set the display to block
        element.style.display = 'block';

        //REM: Repeating the same logic for the parentNode
        indexLink(element.parentNode)
    }
};
Lain
  • 3,657
  • 1
  • 20
  • 27
0
function recursiveApply(from, to, fn) {
    let current = from;

    while(current !== to) {
        fn(current);
        current = current.parentElement;
    }
}

and then use it like:

var a = document.getElementById("1");
var b = document.getElementById("2");

recursiveApply(a, b, function(element) {
    // do stuff with the element
    console.log(element)
});
Michel Vorwieger
  • 692
  • 5
  • 14