Search code examples
validationknockout.jsknockout-validation

Dynamic Knockout Validation not showing error message


I have a property on my view model that only requires to be validated under certain conditions.

It's working fine in the sense that, when I check the console for viewModel.errors() it's showing me the error in there, however the message is never showing up on the page. It works if I extend my observable to begin with, but if I remove the validation and put it back on it won't show the error message on the page anymore.

In the example below, if you load the code/jsfiddle, click on the "Enable Required" button and then on "Show Errors" you'll see it throws the error correctly but won't show the error message. I've tried this with and without the customMessageTemplate (my live tool uses the customMessageTemplate though).

Also one thing this jsfiddle does that my live tool doesn't is throw an error when trying to disable required state, not quite sure why it's doing that. And the self.errors field isn't being populated with the errors but with a function which doesn't happen in any of my other validation models.

The only main difference between the code below and my live build uses a ko.computed property to update whether my self.features needs validation or not, instead of using a function but the end result is the same.

Here's a jsfiddle of my issue.

And here's the code:

<div id='container'>
    <select data-bind="value: feature, options: features, optionsCaption: 'Select'"></select>

    <br/>

    <button data-bind='click: attachRequired'>Enable Required</button>
    <button data-bind='click: removeRequired'>Disable Required</button>
    <button data-bind='click: showMessages'>Show errors</button>

</div>

<script id="customMessageTemplate" type="text/html">
    <em class="customMessage" data-bind='validationMessage: field'></em>
</script>

ko.validation.configure({
    //decorateElement: true,
    registerExtenders: true,
    messagesOnModified: true,
    insertMessages: true,
    parseInputAttributes: true,
    messageTemplate: 'customMessageTemplate'
});


function viewModel(){
    var self = this;

     self.errors = ko.validation.group(self, {
        deep: false,
        observable: false
    });

    self.feature = ko.observable();
    self.feature.subscribe(function () {
        alert(self.feature());
    })
    self.features = ["test1", "test2", "test3"];

    self.attachRequired = function () {
        self.feature.extend({
            required: {
                message: 'please select a feature'
            }
        })  
    };

    self.removeRequired = function () {
        self.feature.extend({ validatable: false });
    };

    self.showMessages = function () {
        self.errors.showAllMessages();
        alert(self.errors().length ? "error" : "no errors");
    };
}


var model = new viewModel();

ko.applyBindings(model);

Solution

  • Well.. after trying for 2 hours I decided to make this post... and of course 5 minutes after submitting it I ended up figuring it out...

    Bare in mind trying to enable/disable validation should work, I haven't quite figured out why the message is not showing up. But regardless there's a much simpler and elegant solution:

    Since my validation was based on whether another property had a value I can use the onlyIf option of ko validation:

    self.feature = ko.observable().extend({
        required: {
            message: 'please select a feature',
            onlyIf: function () {
                return self.propertyToCheckFor() == true;
            }
        }
    });
    

    This enables/disables validation on the fly if the check is done on an observable and the validation error message shows up just fine!