1

I am trying to apply changes to the DOM when a <tr> is clicked. When clicked, it should add data-state=enabled and data-display=expanded to the clicked <tr> while applying data-state=disabled and data-display=collapsed to every other <tr>.

So it should look like highlighting the clicked row while disabling the other rows.

Then, when a row is highlighted, and a user clicks elsewhere, it should reset to default, i.e. data-state=enabled and data-display=collapsed for all <tr>'s

Currently, I have it working so that when a <tr> is clicked, that row is highlighted and all others disabled. However, the script is missing the reset to default because if another <tr> is clicked, it immediately highlights that one and disables the rest.

I would like to do this in vanilla javascript but I am also open to using jQuery if it is substantially easier and won't affect performance noticably.

Here is the JSbin with working code to see where it's at: https://jsbin.com/kirati/

And the code so far:

<table class="table">
                    <thead>
                        <tr>
                            <th class="sort-key asc"><a href="#">Pet Name </a></th>
                            <th><a href="#">Owner (Last, First)</a></th>
                            <th><a href="#">Species</a></th>
                            <th><a href="#">Breed</a></th>
                            <th><a href="#">ID</a></th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>
                                Fluffy
                                <div class="table-row__expanded-content">
                                    <data-key>Sex: </data-key> <data-value>Male</data-value><br />
                                    <data-key>DOB: </data-key> <data-value>12/08/2010</data-value> <br />
                                    <data-key>Weight: </data-key> <data-value>20 lbs</data-value> <br />
                                    <data-key>Location: </data-key> <data-value>Kennel 2B</data-value> <br />
                                    <data-key>Temperament: </data-key> <data-value>Aggresive</data-value> <br />
                                    <data-key>Allergies: </data-key> <data-value>Sulfa, Penicillin, Peanuts</data-value>
                                </div>
                            </td>
                            <td>Anderson, James</td>
                            <td>Dog</td>
                            <td>Bulldog-Shitzu</td>
                            <td>ABCDE1234567</td>
                        </tr>
                        <tr>
                            <td>Feather</td>
                            <td>Michelle Charlotte, <br /> Angel Vanessa</td>
                            <td>Cat</td>
                            <td>American Bobtail</td>
                            <td>FGHIJ1234567</td>
                        </tr>
                        <tr>
                            <td>Fluffer-Nutter</td>
                            <td>Rakerstraw, Rickey</td>
                            <td>Dog</td>
                            <td>American Eskimo</td>
                            <td>KLMNO1234567</td>
                        </tr>
                        <tr>
                            <td>Farley</td>
                            <td>Cunningham, Stephanie</td>
                            <td>Dog</td>
                            <td>Pomeranian</td>
                            <td>PQRST1234567</td>
                        </tr>
                        <tr>
                            <td>Fuzzy</td>
                            <td>Venice, Harding</td>
                            <td>Cat</td>
                            <td>Burmese</td>
                            <td>UVWXY1234567</td>
                        </tr>
                        <tr class="alphabet-label">

                            <td>G</td>
                            <td></td>
                            <td></td>
                            <td></td>
                            <td></td>
                        </tr>
                        <tr>
                            <td>Goldie</td>
                            <td>Cherilyn, Mitchener</td>
                            <td>Dog</td>
                            <td>Chihuahua-Maltese</td>
                            <td>ZABCD1234567</td>
                        </tr>
                    </tbody>
                </table>

And the Javascript

