knockout-observable-promise

A knockout observable extension to automatically, transparently chain onto promises

Usage no npm install needed!

<script type="module">
  import knockoutObservablePromise from 'https://cdn.skypack.dev/knockout-observable-promise';
</script>

README

knockout-observable-promise

Easily wire up promises to knockout

Build Status

Working with data from our server, we often want to show loading status or want to chain other work dependent on an asyncrounous task. knockout-observable-promise is observable extender that will wire up to a promise automatically if it is assigned one.

Examples

var name = ko.observable(),
    age = ko.observable(),
    user = ko.observable()

ko.applyBindings(document.body, {
  name: name,
  age: age,
  user: user,

  findUser: ko.computed(function() {
    if (name() && age()) {
      return $.get({
        url: '/users/search', 
        data: {
          name: name(),
          age: age()
        }
      }).then(function(resp) {
        user(resp.data)
      })
    } else {
      return $.Deferred().promise()
    }
  }).extend({ throttle: 100, promise: true })
})

View:

<style>.loading { background-image: url(loading.gif); }</style>
<form>
  <h1>Search for a person</h1>
  <label for="name">Name</label>
  <input name="name" data-bind="value: name"></input>
  <label for="age">Age</label>
  <input name="age" data-bind="value: age"></input>

  <div data-bind="css: { loading: findUser().state() === 'pending' }">
    <!-- ko if: $root.user() -->
      <p data-bind="text: 'found user ' + $root.user().username">
    <!-- /ko -->
  </div>
  <p class="error" data-bind="visible: findUser().state() === 'rejected'">An error occoured looking for that user!</p>
</form>

You can optionally have the observable convert to the resolve or rejected value if that is convient to you

var name = ko.observable(),
    age = ko.observable

ko.applyBindings(document.body, {
  name: name,
  age: age,

  user: ko.computed(function() {
    return lookupUser(name(), age())
  }).extend({ throttle: 100, promise: { convert: true } })
})

View:

<style>.loading { background-image: url(loading.gif); }</style>
<form>
  <h1>Search for a person</h1>
  <label for="name">Name</label>
  <input name="name" data-bind="value: name"></input>
  <label for="age">Age</label>
  <input name="age" data-bind="value: age"></input>

  <div data-bind="css: { loading: user() && user().state && user().state() === 'pending' }">
    <!-- ko if: $root.user().username -->
      <p data-bind="text: 'found user ' + $root.user().username">
    <!-- /ko -->
  </div>
  <p class="error" data-bind="visible: user() && user().state && user().state() === 'rejected'">
    An error occoured looking for that user!
  </p>
</form>

Differences from ko.promise

ko.promise intends to make observables and promises the same object, letting you use them interchangably for cases when you do have one asyncrounous operation to model. That's not the goal of knockout-observable-promise - the observable is not a promise, nor does it have to be, and it can assigned new promises that are wired up again in the future, whereas ko.promise cannot since once a promise is resolved or rejected, it cannot change - a promise is an async operation, not a pub-sub mechanism. They are different problems, so choose the library that you need.