Yuliam Chandra
Yuliam Chandra

Reputation: 14640

How to get jquery validation status with knockout custom binding?

I try to create view model that has no view information, such as calling jquery validation directly from view model before saving / sending the data to server.

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

    self.password = ko.observable();
    self.save = function (form) {
       // I want to prevent any view information call directly from view model.
       if ($(form).isValid()) {
          // $.ajax({});
       }
    };
};
ko.applyBindings(new vm());

@using (Html.BeginForm(null, null, FormMethod.Post, new { data_bind = "submit: save" }))

Also I don't want to recreate knockout validation manually in the view model, because they have been generated by asp.mvc data annotation as jquery validation attributes.

[Required]
[StringLength(100, ErrorMessageResourceName = "ErrorMinStringLength", ErrorMessageResourceType = typeof(Locale), MinimumLength = 6)]
[DataType(DataType.Password)]
public string Password { get; set; }

@Html.PasswordFor(m => m.Password, new { data_bind = "value: Password" })

// Generated html in the browser view source.
<input type="password" name="Password" id="Password" data-val-required="The Password field is required." data-val-length-min="6" data-val-length-max="100" data-val-length="The Password must be at least 6 characters long." data-val="true" data-bind="value: Password">

I have created a simple custom binding that will update the the valid status as follow.

ko.bindingHandlers.jQueryIsValid = {
    init: function (element, valueAccessor) {
        $(element).closest("form").change(function () {
            var observable = valueAccessor();
            var isValid = $(element).valid();
            observable(isValid);
        });
    }
};

And then update the html and view model as follow.

@using (Html.BeginForm(null, null, FormMethod.Post, new { data_bind = "submit: save, jQueryIsValid: isValid" }))

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

    self.password = ko.observable();
    self.isValid = ko.observable();
    self.save = function () {
       if (self.isValid()) {
          // $.ajax({});
       }
    };
};
ko.applyBindings(new vm());

My point is to enforce mvvm pattern where as viewmodel should ideally have no knowledge about the view (like $(form).dosomething). I just not sure that above solution is the best way to do it. I might miss something about custom binding or existing knockout feature since I'm new to knockout.

Could anybody show the right / best way to do it?

Upvotes: 2

Views: 917

Answers (1)

Michael Papworth
Michael Papworth

Reputation: 453

The custom binding is unnecessary. The view-model doesn't need to be aware of the forms validity. The point being that save should only ever be called on a valid form. Also since you intend to replace the submit behaviour with an AJAX call you will need to ensure that upon clicking a submit button the form is not posted back.

You can achieve this as follows...

$('form').submit(function(e){
    if ($(this).valid()) {
        viewModel.save();
        e.preventDefault();
    }
});

Upvotes: 1

Related Questions