window.onload = function () {

    var tablerow = document.body.getElementsByTagName('tr');
    console.log(tablerow);

     // Convert the HTMLCollection into a true javascript Array, so we can do "stuff" with it       
    var tablerowArr = Array.prototype.slice.call(tablerow);
    console.log(tablerowArr);

// Do stuff
    tablerowArr.forEach(function (value, i) {
        console.log(i, value);

        tablerow[i].onclick = function (e) {
            //console.log("clicked!");


            var newArr = tablerowArr.slice(i, i + 1);
            //console.log(tablerow);
            console.log(i);
            //console.log(tablerowArr);
            console.log('newArr', newArr);


            tablerowArr.forEach(function (value, i) {

                // first reset all instances of data-XXX  
                tablerowArr[i].setAttribute('data-display', "collapsed");
               // tablerowArr[i].setAttribute('data-state', "enabled");

                // Set the <tr> data-display attribute to expanded/collapsed on click
                newArr[0].setAttribute('data-display', tablerowArr[i].getAttribute('data-display') === "collapsed" ? "expanded" : "collapsed");
                //tablerowArr[i].setAttribute('data-display', tablerowArr[i].getAttribute('data-display') === "collapsed" ? "expanded" : "collapsed");

                // Set the <tr> data-state attribute to enabled/disabled on click
                newArr[0].setAttribute('data-state', newArr[0].getAttribute('data-state') === "disabled" ? "enabled" : "enabled");
                tablerowArr[i].setAttribute('data-state', newArr[0].getAttribute('data-state') === "enabled" ? "disabled" : "enabled");

            });

            e.preventDefault();
        };
    });
};
4
  • try this solution maybe it may help How to change HTML Object element data attribute value in javascript or this one Set data attribute using JavaScript Commented Oct 14, 2015 at 14:59
  • "use jQuery if it is substantially easier and won't affect performance noticably" - it always is substantially easier and it doesn't affect performance Commented Oct 14, 2015 at 15:12
  • I prefer VanillaJS because it helps me better understand JavaScript rather than relying on "magic" from cool libraries like jQuery. Of course there is a time and place for libraries because they make some stuff super easy - but there are times when pureJS is just fine (and helps my understanding grow). Commented Oct 14, 2015 at 16:37
  • Possible duplicate of Set data attribute using JavaScript Commented Aug 7, 2018 at 20:19

4 Answers 4

1

Here is a pure javascript example in the below jsfiddle:

http://jsfiddle.net/pya9jzxm/14

    var tbody = document.querySelector('tbody');
    var trs = tbody.querySelectorAll('tr');
    var tr, index = 0, length = trs.length;
    for (; index < length; index++) {
        tr = trs[index];
        tr.setAttribute('data-state', 'enabled');
        tr.setAttribute('data-display', 'collapsed');
        tr.addEventListener('click',
            function () {
                if (this.classList.contains('alphabet-label')) {
                    return;
                }
                var trIndex = 0, trLength = trs.length, hasExpanded = false;
                var state = 'disabled';
                if (tbody.querySelectorAll('[data-display="expanded"]').length > 0) {
                    hasExpanded = true;
                    state = 'enabled';
                }
                for (; trIndex < trLength; trIndex++) {
                    trs[trIndex].setAttribute('data-state', state);
                    trs[trIndex].setAttribute('data-display', 'collapsed');
                }
                if (!hasExpanded) {
                    this.setAttribute('data-state', 'enabled');
                    this.setAttribute('data-display', 'expanded');
                }
            }
        );
    }
};
Sign up to request clarification or add additional context in comments.

20 Comments

Thanks! You did it perfectly!! Pure JS too - even better :-)
That's the one!! Version 7. Thank you once again for the excellent support. I'm working on a big project for a company.
Neat! I like the cleanliness of it. As they say, keep your code DRY.
Lol you're on a roll!
All is perfect now. Thanks again - Cheers!
|
0

in jQuery:

$(function() {
    $('html').click(function() {
        /* return to default state */
        $('.table tbody tr').data('state', 'enabled').data('display', 'expanded');
    });
    $('.table tbody tr').on('click', function(e) {
        /* stop the html click event */
        e.stopPropagation();
        /* set attributes for all rows */
        $('.table tbody tr').data('state', 'disabled').data('display', 'collapsed');
        /* set attributes for the clicked row */
        $(this).data('state', 'enabled').data('display', 'expanded');
    });
});

I've commented the function, to clarify how it works.

10 Comments

