-2

Ok so I feel like I'm missing something let me show you a very simple function I wrote.

function findClosestAncestor(html_child_element, html_class_name) {
    if (!html_child_element.parentElement.classList.contains(html_class_name)) {
        findClosestAncestor(html_child_element.parentElement, html_class_name)
    } else {
        return html_child_element.parentElement;
    }
}

When I am feeding in a child element from my page I debug this function and as expected it hits the else statement after running through twice. This has been confirmed via Chrome's dev tools debugging it live and is the element on the page I wish to return. However when the function is called and set to a variable like so

let parentPanel = findClosestAncestor(e.target, "panel");

parentPanel is undefined after I exit the function. This is causing me a bit of confusion and I may just be overlooking something very simple here. What is happening.

EDIT: Per Thomas suggestion I have tested .closest() this still is not returning a value either. The relevant parts of the structure of the HTML is below

                                <div class="list-info">
                                    <div class="container">
                                        <div class="account-type text-title">Type</div>
                                        <div class="account-type-placeholder text-info">Type Placeholder</div>
                                    </div>
                                    <div class="container">
                                        <div class="account-phone text-title">Phone</div>
                                        <div class="account-phone-placeholder text-info">Phone Placeholder</div>
                                    </div>
                                    <hr /> <hr />
                                    <button class="sublist-accordion">
                                        <div class="sublist-title">
                                            Other cases for this Customer
                                        </div>
                                    </button>
                                    <div class="sublist-panel">

The element we are calling either method on is the final sublist-panel you see the top of there. It should be and in the case of my method is successfully finding the panel class above. However it is still not allowing me to assign that out as a return value and is returning undefined for both my method and .closest

10
  • 3
    You may want to add a return in your if block Commented May 20, 2021 at 18:57
  • let parentPanel = e.target.closest(".panel"); MDN Element#closest() Commented May 20, 2021 at 19:00
  • @Thomas I do not have access to jquery. Commented May 20, 2021 at 19:12
  • 1
    @Iptay this is plain JS, not jquery. That's why I linked the docs for that method. Commented May 20, 2021 at 19:13
  • 1
    @Iptay Given your debugger is showing that it hits the else statement, is it also showing which iteration of findClosestAncestor hits it? If it is a secondary iteration without a return statement in the if part of the previous iteration there's no way to pass the result up the call stack to the original caller. (I would have thought). Commented May 20, 2021 at 19:18

2 Answers 2

1

Since you check whether the parent doesn't contain the class html_class_name, it will keep executing the function until it finds one that contains it. But what happens if no parent has the class? The function keeps executing until there are no more parents to check.

What you are missing is an end to the recursive function when it doesn't find a parent!

    function findClosestAncestor(html_child_element, html_class_name) {
        if(!html_child_element.parentElement){
            // What to do here? That's up to you
            // Return the parent?
            // Return the first child?
        }
        if (!html_child_element.parentElement.classList.contains(html_class_name)) {
            findClosestAncestor(html_child_element.parentElement, html_class_name)
        } else {
            return html_child_element.parentElement;
        }
    }
Sign up to request clarification or add additional context in comments.

2 Comments

Again this has confirmed to return a value. I have debugged it live. I understand it will error if there is no return as it will eventually reach the top of the DOM.
If that's the case, you'll have to give us more info, since this does work locally.
0

Suggested alternative:

function findClosestAncestor(html_child_element, html_class_name) {
    if (!html_child_element.parentElement.classList.contains(html_class_name)) {
        return findClosestAncestor(html_child_element.parentElement, html_class_name)
    } else return html_child_element.parentElement;
}

The point is that you always need to return something; regardless of which branch you take.

2 Comments

Everyone seems to be caught on not answering the question. This value will return. It does return. My question is not about what will happen without a default return value but rather why when it is hitting this part of the code. As confirmed to be happening it is not returning a value ``` } else { return html_child_element.parentElement; } ```
Dude - if you want function "findClosestAncestor()" to return a value ... and you don't explicitly return a value from all code paths ... THEN THAT'S A BUG! Perhaps you've ALSO got another, separate problem or issue. If so, you completely failed to describe it well enough for anybody to help you. But from everything you said, it sounds like you simply don't understand how recursive functions "should" work, as described here

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.