1
votes

I have the following class which validates the name and doesn't let the user put an empty name. With it I can get the valid value and notify the user if the input is invalid (preserving the last good value).

class @Person
  constructor: (name) ->
    @name = ko.observable name
    @nameLastInvalid = ko.observable false
    @nameAttempt = ko.computed
      read: @name
      write: (value) =>
        if value.length > 0
          @name value
          @nameLastInvalid false
        else
          @nameLastInvalid true
      owner: @

I want to make the same functionality more reusable. Is there a way to extend the ko.observable object to add the 'lastInvalid' and 'attempt' methods?

Something like:

class @Person
  constructor: (name) ->
    @name = ko.observable(name).extend({ required: true })

And then be able to do:

person.name()
person.name().lastInvalid()
person.name().attempt()

AFAIK knockout-validation doesn't work this way. It lets you put the invalid value and then tells you if it's valid or not.

Update:

I added the following extender but it doesn't seem to do anything (I get name.attempt is undefined)

ko.extenders.required = (target, option) ->
  target.lastInvalid = ko.observable false
  target.attempt = ko.computed ->
    read: target
    write: (value) ->
      if value.length > 0
        target value
        target.lastInvalid false
      else
        target.lastInvalid true
  target
1

1 Answers

1
votes

You extender is partiality not working because you have an extra -> in the attempt definition. Because when you want to provide the read, write function to an computed you need to provide an object literal and not a function:

target.attempt = ko.computed
    read: target
    write: (value) ->
      if value.length > 0
        target value
        target.lastInvalid false
      else
        target.lastInvalid true
  target

And you try to access the additional properties from the underlying value not from the observable itself. So you need to write:

person.name()
person.name.lastInvalid()
person.name.attempt()

Demo JSFiddle.