DoneJS StealJS jQuery++ FuncUnit DocumentJS
3.14.1
5.0.0 4.3.0 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
    • Observables
      • can-compute
      • can-define
      • can-define/list/list
      • can-define/map/map
      • can-define-stream
      • can-define-stream-kefir
      • can-event
      • can-event/async/async
      • can-event/batch/batch
      • can-event/lifecycle/lifecycle
      • can-kefir
      • can-list
      • can-map
      • can-map-backup
      • can-map-define
      • can-observation
      • can-observe
      • can-simple-map
      • can-simple-observable
      • can-stream
      • can-stream-kefir
    • Data Modeling
      • can-connect
      • can-connect-cloneable
      • can-connect-feathers
      • can-connect-ndjson
        • options
          • ndjson
        • DefineList methods
          • isStreaming
          • streamError
      • can-connect-signalr
      • can-fixture
      • can-fixture-socket
      • can-ndjson-stream
      • can-set
    • Views
      • can-component
      • can-ejs
      • can-element
      • can-react-component
      • can-stache
      • can-stache/helpers/route
      • can-stache-bindings
      • can-stache-converters
      • can-view-autorender
      • can-view-callbacks
      • can-view-href
      • can-view-import
      • can-view-live
      • can-view-model
      • can-view-nodelist
      • can-view-parser
      • can-view-scope
      • can-view-target
      • react-view-model
      • react-view-model/component
      • steal-stache
    • Routing
      • can-deparam
      • can-param
      • can-route
      • can-route-pushstate
    • JS Utilities
      • can-assign
      • can-define-lazy-value
      • can-globals
      • can-key-tree
      • can-make-map
      • can-parse-uri
      • can-string
      • can-string-to-any
      • can-util
      • can-zone
      • can-zone-storage
    • DOM Utilities
      • can-ajax
      • can-attribute-encoder
      • can-control
      • can-dom-events
      • can-event-dom-enter
      • can-event-dom-radiochange
      • can-jquery
    • Data Validation
      • can-define-validate-validatejs
      • can-validate
      • can-validate-interface
      • can-validate-legacy
      • can-validate-validatejs
    • Typed Data
      • can-cid
      • can-construct
      • can-construct-super
      • can-namespace
      • can-reflect
      • can-reflect-promise
      • can-types
    • Polyfills
      • can-symbol
      • can-vdom
    • Core
    • Infrastructure
      • can-global
      • can-test-helpers
    • Ecosystem
    • Legacy
  • Community
  • Contributing
  • GitHub
  • Twitter
  • Chat
  • Forum
  • News
Bitovi

can-connect-ndjson

  • npm package badge
  • Star
  • Edit on GitHub

Get a list of data from an NDJSON service endpoint.

ndjsonStream( baseConnection )

Overwrites the getListData and [can-connect/constructor.hydrateList] methods on the can-connect base connection to enable NDJSON streaming using Fetch with ReadableStreams. Falls back to default baseConnection in browsers that do not support Fetch and ReadableStream.

Use

In this example, we will connect a DefineMap model to an NDJSON stream service. If you prefer to use a non-CanJS type, skip step 1 and modify the behaviors in step 2 (can/map in particular) to suit your data structure.

Follow these steps to get started:

1. Define a model.

import DefineList from "can-define/list/list";
import DefineMap from "can-define/map/map";

// Define model
const Todo = DefineMap.extend( "Todo", { id: "number", name: "string" } );
Todo.List = DefineList.extend( "TodoList", { "#": Todo } );

2. Include the required behaviors.

These four behaviors are the minumum required behaviors if you choose to use DefineMaps and DefineLists for the model layer. can-connect is flexible and can be used with any array-like type.


//Define required behaviors, including can-connect-ndjson
const behaviors = [
    require( "can-connect/data/url/url" ),
    require( "can-connect/constructor/constructor" ),
    require( "can-connect/can/map/map" ),
    require( "can-connect-ndjson" ) //require NDJSON behavior
];

3.Create can-connect connection.

Link can-connect to the model by attaching a connection object. The connection object is created by calling connect with the behaviors and options. You may need to pass an NDJSON-specific endpoint option if the backend serves NDJSON from a different URL.

import connect from "can-connect";

// Create connection and pass the optional NDJSON API endpoint
Todo.connection = connect( behaviors, {
    Map: Todo,
    List: Todo.List,
    url: "/other/endpoint",
    ndjson: "/api" //declare the NDJSON API endpoint here
} );

4. Use the can-connect methods on the model.

getList now uses a ReadableStream response behind the scenes. NDJSON lines read from the stream will be pushed into the list instance as JavaScript objects.

let todoListPromise = Todo.getList( {} );

The todoListPromise will return the list as soon as the streaming response starts. At that time the list is usually empty since the response has just begun. Afterwards, as JSON lines are streamed from the response, instances are created from each line and added to the list, one at a time.

If using the raw data below, each Todo instance in the list will contain the properties from a line, eg. {"name":"first", "id": 1}

//NDJSON raw data example
{"name":"first", "id": 1}\n
{"name":"second", "id": 2}\n
{"name":"third", "id": 3}\n
{"name":"fourth", "id": 4}\n

5. Use the model with a template.

Use can-stache or your favorite live-binding template language to attach your data to the DOM.

import stache from "can-stache";

const template = stache( "<ul>{{#each todos}}<li>{{name}}</li>{{/each}}</ul>" );

todoListPromise.then( list => {
    document.body.append( template( { todos: list } ) );
} );

Though the list is initially empty, the template will update with new li elements each time the list is updated with a newly streamed line.

All together

We use our ndjsonStream behavior to enable our model to work seamlessly with a stream of NDJSON, which it will parse into an array of JS objects.

Note:

  • you must pass the ndjsonStream behavior
  • if no ndjson option is passed, the endpoint accessed by getListData will default to the url.
import connect from "can-connect";
import DefineList from "can-define/list/list";
import DefineMap from "can-define/map/map";
import stache from "can-stache";

//Define template
const template = stache( "<ul>{{#each todos}}<li>{{name}}</li>{{/each}}</ul>" );

// Define model
const Todo = DefineMap.extend( "Todo", { id: "number", name: "string" } );
Todo.List = DefineList.extend( "TodoList", { "#": Todo } );

//Define required behaviors, including can-connect-ndjson
const behaviors = [
    require( "can-connect/data/url/url" ),
    require( "can-connect/constructor/constructor" ),
    require( "can-connect/can/map/map" ),
    require( "can-connect-ndjson" ) //require NDJSON behavior
];

// Create connection and pass the NDJSON API endpoint
Todo.connection = connect( behaviors, {
    Map: Todo,
    List: Todo.List,
    url: "/other/endpoint",
    ndjson: "/api" //declare the NDJSON API endpoint here
} );

let todoListPromise = Todo.getList( {} );

todoListPromise.then( list => {
    document.body.append( template( { todos: list } ) );
} );

Fallback for browsers without fetch and stream support

In browsers that don't support fetch and streams, this module will fall back to the baseConnection configuration. The baseConnection and will do a GET request to the url endpoint and expects to receive JSON data.

Note: the stream state properties such as streamError or isStreaming are not available when falling back.

Try out the demo to see how to works.

Using fetch with NDJSON and ReadableStreams

Learn more about using the fetch API with NDJSON and ReadableStreams here.

Parsing a stream of NDJSON to a stream of JS Objects

Learn about how we parse the NDJSON stream into a ReadableStream of JS objects using can-ndjson-stream.

Creating an NDJSON service using Express

Checkout this tutorial or the can-ndjson-stream module documentation.

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

On this page

Get help

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