Darren
Darren

Reputation: 793

Having trouble traversing DOM to get div occuring just before another element

The value of previousDiv when i run the jQuery shown below is always: [ ]. I have tried several variations of the .prev() function including .prev('div'), and .prev() all with the same result.

Here is the jQuery:

$('.AddToRole').click(function(evt) {
var path = document.URL;
var thisUser = this.value;
var previousControl = $(this).prev('.AvailableRoles');
var newUserRole = previousControl[0].options[previousControl[0].selectedIndex].text;
var newHTML = "<button id='button_DeleteRole_" + newUserRole +"' class='DeleteRole' value=" + newUserRole + ">X</button>&nbsp;<label id='label_DeleteRole_" + newUserRole + "'>" + newUserRole + "</label><br />";
var previousDiv = $(this).prev('#DisplayUserRoles');
$(previousDiv).append(newHTML);

Here is the html/razor code in the page:

<div>
                    @* Display user email. *@
                    <h3>@user.Email</h3>
                    <div>
                        <div id="DisplayUserRoles">
                            @{
                                @* Display roles user belongs to. *@
                                foreach (var role in userRoles)
                                {
                                    @* Remove user from role button. *@
                                    <button id="[email protected]" value="@role.RoleName" onclick="RemoveUserFromRole(this);">X</button>
                                    <label id="[email protected]">@role.RoleName</label>
                                    <br />
                                }
                            }
                        </div>
                        <br />                            
                    @{                                                    
                        @* Create ListBox with roles user does not belong to. *@
                        var items = rolesUserDoesNotBelongTo.Select(i => new SelectListItem
                        {
                            Value = i.RoleName,
                            Text = i.RoleName
                        });

                        string listBoxId = "listboxRoles_";
                        listBoxId = listBoxId + user.Email;

                    }                            
                        @Html.ListBox(listBoxId, items, new { @class = "AvailableRoles" })
                        @* Add user to role button. *@
                        <button id="[email protected]" class="AddToRole" value="@user.Email">Add To Role</button>
                    </div>
                </div>

For the end result I am trying to add another button and label just before the closing div tag for #DisplayUserRoles.

Upvotes: 0

Views: 131

Answers (2)

CalMlynarczyk
CalMlynarczyk

Reputation: 705

As stated before, if there are no sibling elements of the selected element, .prev() returns an empty array. If this is the case, then check the closest parent element.

var previousControl = $(this).prev();

if (!previousControl.length) {
    previousControl = $(this).parent();
}

previousControl.toggleClass('bestClass'); // This is just an example function 
                                          // call on the element

Upvotes: 1

jfriend00
jfriend00

Reputation: 707298

.prev() does not work how you are using it. It gets the previous sibling element and then filters that by the selector you pass. It does NOT look for any previous sibling that matches the selector.

Thus, when you do both of these:

$(this).prev('.AvailableRoles');
$(this).prev('#DisplayUserRoles');

At least one of them will return no object unless the previous sibling is both .AvailableRoles and #DisplayUserRoles which I doubt is what you're looking for.


I'm not exactly sure I know what you're trying to do with these, but you could do this instead:

$(this).prevAll('.AvailableRoles').first();

And for the DisplayUserRoles, since there can only ever be one object with a given ID in the document, you can just do this:

$('#DisplayUserRoles');

These would get all previous siblings that match the selector and then get just the first one.


As I said in my comment, we could help a lot better if you posted the generated HTML (what a browser sees with View/Source) rather than you template code which we don't necessarily know what HTML it generates.

Upvotes: 1

Related Questions