-3

This appears to be a pretty common issue for a lot of people, but I haven't been able to figure out a solution that works.

I have a method that receives a DOM element from the caller. This DOM element happens to be a div, and I want to get an array of all of the buttons that are descendants of the div so that I can inspect them.

My first stop was to try var buttons = jQuery(element).find('button'); but this only returns the first button it finds.

However, if I do something like var buttons = jQuery('.someClass').find('button'); I get a list of all matched buttons.

Unfortunately, searching using a selector isn't an option, as I only have an element to work from.

One solution I found is at: jQuery find() returns only the first matched result ?. This person's question is almost identical to mine, but I can't get the solution to work, and also don't understand why jQuery isn't doing what I expect it to do here.

Other examples exist all over google and even SO, but most seem to target the use of selectors, not elements.

What don't I understand about jQuery that is preventing this from working the way I think it should, and how can I accomplish what I'm looking to?

Additional Information (is this maybe actually a knockout issue?)

It's a little difficult to give you a concrete set of HTML to look at because it's being rendered dynamically via knockout. That said, here is the a snippet that applies to this situation:

<!-- ko if: Answers.length == 4 -->
<div class="col-xs-12 col-xs-offset-0 col-sm-12 col-sm-offset-0" data-bind="ButtonTextReflowWidth: '120px'">
    <!-- ko foreach: Answers -->
    <div class="answer col-xs-12 col-sm-3" data-bind="css: { selectedAnswer: $parent.SelectedScaleValueID() == ScaleValueID }">
        <button tabindex="-1" class="btn" data-bind="click: $parent.SetSelectedScaleValueID, text: Text, enable: ($parent.ParentVM.CurrentQuestion().QuestionID == $parent.QuestionID)" type="button"></button>
    </div>
    <!-- /ko -->
    <!-- ko template: {name: 'editButtonTemplate'} --><!-- /ko -->
</div>
<!-- /ko -->

data-bind="ButtonReflowWidth: '120px'" is the binding that pass its div as the element into a function that needs to find all of the buttons within the div.

Now that I look at it with fresher eyes, I'm wondering if this is really a knockout issue, rather than a jQuery issue. Could it be that the custom binding is being initialized before the DOM is aware that the template has been rendered out?

The anwsers observable contains at least 4 items, which means that the button and its parent div.answer should get rendered four times. I expect to find 4 buttons when making the jQuery find call.

Community
  • 1
  • 1
Joe
  • 776
  • 7
  • 20
  • 4
    Post a code example that reproduces your issue. – Adam Jenkins Feb 12 '16 at 00:25
  • 1
    The reason why you see a single result is because 'element' ref probably represents an element with an id, which could only have a single instance of 'button' as child. – DinoMyte Feb 12 '16 at 00:27
  • what is the value of element? and how many buttons you are expecting? – JGV Feb 12 '16 at 00:30
  • Commuting now, will get more detail up asap. – Joe Feb 12 '16 at 00:33
  • @DinoMyte - Huh? Whether an element has an id doesn't affect whether it can have child/descendent elements. – nnnnnn Feb 12 '16 at 00:41
  • @nnnnnn: what i meant was jQuery("#div).find('button') against jQuery("div").find('button') – DinoMyte Feb 12 '16 at 00:43
  • 2
    @DinoMyto - there's no reason why both of those wouldn't return all descendent buttons if the #div element contains multiple button elements. And the question says one div contains multiple buttons. (Of course, without seeing the actual html and JS we can't really tell what's wrong.) – nnnnnn Feb 12 '16 at 00:46
  • Alright, I added some detail. Now that I look at it some more, I'm starting to think that this is a knockout issue rather than a jQuery issue. I tagged the post with knockout, so hopefully that will attract some attention from that group. Not really sure why this has been downvoted so many times... seems pretty clear and researched to me, – Joe Feb 12 '16 at 03:04
  • @Joe - are 4 buttons being renderer to the screen? If so, it's almost certain that your jQuery call to `.find()` is too early meaning that it queries the DOM before the elements have been rendered. – Adam Jenkins Feb 12 '16 at 14:54
  • Yeah, I think you're right about that. I thought knockout initialized its bindings after templates were rendered into the DOM, but that must not be the case. – Joe Feb 12 '16 at 15:59
  • @Adam, you're correct. I posted my own answer below. Thanks for sticking with me on this one. – Joe Feb 12 '16 at 18:27

2 Answers2

0

This did turn out to be a knockout issue, not a jQuery issue. The custom binding does not necessarily have access to the full DOM when it is first initialized/updated.

The solution was to defer evaluation of the binding until after the DOM is fully loaded a la jQuery(()=> {jQuery(element).find('button');});

Joe
  • 776
  • 7
  • 20
-3

try this. Should work:

var elems = document.getElementsByTagName( "button" ); var arr = jQuery.makeArray( elems );