Hemant
Hemant

Reputation: 49

How to implement cancel functionality using knockout.js

I am working on a asp.net MVC project. and i am using knockout.js on my view page. I am trying to develop a data entry grid. Everything works fine except Cancel button.

If i change something on my UI ( view) and clicked on cancel , It is not showing me old values .it only show me the latest values.

Steps:

Right now , even if you edit and click on cancel button , it is able to revert to old state.

I am not going back to old state when i clickd on cancel button. Please suggest me some examples .

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Type Lookup....</title>
    <script src="~/Scripts/jquery-2.1.0.js"></script>
    <script src="~/Scripts/knockout-3.0.0.js"></script>

    <link href="~/Content/Site.css" rel="stylesheet" />
    <link href="~/Content/bootstrap.css" rel="stylesheet" />
    <script type="text/javascript">
        viewModel = {
            lookupCollection: ko.observableArray()
        };

        //wrapper to an observable that requires accept/cancel
        ko.protectedObservable = function (initialValue) {
            //private variables
            var _actualValue = ko.observable(initialValue),
                _tempValue = initialValue;

            //computed observable that we will return
            var result = ko.computed({
                //always return the actual value
                read: function () {
                    return _actualValue();
                },
                //stored in a temporary spot until commit
                write: function (newValue) {
                    _tempValue = newValue;
                }
            });

            //if different, commit temp value
            result.commit = function () {
                if (_tempValue !== _actualValue()) {
                    _actualValue(_tempValue);
                }
            };

            //force subscribers to take original
            result.reset = function () {
                _actualValue.valueHasMutated();
                _tempValue = _actualValue();   //reset temp value
            };

            return result;
        };

        $(document).ready(function () {
            $.ajax({
                type: "GET",
                url: "/Home/GetIndex",
            }).done(function (data) {
                $(data).each(function (index, element) {
                    var mappedItem =
                        {
                            Id: ko.observable(element.Id),
                            Key: ko.observable(element.Key),
                            Value: ko.observable(element.Value),
                            Mode: ko.observable("display")
                        };
                    viewModel.lookupCollection.push(mappedItem);
                });
                ko.applyBindings(viewModel);
            }).error(function (ex) {
                alert("Error.....");
            });


            $(document).on("click", ".kout-edit", null, function (ev) {
                var current = ko.dataFor(this);
                current.Mode("edit");
            });

            $(document).on("click", ".kout-update", null, function (ev) {
                var current = ko.dataFor(this);
                saveData(current);
                current.Mode("display");
            });

            $(document).on("click", ".kout-cancel", null, function (ev) {
               var current = ko.dataFor(this);
               current.Mode("display");
            });

            $(document).on("click", "#create", null, function (ev) {
                var current = {
                    Id: ko.observable(0),
                    Key: ko.observable(),
                    Value: ko.observable(),
                    Mode: ko.observable("edit")
                }
                viewModel.lookupCollection.push(current);
            });

            function saveData(currentData) {
                var postUrl = "";
                var submitData = {
                    Id: currentData.Id(),
                    Key: currentData.Key(),
                    Value: currentData.Value()

                };

                if (currentData.Id && currentData.Id() > 0) {
                    postUrl = "/Home/Edit"
                }
                else {
                    postUrl = "/Home/Create"
                }
                $.ajax({
                    type: "POST",
                    contentType: "application/json",
                    url: postUrl,
                    data: JSON.stringify(submitData)
                }).done(function (id) {
                    currentData.Id(id);
                }).error(function (ex) {
                    alert("ERROR Saving....");
                })
            }

        });

    </script>
</head>
<body>
    <div>
        <p>
            <button class="btn btn-primary" id="create">Create</button>
        </p>
        <table class="table">
            <tr>
                <th>Key
                </th>
                <th>Value
                </th>
                <th>Action
                </th>
            </tr>

            <tbody data-bind="foreach: lookupCollection">
                <tr data-bind="template: { name: Mode, data: $data }">
                </tr>
            </tbody>
        </table>

        <script type="text/html" id="display">
            <td data-bind="text: Key"></td>
            <td data-bind="text: Value"></td>
            <td>
                <button class="btn btn-success kout-edit">Edit</button>
                <button class="btn btn-danger kout-delete">Delete</button>
            </td>
        </script>

        <script type="text/html" id="edit">
            <td>
                <input type="text" data-bind="value: Key" /></td>
            <td>
                <input type="text" data-bind="value: Value" /></td>
            <td>
                <button class="btn btn-success kout-update">Update</button>
                <button class="btn btn-danger kout-cancel">Cancel</button>
            </td>
        </script>
    </div>
</body>
</html>

Upvotes: 0

Views: 1396

Answers (3)

Gagan
Gagan

Reputation: 130

Use this

 ko.observable.fn.revertable = function () {

    var self = this, originalValue = self();

    if (!originalValue) {
        self.subscribe(function () {
            originalValue = originalValue || self();
        });
    }

    self.commit = function () {
        originalValue = self();
    };

    self.revert = function () {
        self(originalValue || '');
    };

    self.isDirty = function () {
        return (self() != originalValue);
    };

    return self;
};

and your observables like this

this.text=ko.observable().revertable();

i assume you have cancel function so in that you can do it like

this.text.revert();

and if you want to save those changes then

this.text.commit();

Upvotes: 1

Akhlesh
Akhlesh

Reputation: 2399

I have modified your code little bit.

var mappedItem =
{
 Id: ko.observable(element.Id),
 Key: ko.observable(element.Key),
 Value: ko.observable(element.Value),
 Mode: ko.observable("display"),
 oldData: ko.observable()
};

I have added oldData observable to retain previous data when edit button clicked. So now when you click on cancel data will be restored by "olData" observable. see the below code.

$(document).on("click", ".kout-edit", null, function (ev) {
    var current = ko.dataFor(this);
    current.oldData(ko.toJS(current));
    current.Mode("edit");
});

$(document).on("click", ".kout-update", null, function (ev) {
    var current = ko.dataFor(this);
    current.oldData(null);
    saveData(current);
    current.Mode("display");
});

$(document).on("click", ".kout-cancel", null, function (ev) {
    var current = ko.dataFor(this);
    current.Id(current.oldData().Id);
    current.Value(current.oldData().Value);
    current.Key(current.oldData().Key);
    current.Mode("display");
    current.oldData(null);
});

Here is working example on Jsfiddle

Upvotes: 1

Hans Roerdinkholder
Hans Roerdinkholder

Reputation: 3000

You have the protectedObservable in your code, but you're not using it. Turn your 'model' (the data you want to 'cancel') into a protectedObservable. On cancel, call data.reset(). On save, call data.commit().

Little example (not complete):

        $(document).on("click", ".kout-cancel", null, function (ev) {
           var current = ko.dataFor(this);
           current.reset();
           current.Mode("display");
        });

        $(document).on("click", "#create", null, function (ev) {
            var current = ko.protectedObservable({
                Id: ko.observable(0),
                Key: ko.observable(),
                Value: ko.observable(),
                Mode: ko.observable("edit")
            });
            viewModel.lookupCollection.push(current);
        });

Upvotes: 0

Related Questions