-1

I am trying to do color animation for TR by custom binding but things are not working as expected. I made some mistake because I am new in KnockoutJS. So please tell me in which area I need to fix in my code.

The mistake is here AnimateRow : $parent.Hasfade() I have a property called Hasfade which I initialize with false but when rows get inserted or updated then I set true.

Custom binding code

    ko.bindingHandlers.AnimateRow = {
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            alert(value);
            $(element).animate({ backgroundColor: "#FCFCD8" }, 300).delay(1000).animate({ backgroundColor: "#EFEAEA" }, 500);

        }
    }

The value is getting null but it suppose to has true because I set at the time of insert and update data in observable array. Please guide me to a fix.

Here is my full code.

<head id="Head1" runat="server">
    <title></title>
    <style type="text/css">
        table.imagetable
        {
            font-family: verdana, arial, sans-serif;
            font-size: 11px;
            color: #333333;
            border-width: 1px;
            border-color: #999999;
            border-collapse: collapse;
        }
        table.imagetable th
        {
            background: #b5cfd2;
            border-width: 1px;
            padding: 8px;
            border-style: solid;
            border-color: #999999;
        }
        table.imagetable td
        {
            background: #dcddc0;
            border-width: 1px;
            padding: 8px;
            border-style: solid;
            border-color: #999999;
        }
        tr.mutating td
        {
            background-color: #efe;
        }
    </style>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/knockout-3.3.0.js" type="text/javascript"></script>
    <script src="Scripts/knockout.mapping.js" type="text/javascript"></script>

    <script type="text/javascript">
        $(document).ready(function () {
            ko.bindingHandlers.AnimateRow = {
                update: function (element, valueAccessor) {
                    var value = ko.utils.unwrapObservable(valueAccessor());
                    alert(value);
                    $(element).animate({ backgroundColor: "#FCFCD8" }, 300).delay(1000).animate({ backgroundColor: "#EFEAEA" }, 500);

                }
            }

            var StockItem = function (_id, _name, _price, _status) {
                var self = this;
                self.id = ko.observable(_id);
                self.name = ko.observable(_name);
                self.price = ko.observable(_price);
                self.status = ko.observable(_status);
                self.mutating = ko.observable(false);
            };

            var data = [
            new StockItem("12345", "Acme Widget 1", "£25.99", "In Stock"),
            new StockItem("67890", "Acme Widget 2", "£28.99", "In Stock"),
            new StockItem("11123", "Acme Widget 3", "£15.99", "In Stock"),
            new StockItem("14156", "Acme Widget 4", "£33.99", "In Stock")];

            var NewData = [new StockItem("99999", "HSL Limited", "£78.99", "In Stock")];

            var appViewModel = function () {
                var self = this;
                self.Hasfade = ko.observableArray(false);
                self.Stocks = ko.observableArray(data);

                self.AddNewData = function () {
                    self.Stocks.push.apply(self.Stocks, NewData);
                    NewData.forEach(markMutated);
                };

                self.DeleteItem = function (dataContext) {
                    var itemToDelete = dataContext;
                    self.Stocks.remove(itemToDelete);
                }

                self.UpdateDataByIds = function () {
                    var id1 = '11123';
                    var id2 = '12345';
                    self.UpdateById(id1, null, null, "Out of Stock");
                    self.UpdateById(id2, null, "31.45", null);
                };

                function markMutated(item) {
                    item.Hasfade(true);
                    setTimeout(function () {
                        item.Hasfade(false);
                    }, 800);
                }

                self.UpdateById = function (_id, _name, _price, _status) {
                    var matchedItem = ko.utils.arrayFirst(self.Stocks(), function (item) {
                        return item.id() === _id;
                    });

                    if (matchedItem != null) {
                        if (_name != null) matchedItem.name(_name);
                        if (_price != null) matchedItem.price(_price);
                        if (_status != null) matchedItem.status(_status);
                        markMutated(matchedItem);
                    }
                };

                self.UpdateData = function (dataContext) {
                    var itemToEdit = dataContext;
                    itemToEdit.status("Out of Stock");
                    markMutated(itemToEdit);
                };
            };

            var vm = new appViewModel();
            ko.applyBindings(vm);
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <button data-bind="click: AddNewData">Add New Data</button>

    <button data-bind="click: UpdateDataByIds">Update Data</button>

    <br>
    <br>
    <table class="imagetable">
        <thead>
            <tr>
                <th>
                    ID
                </th>
                <th>
                    Name
                </th>
                <th>
                    Price
                </th>
                <th>
                    Status
                </th>
                <th>
                    Edit
                </th>
                <th>
                    Delete
                </th>
            </tr>
        </thead>
        <tbody data-bind="foreach: Stocks">
            <tr data-bind="attr: { id: 'tr_' + $index() } , AnimateRow : $parent.Hasfade()">
                <td data-bind="text: id">
                </td>
                <td data-bind="text: name">
                </td>
                <td data-bind="text: price">
                </td>
                <td data-bind="text: status">
                </td>
                <td>
                    <a href="#" data-bind="click: $parent.UpdateData">edit</a>
                </td>
                <td>
                    <a href="#" data-bind="click: $parent.DeleteItem">delete</a>
                </td>
            </tr>
        </tbody>
    </table>
    </form>
</body>

Thanks

Thomas
  • 33,544
  • 126
  • 357
  • 626
  • Please see ["Should questions include “tags” in their titles?"](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), where the consensus is "no, they should not"! –  Jun 08 '15 at 07:14
  • Why use the `$parent` keyword when the `HasFade` is in the item currently being iterated on? Try `AnimateRow : Hasfade`. Also, if you don't mind old browsers, you better go with CSS3 animations, getting rid of the custom `AnimateRow` handler and using `css` handler instead. – haim770 Jun 08 '15 at 07:18
  • @haim770 as per your suggestion i change the code. here is jsfiddle link http://jsfiddle.net/tridip/o47suzqo/6/ now it is working but custom binding update section firing twice when inserting data to Observable array....would u plzz tell me why this is happening ? why custom binding update section firing twice when inserting data to Observable array ? – Thomas Jun 08 '15 at 09:41

1 Answers1

0
  1. You made Hasfade an observableArray instead of an observable.
  2. item doesn't have Hasfade. It is a property of the appModel.
  3. You don't do anything with Hasfade except unwrap it.
  4. The binding handler will only fire when the row is updated; updating its individual parts will not cause the handler to fire

The handler is firing at row-create time, but no animation is visible. Animations are not supported on table rows.

Community
  • 1
  • 1
Roy J
  • 42,522
  • 10
  • 78
  • 102
  • yes i fixed it but when i set value true from function markMutated then custom binding showing false as value because i alert there. – Thomas Jun 07 '15 at 20:14
  • why this line is not working `$(element).animate({ backgroundColor: "#FCFCD8" }, 300).delay(1000).animate({ backgroundColor: "#EFEAEA" }, 500);` – Thomas Jun 07 '15 at 20:15
  • Are you testing your app with the Chrome debugger running? Or Firebug in Firefox? You should be getting errors. I'm running your code in a Fiddle: http://jsfiddle.net/o47suzqo/ and Chrome debugger is telling me when it hits an error. – Roy J Jun 07 '15 at 20:22
  • HI, see these jsfiddle link jsfiddle.net/62Ls6x9n/173 jsfiddle.net/62Ls6x9n/163 here u can see how css binding works... here they declare mutated property which was not a part of item but it works when row edit button clicked. so not mine work. can u rectify my code. thanks – Thomas Jun 08 '15 at 06:45
  • i update the jsfiddle link http://jsfiddle.net/tridip/o47suzqo/12/ still fade in effect is not very smooth. so looking for suggestion to have smooth fade in effect. thanks – Thomas Jun 08 '15 at 10:42
  • You seem to be shooting in the dark in dealing with the mutating class and the value passed to the binding handler. Play with one at a time until you really understand what it's doing. This does the fade-in: http://jsfiddle.net/o47suzqo/14/ – Roy J Jun 08 '15 at 12:40
  • It looks quite smooth to me. – Roy J Jun 08 '15 at 15:33
  • now i update code once again. here is the link http://jsfiddle.net/tridip/o47suzqo/16/ this time i used jquery animate to make it more smooth. – Thomas Jun 08 '15 at 17:12