Reactively change CSS for items in a table

Hi!

I have Documents that are displayed as <tr>s in a <table>. These Documents come from a paginated reactive subscribe function.

There’s a feature to show/hide certain table columns (so both <th> and the respective actual column<tr> based on checkbox selections)


<!-- Checkbox input to show/hide column-->
<input type="checkbox" class="toggle-column" data-target=".Field1>
<input type="checkbox" class="toggle-column" data-target=".Field2>
<input type="checkbox" class="toggle-column" data-target=".FieldN>


<table>
    {{#each documents}}
        <tr>
            <td class="field1">{{field1}}
            <td class="field2">{{field2}}
            <td class="fieldN">{{fieldN}}
        </tr>
    {{/each}}
</table>

Then, I have an event to perform the toggle onCheck

'click .toggle-column'(e) {
        var selectedColumn = e.currentTarget.getAttribute("data-target");

        $(selectedColumn).toggle();
    },

This works fine until data starts reactively changing. A couple scenarios can happen.

  1. A Document can be “removed” from the table based on user input changing a field. Changing of this field then fails the where clause of the publish method and the document will no longer be in MiniMongo.

  2. The other edge case here is if the user jumps to another page. In this case, a whole new set of Documents will be fetched and they won’t have the same class values.

Solution seemed simple enough. Simply unconditionally have the class display come from whatever value is checked off.

I have my subscription function in an autorun. I understand that I can simply loop through all checked inputs and apply css in this function. That could solve #2, but it won’t solve #1 in which a Document altogehter just gets removed. This is because there’s nothing actually reactive going on here. I suppose I could create a ReactiveVar for the current count of Documents and then insert that reactiveVar in the autorun to trigger the show/hide.

But, this is Meteor and I feel like the optimal solution to solve this should be to use helpers.
I tried something like the following

<td class={{getDisplay "field1"}}>{{field1}}

//helper
 getDisplay: function (className) {
        const checked = $(`.toggle-column[data-target="${className}"]`).prop("checked");
        checked ? $(className).show() : $(className).hide();
}

This doesn’t fully work though. The helper gets called everytime the DOM is created. But then if the user tries to check/uncheck a column…nothing happens anymore.

Seems like a simple enough UI issue that maybe I’m overthinking. Anyone solve anything like this before or this a desired pattern? Thanks!

I usually set reactive vars in the onCreated event with reasonable defaultsthen based on clicks / data changes and what not update the vars as needed.

Then in a helper serve up the reactive value as a variable class name or style replacement where needed in ur template.

Template.tname.onCreated(function(){
    const myvar = new ReactiveVar(‘cssclassname’)
})
    
Template.tname.helpers({
    dynamicClass(){
        return Template.instance().myvar.get()
    }
})

Template.tname.events({
     ‘click #btnOk’: function(event, instance){
          instance.myvar.set(‘mynewclassvalue’)
     }
})


<template name=“tname”>
    <div class=“{{dynamicClass}}”>hi there</div>
</template>


Or something very similar to that.

2 Likes

Thanks @drollins!
I’ll try something like that

Your solution worked to a tee. How can I mark this SOLVED?