user2197158
user2197158

Reputation: 31

How can I get a table row to highlight when an item changes?

I have a table of data which is populated with asset information. The user is able to add/edit/delete assets, and when they add or edit an asset I'd like the corresponding table row to be highlighted.

The problem I'm having is that all of the table rows get highlighted when an asset is added or updated, instead of just the row in question; I think this may be to do with my use of a computed observable to populate the table. I use the computed observable to allow me to filter the table dynamically.

Here is an example of what the viewmodel and HTML currently looks like (the filter doesn't work in the fiddle for some reason and I'm not sure why right now) -> http://jsfiddle.net/c7y2A/1/.

I attempted to use a simple binding, assigned to the <tr> elements

ko.bindingHandlers.flash = {
    update: function (element, valueAccessor) {
        var el = $(element);
        ko.utils.unwrapObservable(valueAccessor());

        el.addClass('flash');
    }
};

Can anyone help me just highlight individual rows? Do I need to change my setup somehow to not use the computed observable? I still need to be able to dynamically filter the table though so I'm not sure how that would work if I didn't use a computed observable.

The flash class just does the following by the way:

.flash {
    animation: flash 2s ease forwards;
}

@keyframes flash {
    0% {
        background: white;
    }

    35% {
        background: #fffbcc;
    }

    65% {
        background: #fffbcc;
    }

    100% {
        background: white;
    }
}

Thanks for any help you can give me :-)

Adam

Upvotes: 0

Views: 1528

Answers (1)

Nathan Fisher
Nathan Fisher

Reputation: 7941

I think that you need something to record the original values of the asset object so that you can compare the current value to the original value. Using a computed you could then output the desired css.

http://jsfiddle.net/gonefishern/c7y2A/3/

HTML

<input type="text" data-bind="value: filter, valueUpdate: 'afterkeydown'" placeholder="Filter assets" />
<table>
    <thead>
        <tr>
            <th>Asset Name</th>
            <th>Serial Number</th>
            <th>Manufacturer</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: {data: filteredAssets}">
        <tr data-bind="css: flashCss, click: $parent.selectAsset">
            <td data-bind="text: name"></td>
            <td data-bind="text: serialNumber"></td>
            <td data-bind="text: manufacturer"></td>
        </tr>
    </tbody>
</table>
<br/>
<br/>
<div data-bind="with: selectedAsset">
    <p>Selected Asset</p>
    <label>Asset Name</label>
    <input type="text" data-bind="value: name"/>
</div>

JavaScript

var asset = function (name, serialNumber, manufacturer) {
    var self = this;
    self.name = ko.observable(name);
    self.serialNumber = ko.observable(serialNumber);
    self.manufacturer = ko.observable(manufacturer);

    self.name.original = name;
    self.serialNumber.original = serialNumber;
    self.manufacturer.original = manufacturer;

    self.hasChanged = ko.computed(function(){
        if (self.name() == self.name.original && self.serialNumber() == self.serialNumber.original && self.manufacturer() == self.manufacturer.original) {
            return false;
        }
        return true;
    });

    self.flashCss = ko.computed(function () {
        //just an example
        if (self.hasChanged()){
            return 'flash';
        }
        return '';
    });
};

var viewmodel = function () {
    var self = this;

    self.filter = ko.observable('');

    self.assets = ko.observableArray([
    new asset("asset 1", "12345", "Dell"),
    new asset("asset 2", "67890", "Dell"),
    new asset("asset 3", "12098", "HP"),
    new asset("asset 4", "55443", "Dell")]);

    // Method to filter the assets table based on user input.  Computed observable is throttled to ensure it doesn't kick in too quickly.
    self.filteredAssets = ko.computed(function () {
        var filter = self.filter().toLowerCase();
        if (!filter) {
            return self.assets();
        } else {
            return ko.utils.arrayFilter(self.assets(), function (item) {
                return item.name().toLowerCase().indexOf(filter) > -1;
            });
        }
    }).extend({
        throttle: 500
    });
    self.selectedAsset = ko.observable();
    self.selectAsset = function(item){
        self.selectedAsset(item);
    };

};

ko.applyBindings(new viewmodel());

CSS

.flash {
    background-color: yellow
}

Upvotes: 1

Related Questions