user3378165
user3378165

Reputation: 6896

Reset observable form fields Knockout

On my MVC project I have a View with 3 forms and one KO ViewModel.

On each form I have a reset button to clear its own fields.

I can't use input type="reset" because it doesn't update the observable values.

I can't either reset the View Model because that will reset all the observables of the View Model and I only need to reset the ones that are on the form that triggered the reset.

I can write 3 functions, one for each form and manually deleting each form fields like this:

this.onForm1Reset = function () {
    this.field1('');
    this.field2('');
    //etc..
}

this.onForm2Reset = function () {
    this.field3('');
    this.field4('');
    //etc..
}

this.onForm3Reset = function () {
    this.field5('');
    this.field6('');
    //etc..
}

But I'm looking for a more global and a shorter solution.

I made a lot of researches online but couldn't find a good solution for that.

Any help would be very much appreciated.

Upvotes: 3

Views: 3341

Answers (4)

Roy J
Roy J

Reputation: 43881

If you can group the forms' fields, you can use a with binding on each form to provide a different context to the form members, so the reset function (as a click handler) attached to a reset button will only be looking at the observables for its own form.

If you can't group the fields, a (less-preferred) possibility would be to run through the bound elements of the form containing the reset button, reset their values, and fire the change events for them. The commented-out code in my snippet would do that.

vm = {
    fieldset1: {
      field0: ko.observable(),
      field1: ko.observable()
    },
    fieldset2: {
      field2: ko.observable(),
      field3: ko.observable()
    },
    fieldset3: {
      field4: ko.observable(),
      field5: ko.observable()
    },
    reset: function(data) {
      for (var key in data) {
        if (data.hasOwnProperty(key)) {
          data[key]('');
        }
      }
    };

    ko.applyBindings(vm);

    /*
    $('body').on('click', '[type="reset"]', function() {
      $(this.parentNode).find('[data-bind*="value:"]').each((index, item) => {
        $(item).val('').change();
      });
    });
    */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<form data-bind="with: fieldset1">
  <input data-bind="value:field0" />
  <input data-bind="value:field1" />
  <input type="reset" data-bind="click: $parent.reset" />
</form>

<form data-bind="with: fieldset2">
  <input data-bind="value:field2" />
  <input data-bind="value:field3" />
  <input type="reset" data-bind="click: $parent.reset" />
</form>

<form data-bind="with: fieldset3">
  <input data-bind="value:field4" />
  <input data-bind="value:field5" />
  <input type="reset" data-bind="click: $parent.reset" />
</form>

Upvotes: 4

Aurora
Aurora

Reputation: 282

Would something like this work? Where you have a function to empty observables? Depending on the click of reset?

this.emptyObservablesRestForm1 = function () {
   this.field1(false);
}


this.emptyObservablesRestForm2 = function () {
       this.field2(false);
    }

Upvotes: 0

jbin
jbin

Reputation: 166

You might also want to consider splitting your ViewModel into one separate VM per Form(Group of fields).
Using this approach you coud reset a Form by recreating the respective ViewModel.

Upvotes: 1

haim770
haim770

Reputation: 49095

A more practical solution would be to contain your view-model in an observable, and re-create the model upon resetting:

function MyViewModel()
{
    this.field1 = ko.observable();
    this.field2 = ko.observable();

    // etc...
}

var model = {
    data: ko.observable(new MyViewModel()),
    reset: function() {
        model.data(new MyViewModel());
    }
};

ko.applyBindings(model);

And in your HTML:

<body data-bind="with: data">
    ...
    <button data-bind="click: $root.reset">Reset</button>
</body>

See Fiddle

Update (as per your comment):

Since you don't want to replace the entire view-model but only reset certain fields, I assume you'll have to introduce a reset() method to your model:

function MyViewModel()
{
    this.field1 = ko.observable();
    this.field2 = ko.observable();

    this.reset = function() {
        this.field1('');
        this.field2('');
    }.bind(this);
}

ko.applyBindings(new MyViewModel());

And in your HTML:

<button data-bind="click: reset">Reset</button>

Upvotes: 1

Related Questions