# Reject Invalid Values in Knockout Observables

**Date:** 2017-09-07  
**Author:** Kees C. Bakker  
**Categories:** JavaScript  
**Tags:** Knockout  
**Original:** https://keestalkstech.com/conditioning-knockout-observable-reject-values/

![Reject Invalid Values in Knockout Observables](https://keestalkstech.com/wp-content/uploads/2017/09/william-bout-264826.jpg)

---

Wouldn't it be nice if we could restrict the value written to a Knockout observable? Some values might mess up your model completely while others just don't make sense. So how can we create a conditioned observable that rejects invalid values? It turns out that conditioning an observable is not so hard.

This approach is deliberately strict: after normalization, it rejects every value that does not satisfy the condition.

[outline]

## A small example: Sudoku

Let's think of a Sudoku cell. Its value must be a number from 1 through 9. Its valid values also depend on the numbers already used in the same row and column (orange) and the box the cell is in (purple).

![Not allowed due to row and column: 1, 2, 3, 4, 6, 7, 8, 9. Not allowed due to box: 2, 3, 6, 8. Allowed: 5.](https://keestalkstech.com/wp-content/uploads/2017/09/Conditioned-Cell-Sudoku.jpg)
*The restrictions for a Sudoku cell visualized:Not allowed due to row and column: 1, 2, 3, 4, 6, 7, 8, 9.Not allowed due to box: 2, 3, 6, 8. Allowed: 5.*

## The Cell

We can model this Sudoku cell as a class with options and a value. Options can be removed from the cell. This is useful when an option is no longer possible because a related cell has changed. When a value is set, the cell should check whether that value is still an option.

```js
class Cell {

  constructor() {
    this.options = ko.observableArray([1,2,3,4,5,6,7,8,9]);
    this.value = ko.observable(null);
  }

}
```

How can we restrict that number?

## Conditioned Observable

Let's extend Knockout with a `conditionedObservable` that takes an initial value, a condition, and an optional normalizer.

### Inner workings

The basic idea comes from [this post by Ryan Niemeyer](https://www.knockmeout.net/2011/03/guard-your-model-accept-or-cancel-edits.html). Building the conditioned observable works as follows:

### Implementation

Here's the implementation:

```js
ko.conditionedObservable = function(
    initialValue,
    condition,
    normalize
){
    let obi = ko.observable(initialValue);
    let computer = ko.computed({
        owner: this,
        read: () => obi(),
        write: (newValue) => {

            //unwrap and normalize the value
            let value = ko.unwrap(newValue);
            let normalizedValue = normalize
                ? normalize(value)
                : value;

            //check condition
            if(condition(normalizedValue)){

                //set it to the observable
                obi(normalizedValue);
            }
            else {
                //reset the value
                computer.notifySubscribers(computer());
            }
        }
    });

    return computer;
};
```

Looks pretty simple. Yet it is very effective.

### Conditioning in action

Let's add it to the `Cell` class. The observable is now conditioned to allow only a `null` value or values that are still available in the `options` array. The normalizer converts numeric strings to numbers before they are validated and stored.

```js
class Cell {

  constructor() {
    this.options = ko.observableArray([1,2,3,4,5,6,7,8,9]);
    this.value = ko.conditionedObservable(
      null,
      (value) => value == null || this.options().indexOf(value) > -1,
      (value) => value == null || value === "" ? null : Number(value)
    );
  }

}
```

Notice how the [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) captures `this`, allowing it to access `this.options`.

## Summary

Knockout is a versatile MVVM framework that you can extend with features like conditioned observables. With a few lines of code, you can add constraints to your observables. Conditioning made easy.

## Changelog

- 2026-07-19: Converted the examples from TypeScript to JavaScript, added input normalization, corrected rejected-value notifications and Sudoku constraints, and updated outdated links.
- 2017-09-07: Initial article.