just double check $(this).data( do you not mean $(this).attr( ?
When I added this to my JSbin with jquery loaded, the script did not work, using (this).data and (this).attr - see JS bin with original code: jsbin.com/xukiyoragu
@freedomn-m do you mind posting a link to support your claim as I have one which directly contradict you api.jquery.com/data
@TetraDev see my answer for jquery. also may i suggest you change some of this to work off html classes instead of data attributes, unless there is some other framework which you are relying on.
@freedomn-m the one modifies the DOM the other does not.... so ask yourself the same question. He wants to modify the DOM not underlining model data... so ... I hope that helps you understand the diff between attr and data. He wants to modify the actual HTML in the page.
|
0

Which is very simular to @LinkinTED

Please inspect the html before you say this does not work.. I've tested it myself.

May i suggest that you instead modify the class... to change the effects.

$(function() {

    var $row = $('.table tbody tr');

    $('html').click(function() {
        $row.attr('state', 'enabled').attr('display', 'expanded');
    });

    $row.on('click', function(e) {
        e.stopPropagation();
        $row
          .attr('state', 'disabled')
          .attr('display', 'collapsed');

      //console.log(e);

        $(this)
          .attr('state', 'enabled')
          .attr('display', 'expanded');
    });
});

8 Comments

It works if I edit the attr to data-state and data-display (that's what my css required). Although it is only missing the "reset" when clicking to another row after being highlighted. It resets if I click anywhere in the DOM which is not a <tr> but it should also reset even when clicking another <tr> before applying the next highlight.
OK but is this just to: highlight row, and show hidden data when clicked, if so I would change this to add and remove classes instead of working off attributes. You could just add a check in to meet your additional requirement. Also if you don't like the rest variable you could change it.
It's not a matter of 'inspecting the html' because OP is using css which is looking for attributes "data-state" so attr("state") isn't the same as attr("data-state")
I wanted to avoid using classes to change states because I want to keep my classes clean and minimal, and use html5 data- properties for best practice. Just my personal preference.
@TetraDev ... just so you are aware... maybe im wrong but i dont think so... the more correct way.... even with html5 and attr's, to do this, is with classes.... if you think im wrong... you could ask this on SO. (but remember i called it ;-)), you could using common classes like "hide" part of bootstrap, and you already using css... so... not sure why you think classes is not the correct way to modify the dom. attr are usually used to carry info, not to affect styling...just an FYI, hope this was useful.
|
0

Using vanilla JS and event delegation. DEMO

var tablerow = document.body.getElementsByTagName('tr');
// Convert the HTMLCollection into a true javascript Array, so we can do "stuff" with it       
var tablerowArr = Array.prototype.slice.call(tablerow);
// store the highlighted row
var highlighted;

// extracted function to enable/disable rows
var enable = function(row){
    row.setAttribute('data-display', "expanded");
    row.setAttribute('data-state', "enabled");
}
var disable = function( row ){
    row.setAttribute('data-display', "collapsed");
    row.setAttribute('data-state', "disabled");
}
// on click anywhere
document.body.addEventListener('click', function(e){
    var target = e.target;
    // check if event target or any of its parents is a TR
    while( target.parentNode && target.nodeName.toLowerCase() != 'tr' ){
        target = target.parentNode;   
    }
    // if s row was higlighted disable all rows
    if( highlighted ){
        tablerowArr.forEach(  disable );
        // and remove the reference to highlighted
        highlighted = null;
    }
    // no row is highlighted
    else {
        tablerowArr.forEach( function(row){
            // if the event target is a row, highlight it
            if(row == target) {
                enable( row );
                // and store it as the currently highlighted
                highlighted = row;
            }
            // if it's not the event target then disable
            else {
                disable( row ); 
            }
        });
    }
});

3 Comments

Works great except it is also missing the "reset to default" after clicking off of a row which is highlighted. i.e. first click away from highlighted row makes every row is unhighlighted, second click then highlights the new row.
@TetraDev I have focused on the "clicking anywhere" part to remove highlights. Fixed now to remove highlight on first click.
Thanks - that part works. But I did not communicate clearly - on the reset, all rows should go back to default data-state-enabled and data-display=collapsed. Right now, when the "reset" is applied, all rows are disabled and collapsed (should be enabled and collapsed)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.