Select Adjacent Rows That Have Class

Select Adjacent Rows That Have Class

dredgydredgy Posts: 16Questions: 5Answers: 0

Ok I have a very inelegant solution that has problems. I am pushing what datatables is meant to be used for.

Basically in my table, a user select a row, and then add "instructions to it". These instructions are new rows, but assigned a class "instructionRow" so I can make it look like a "sub" table (CSS adds indents etc). See below:

I want to make it so that when you select a standard row, it checks to see if it has any instruction rows adjacent to it. If it does, it selects them too. However if you select an instruction row by itself, it must not select adjacent rows. In the previous example, if I select "Burger", it must also select "No Pineapple" and "Seafood Allergy". However if I select "No Pineapple", it just selects "No Pineapple" and doesn't select "Seafood Allergy" as per examples below:


Now I do have a semiworking solution but it's extremely messy and I think I want to redo it ground up. The function is tied to the select event. Because I am programmatically selecting things, I am using .addClass('.select') as opposed to .select() because I couldn't figure out a way to use .select() without having recursion problems. But the problem with using addClass is that, while visually it's great, it doesn't actually change the selected status of the item, which means updating the total of selected items via .sum() doesn't work. So I'd rather a solution that recursively uses .select(), as it would inevitably be nice than my current spaghetti.

It needs to
* Check if the initial item selected is a normal row, or an instruction row
* If it is an instruction row (has class instructionRow), then just select that row and nothing more.
* If it is a normal row, check if the next row is an instruction row. If the next row is not an instruction row, then only select the initial row.
* If it is a normal row and the next row IS an instruction row. Select the next row too.
* Check each subsequent instruction row and select them.
* Stop checking rows once the next normal row is reached.

My current function (called when a row is selected):

function selectInstructions(parentRow, hasBeenCalledInternally=false){
        index = parentRow.index();
    
        currentRow = orderBox.row(index);
        currentRowIsInstruction = $(currentRow.node()).hasClass('instructionRow');
   
        
        nextRow = orderBox.row(index+1);
        nextRowIsInstruction = $(nextRow.node()).hasClass('instructionRow');

        
        if(nextRowIsInstruction){
            if(hasBeenCalledInternally){
                $(nextRow.node()).addClass('selected');
                selectInstructions(nextRow, true);
                 
            } else if(!currentRowIsInstruction) {
                 $(nextRow.node()).addClass('selected');
                 selectInstructions(nextRow, true);
                
            }
        }

        orderBox.DataTable();
}

I'd love to see your approaches. Or I guess to cheat, if there is a way to programmatically select a row without triggering this function in the select event once it's already been done.

Thanks in advance

This question has accepted answers - jump to:

Answers

  • kthorngrenkthorngren Posts: 21,173Questions: 26Answers: 4,923
    Answer ✓

    I am using .addClass('.select') as opposed to .select() because I couldn't figure out a way to use .select() without having recursion problems.

    I suspect the problem is you used jQuery on() but instead needed to use jQuery one() to invoke the event once.

    This example is how I would approach the problem:
    http://live.datatables.net/walafipu/1/edit

    I put some comments and console log statements to help you understand. Let us know if there are any questions. The example relies on getting the rows().indexes() in the order the table is sorted. It uses indexOf() to get the array index of the selected row. It loops array starting at this index to get the next rows until the instructionRow class is no found.

    Hope it makes sense.

    Kevin

  • dredgydredgy Posts: 16Questions: 5Answers: 0

    Thanks Kevin, great code and seems to work exactly how I need it. I was sitting in here in bed thinking up very convoluted ways involving generating a unique row id, and assigning a class to instructions based on that Id.

    I like your way much better, I wasn’t sure how .one() behaved and had already ruled it out. But the reattaching it at the end of the function is exactly the kind of inspiration I needed.

    I’ll give you a shout out tomorrow if I have any more questions, but I think I should be good! Much appreciated!

  • dredgydredgy Posts: 16Questions: 5Answers: 0

    Had to get out of bed to try. I am mostly asleep so can likely troubleshoot this myself tomorrow but if you're awake, feel free to jump in!

    As you've written, it works. I would like to be able to select multiple of these groups at a time though, and doing so with your code produces some bugs. (I'm just commenting out (orderBox.rows().deselect() to prevent it from deselecting rows first, which does work but only if you select the bottom group first and then move up).

    And then when writing the inverse to deselect these groups, do I still check {selected: true} at the start of the function?

    Thanks!

  • kthorngrenkthorngren Posts: 21,173Questions: 26Answers: 4,923
    Answer ✓

    The select event has some parameters passed in with one of them being the row indexes. I changed the example to use the indexes parameter to process only the selected row - leaving the other selected rows alone.
    http://live.datatables.net/walafipu/2/edit

    My example assumes only one row is selected at a time, ie, indexes[0]. It can be updated to loop through all the indexes if needed.

    You can probably do something similar with the deselect event and deselect the appropriate instructionsRows.

    Kevin

  • dredgydredgy Posts: 16Questions: 5Answers: 0

    Thanks, I was able to get something that resembles that to work this morning as both selecting and deselecting.

    But I can't say I find the indexes particularly easy to understand! Thanks for all your help, this table component is all but done, assuming I can get a working addRowBelowIndex() function!

  • kthorngrenkthorngren Posts: 21,173Questions: 26Answers: 4,923
    edited November 2020

    But I can't say I find the indexes particularly easy to understand!

    What do you have questions on?

    assuming I can get a working addRowBelowIndex() function!

    The sorting of the table will determine where the added row is displayed.

    Kevin

  • dredgydredgy Posts: 16Questions: 5Answers: 0

    What do you have questions on?

    Nothing in particular, just having trouble visualizing it. I'm still struggling with JQuery tbh, I don't even usually consider using it due to code bloat, but since this project is never going to be deployed on the internet I wasn't too phased. So I get very confused as to when I'm meant to convert to a jQuery Object, perform a function on the row object itself, or on the node() and now I've got to worry about where all the indices are!

    The sorting of the table will determine where the added row is displayed.

    Yup, which is a massive clue that DataTables isn't what I actually want to be using for this use case - I'm using it as an input to determine the order manually without sorting. I'm treating it more as a UI control - I just wanted something to programmatically add/remove/select rows.

    That said, I do have a mostly working addRowBelowIndex() function by storing all the rows in an array, splicing in the new one and then reloading the table. But it does strip all the rows & cells of their classes so going to have to try a new approach of creating a new row as per normal and then moving just it. It seems very doable, but there's enough resistance that I can tell I'm not meant to be doing it :p

  • kthorngrenkthorngren Posts: 21,173Questions: 26Answers: 4,923

    In your data how do you know which instruction rows belong to a particular non-instruction row? Maybe a foreign key or something like that? You can have hidden columns and sort on those.

    If you want to update the example with something that represents your data we might be able to help with a sorting solution.

    Kevin

  • dredgydredgy Posts: 16Questions: 5Answers: 0

    In your data how do you know which instruction rows belong to a particular non-instruction row? Maybe a foreign key or something like that? You can have hidden columns and sort on those.

    Hmmm. Not at the moment. Wouldn't be a huge thing to add if I just gave each row an incrementing id, unless it's an instruction in which case it gets the same as it's parent. Though would still need to track what order instructions were inputted.

    This is definitely new thread territory though. If I can't get it working tonight, then I will ask as a new question or tear the whole thing down and start again with just direct DOM manipulation. Thanks for all your help!

This discussion has been closed.