0

I have a view model that has the observable "yearsOld" which is bound to an html input.

<input type="text" data-bind="value:yearsOld">

    var viewModel = {
      yearsOld: ko.observable("");
    }

Is there any way to add a css class to the input from the viewModel? The reason I'm asking is because I need to add a css class named "positive-integer" to the input bound to yearsOld so that my 3rd party jQuery library will restrict non-numeric input on that bound input field.

Note: I'm aware of the css binding that knockout provides to place on a input field, but that doesn't help me here since the css is not necessarily dynamic. I'm just hoping to be able to put a css class on the input from the viewModel instead of putting it directly on each individual input. Even if this doesn't make sense to you, I'm just curious if it is possible.

3 Answers 3

2

It certainly is possible, and you'd do it via the css binding. I don't understand why you think the css binding won't work for you.

Here's how I'd do it:

<input data-bind="value: yearsOld, css: { 'positive-integer': positiveIntegersOnly }" />

var viewModel = {
   yearsOld: ko.observable(),
   positiveIntegersOnly: ko.observable(false)
}

To apply the 'positive-integer' class:

viewModel.positiveIntegersOnly(true);
Sign up to request clarification or add additional context in comments.

Comments

1

At first my answer was no, this is not possible. But after some research I have discovered that it is entirely possible.

Using the wonderful answer from this question here: knockoutjs overriding bindinghandlers you are able to override the behaviour of the value binding, and add the desired behaviour necessary.

var originalInit = ko.bindingHandlers.value.init,
    originalUpdate = ko.bindingHandlers.value.update;

ko.bindingHandlers.value= {
    init: originalInit,
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var $element = $(element);
        var value = ko.utils.unwrapObservable(valueAccessor());
        // only apply to inputs, and if value is a number and is greater than 0
        if ($element.prop("tagName").toLowerCase() == "input" && !isNaN(value) && value > 0) {
            $element.addClass('positive-integer');
        }
        else {
            // otherwise ensure the class is removed
            $element.removeClass('positive-integer');
        }
        // call the original update function
        originalUpdate(element, valueAccessor, allBindingsAccessor, viewModel);
    }
};

This code will run before the regular value: binding code, and update your elements class (jQuery is needed, but only because I am lazy - should be easily converted if necessary).

Full working JS fiddle available here: http://jsfiddle.net/sp3uF/

Comments

0

You want the next scenario: user enters some non-numeric and your input changes the style?

Two ways: jQuery and css binding:

//jQuery
var viewModel = {
    hasNonNumeric: function(){//not implemented},
    yearsOld: ko.observable(),
    yearsOld.subscribe(function(newValue) {
        if (this.hasNonNumeric(newValue)) {
            $('input').addClass("positive-integer");
        }
        else {
            $('input').removeClass("positive-integer");
        }
    });
}​

//knockout
var viewModel = {
        hasNonNumeric: function() { //not implemented},
        yearsOld: ko.observable(),
        scareUser: ko.computed(function() {
            var result = false;
            if (this.hasNonNumeric(this.yearsOld())) {
                result = true;
            }            
            return result;
        });
    }​

<input data-bind="value: yearsOld, css: { 'positive-integer': scareUser}" />

3 Comments

Doing $('input').addClass("positive-integer"); would change ALL input elements on the page to have/not have this class whenever you edit yearsOld to satisfy hasNonNUmeric()
I used it just for example. You can use any selector you need: $('#theinput').
Ok! Just thought it was worth pointing out so someone doesn't fall into that trap

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.