DoneJS StealJS jQuery++ FuncUnit DocumentJS
6.0.1
5.33.2 4.3.0 3.14.1 2.3.35
  • About
  • Guides
  • API Docs
  • Community
  • Contributing
  • Bitovi
    • Bitovi.com
    • Blog
    • Design
    • Development
    • Training
    • Open Source
    • About
    • Contact Us
  • About
  • Guides
  • API Docs
  • Community
  • Contributing
  • GitHub
  • Twitter
  • Chat
  • Forum
  • News
Bitovi

CanJS — Build CRUD apps in fewer lines of code.

  • npm package badge
  • Star
  • Edit on GitHub

CanJS is a JavaScript framework for building CRUD apps in fewer lines of code.

Build CRUD apps in fewer lines of code

Learn how to build this CRUD app

Model layer

Components shouldn’t be concerned with how data is fetched, updated, or cached.

CanJS provides the right abstractions for your model code to be cleanly separated from your UI code. Learn more…

Promises in templates

CanJS’s stache templating language can directly read the state and values from Promises.

No need to write any extra code to determine whether a Promise is pending, resolved, or rejected. Learn more…

{{# if(this.promise.isPending) }}
  Loading…
{{/ if }}
{{# if(this.promise.isRejected) }}
  Error: {{ this.promise.reason }}
{{/ if }}
{{# if(this.promise.isResolved) }}
  Result: {{ this.promise.value }}
{{/ if }}

Real-time list updating

After data is created, updated, or destroyed, CanJS automatically updates your lists for you.

Filtering and sorting are preserved, so you don’t have to manually update your lists or fetch the same data again. Learn more…

We have your back

CanJS is backed by Bitovi, a company built on using and publishing open source software. We answer every question on our Slack and our Discourse forums. We want to help you get started with CanJS!

  • Star
  • Follow @canjs
Slack Discourse

Model layer

With a single line of code, CanJS creates a model that represents the objects returned by a backend API. See how Todo is created by passing a URL to realtimeRestModel().

The model layer is responsible for making GET, POST, PUT, and DELETE requests to your backend. With your component UI code using the model’s standard interface to make requests, if the backend API changes, you only have to configure the model and not change every component that uses that backend API.

By default, CanJS assumes your backend API is RESTful. If your backend API isn’t RESTful, that’s ok! CanJS has configuration options for you to control how it makes requests, parses data, and more.

import { realtimeRestModel } from "can";

const Todo = realtimeRestModel("/api/todos/{id}").ObjectType;

// Get todos sorted by name
const todosPromise = Todo.getList({sort: "name"});
todosPromise.then(todos => {
  // Your backend API might return something like:
  // todos = [ {name: "a"}, {name: "b"}, {name: "c"} ]
});

Promises in templates

CanJS’s stache templating language is similar to Handlebars and Mustache. Wherever you see {{ }} in a template, CanJS evaluates the expression inside to either print a value or perform some basic logic, like #if and #for(of).

Stache is able to read the state and value of Promises. See isPending, isRejected, and isResolved being read on this.todosPromise in the example code? Those return true depending on the current state of the Promise. reason is provided if the Promise is rejected with an error, and value contains the resolved value if the promise succeeds.

These helpers make it much easier to include loading and error states in your app. We promise you’ll love writing your templates this way.

{{# if(this.todosPromise.isPending) }}
    Loading todos…
{{/ if }}
{{# if(this.todosPromise.isRejected) }}
    Error: {{ this.todosPromise.reason.message }}
{{/ if }}
{{# if(this.todosPromise.isResolved) }}
    <ul>
        {{# for(todo of this.todosPromise.value) }}
            <li>
                {{ todo.name }}
            </li>
        {{/ for }}
    </ul>
{{/ if }}

Real-time list updating

Here you can see CanJS’s model layer in action. When Todo.getList({sort: "name"}) is called, CanJS makes a GET request to /api/todos?sort=name

When the array of to-dos comes back, CanJS associates that array with the query {sort: "name"}. When new to-dos are created, they’re added to the list that’s returned automatically, and in the right spot! You don’t have to write any code to make sure the new to-do gets inserted into the right spot in the list.

CanJS does this for filtering as well. If you make a query with a filter (e.g. {filter: {complete: true}}), when items are added, edited, or deleted that match that filter, those lists will be updated automatically.

Save yourself time by not writing code that updates your app’s UI.

import { realtimeRestModel } from "can";

const Todo = realtimeRestModel("/api/todos/{id}").ObjectType;

// Get completed todos
Todo.getList({sort: "name"}).then(todos => {
  // Let’s assume the API came back with
  // todos = [ {name: "a"}, {name: "c"} ]

  // Create a new todo client-side
  const newTodo = new Todo({name: "b"});

  // The todos list is immediately updated with the
  // new to-do in the right place, alphabetically:
  // todos = [ {name: "a"}, {name: "b"}, {name: "d"} ]
});
Take the CRUD Tutorial

Get started with just a few lines of code

Below is an entire app that shows off some of the best features of CanJS:

  • One line of code to create a model from the data returned by a backend API (with realtimeRestModel).
  • isPending, isRejected, isResolved, and value helpers for directly reading the state of a Promise.
  • When you add a to-do, it automatically gets inserted into the list in the right position.

See the Pen CanJS 5 — Basic Todo App by Bitovi (@bitovi) on CodePen.

Type in a new to-do and click “Add” to see it appear in the list. Notice that new to-dos are inserted in alphabetical order, without any code that explicitly inserts the new one in the right place!
Learn how to build this CRUD app

Who Uses CanJS?

Chase Bitovi Apple Delta HP FedEx Tucows

Use DevTools to debug your app

Use the CanJS DevTools to edit your app’s state at runtime, visualize the dependency graphs between elements and state, and debug changes to observables.

Small bundle size

At 72 KB gzipped, CanJS provides all the tools you need at a small size.

Browser support

CanJS supports Internet Explorer 11, Chrome, Edge, Firefox, and Safari.

Sauce Test Status
Take the CRUD Tutorial

CanJS is part of DoneJS. Created and maintained by the core DoneJS team and Bitovi. Currently 6.0.1.

On this page

Get help

  • Chat with us
  • File an issue
  • Ask questions
  • Read latest news