From 0e50e99c5981a6968001c86d1c34916d2ded9f45 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 29 Jun 2012 15:41:10 +0100 Subject: [PATCH 01/10] [be/dataproxy][xs]: dataproxy timeout is now configurable (defaults to 5s). --- src/backend.dataproxy.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend.dataproxy.js b/src/backend.dataproxy.js index ac3eeab3..58f537d7 100644 --- a/src/backend.dataproxy.js +++ b/src/backend.dataproxy.js @@ -6,6 +6,9 @@ this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {}; my.__type__ = 'dataproxy'; // URL for the dataproxy my.dataproxy_url = 'http://jsonpdataproxy.appspot.com'; + // Timeout for dataproxy (after this time if no response we error) + // Needed because use JSONP so do not receive e.g. 500 errors + my.timeout = 5000; // ## load // @@ -48,12 +51,11 @@ this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {}; // a crude way to catch those errors. var _wrapInTimeout = function(ourFunction) { var dfd = $.Deferred(); - var timeout = 5000; var timer = setTimeout(function() { dfd.reject({ - message: 'Request Error: Backend did not respond after ' + (timeout / 1000) + ' seconds' + message: 'Request Error: Backend did not respond after ' + (my.timeout / 1000) + ' seconds' }); - }, timeout); + }, my.timeout); ourFunction.done(function(arguments) { clearTimeout(timer); dfd.resolve(arguments); From 12f6afebc90f9b54f5fe2e916b3ff7f6d1842523 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 29 Jun 2012 15:49:43 +0100 Subject: [PATCH 02/10] [#168,docs/backend][s]: bring backend example up to date. --- docs/backends.markdown | 8 ++++++++ example-backends.markdown | 15 +++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/backends.markdown b/docs/backends.markdown index a7af4a04..72e22069 100644 --- a/docs/backends.markdown +++ b/docs/backends.markdown @@ -11,11 +11,19 @@ root: ../ +Backends connect Dataset and Documents to data from a specific 'Backend' data +source. They provide methods for loading and saving Datasets and individuals +Documents as well as for bulk loading via a query API and doing bulk transforms +on the backend. + Backends come in 2 flavours: 1. Loader backends - only implement fetch method. The data is then cached in a Memory.Store on the Dataset and interacted with there. This is best for sources which just allow you to load data or where you want to load the data once and work with it locally. 2. Store backends - these support fetch, query and, if write-enabled, save. These are suitable where the backend contains a lot of data (infeasible to load locally - for examples a million rows) or where the backend has capabilities you want to take advantage of. + +# Backend API + Backend modules must implement the following API: {% highlight javascript %} diff --git a/example-backends.markdown b/example-backends.markdown index 918156ba..cf754c1c 100644 --- a/example-backends.markdown +++ b/example-backends.markdown @@ -30,20 +30,18 @@ source. They provide methods for loading and saving Datasets and individuals Documents as well as for bulk loading via a query API and doing bulk transforms on the backend. -You can instantiate a backend directly e.g. +You can use a backend directly e.g. {% highlight javascript %} -var backend = recline.Backend.ElasticSearch(); +var backend = recline.Backend.ElasticSearch.fetch({url: ...}); {% endhighlight %} But more usually the backend will be created or loaded for you by Recline and all you need is provide the identifier for that Backend e.g. {% highlight javascript %} var dataset = recline.Model.Dataset({ - ... - }, - 'backend-identifier' -); + backend: 'backend-identifier' +}); {% endhighlight %}
@@ -53,7 +51,6 @@ How do you know the backend identifier for a given Backend? It's just the name o ### Included Backends -* [memory: Memory Backend (local data)](docs/backend/memory.html) * [elasticsearch: ElasticSearch Backend](docs/backend/elasticsearch.html) * [dataproxy: DataProxy Backend (CSV and XLS on the Web)](docs/backend/dataproxy.html) * [gdocs: Google Docs (Spreadsheet) Backend](docs/backend/gdocs.html) @@ -71,8 +68,6 @@ This is as per the [quickstart](example-quickstart.html) but the set of files is - - @@ -110,5 +105,5 @@ a bespoke chooser and a Kartograph (svg-only) map. ## Writing your own backend Writing your own backend is easy to do. Details of the required API are in the -[Backend documentation](docs/backend/base.html). +[Backend documentation](docs/backends.html). From 889fb6afb130618202bef4c78137433d25629a14 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 29 Jun 2012 16:40:22 +0100 Subject: [PATCH 03/10] [docs,refactor][s]: move examples to being tutorials in the docs directory. --- docs/index.html | 4 ++-- example-backends.markdown => docs/tutorial-backends.markdown | 1 + example-quickstart.markdown => docs/tutorial-views.markdown | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) rename example-backends.markdown => docs/tutorial-backends.markdown (99%) rename example-quickstart.markdown => docs/tutorial-views.markdown (96%) diff --git a/docs/index.html b/docs/index.html index caadbff8..7f7f7ece 100644 --- a/docs/index.html +++ b/docs/index.html @@ -52,12 +52,12 @@ root: ../
diff --git a/example-backends.markdown b/docs/tutorial-backends.markdown similarity index 99% rename from example-backends.markdown rename to docs/tutorial-backends.markdown index cf754c1c..189970dd 100644 --- a/example-backends.markdown +++ b/docs/tutorial-backends.markdown @@ -2,6 +2,7 @@ layout: container title: Library - Example - Loading data from different sources using Backends recline-deps: true +root: ../ --- \
\
\ - {{docCount}} records\ + {{recordCount}} records\
\ diff --git a/docs/models.markdown b/docs/models.markdown index 05ec1976..676dbcb2 100644 --- a/docs/models.markdown +++ b/docs/models.markdown @@ -21,7 +21,7 @@ holding summary information about a Field (or multiple Fields). All the models are Backbone models, that is they extend Backbone.Model. Note, however that they do not 'sync' (load/save) like normal Backbone models. -## Dataset +

Dataset

A Dataset is *the* central object in Recline. Standard usage is: @@ -159,7 +159,6 @@ field's value (if any) and the current record. It's signature and behaviour is the same as for renderer. -

Query

Query instances encapsulate a query to the backend (see

Loading data from different sources using Backends +
+ These set of examples will show you how you can load data from different +sources such as Google Docs or the DataHub using Recline

-These set of examples will show you how you can load data from different -sources such as Google Docs or the DataHub using Recline.

Note: often you are loading data from a given source in -order to display it using the various Recline views. However, you can also -happily use this data with your own code and app and this is a very common -use-case.

-

Moreover, Recline is designed so you need only include the -backend and its dependencies without needing to include any of the dependencies -for the view portion of the Recline library.

+order to load it into a Recline Dataset and display it in a View. However, you can also +happily use a Backend to load data on its own without using any other part of the Recline library as all the Backends are designed to have no dependency on other parts of Recline.

## Overview @@ -61,7 +58,7 @@ Backend not on this list that you would like to see? It's very easy to write a n ## Preparing your app -This is as per the [quickstart](example-quickstart.html) but the set of files is much more limited if you are just using a Backend. Specifically: +This is as per the [quickstart](tutorial-views.html) but the set of files is much more limited if you are just using a Backend. Specifically: {% highlight html %} diff --git a/docs/tutorial-basics.markdown b/docs/tutorial-basics.markdown new file mode 100644 index 00000000..2705c814 --- /dev/null +++ b/docs/tutorial-basics.markdown @@ -0,0 +1,170 @@ +--- +layout: container +title: Tutorial - Dataset Basics +recline-deps: true +root: ../ +--- + + + +## Preparations + +1. [Download ReclineJS]({{page.root}}download.html) and relevant dependencies. + +2. Include the core dependencies for the Dataset model + + {% highlight html %} + + + + +{% endhighlight %} + +## Creating a Dataset + +Here's the example data We are going to work with: + +{% highlight javascript %} +{% include data.js %} +{% endhighlight %} + +In this data we have 6 records / rows. Each record is a javascript object +containing keys and values (values can be 'simple' e.g. a string or float or arrays or hashes - e.g. the geo value here). + +
+ +We can now create a recline Dataset object from this raw data: + +{% highlight javascript %} +var dataset = new recline.Model.Dataset({ + records: data +}); +{% endhighlight %} + + + +## Records, Fields and more + +Now that we have created a Dataset, we can use it. + +For example, let's display some information about the Dataset and its records: + +
You can find out more about Dataset and Records in the reference documentation
+ +{% highlight javascript %} +{% include tutorial-basics-ex-1.js %} +{% endhighlight %} + +Here's the output: + +
 
+ + + +Note how the last geo attribute just rendered as `[object Object]`. This is because the Dataset is treating that field value as a string. Let's now take a look at the Dataset fields in more detail. + +### Fields + +In addition to Records, a Dataset has Fields stored in the `fields` attribute. Fields provide information about the fields/columns in the Dataset, for example their id (key name in record), label, type etc. + +The Dataset's fields will be automatically computed from records or provided by the backend but they can also be explicitly provided and configured. Let's take a look at the fields on the dataset at present using the following code: + +{% highlight javascript %} +{% include tutorial-basics-ex-fields.js %} +{% endhighlight %} + +Running this results in the following: + +
 
+ + + +As can be seen all fields have the default type of 'string'. Let's change the geo field to have type geo\_point and see what affect that has on displaying of the dataset (for good measure we'll also set the label): + +{% highlight javascript %} +{% include tutorial-basics-ex-fields-2.js %} +{% endhighlight %} + +
 
+ + + +As can be seen the rendering of the field has changed. This is because the `recordSummary` method uses the Record.getFieldValue function which in turn renders a record field using the Field's renderer function. This function varies depending on the type and can also be customized (see the Field documentation). + + +## Querying + +The basic thing we want to do with Datasets is query and filter them. This is very easy to do: + +{% highlight javascript %} +{% include tutorial-basics-ex-2.js %} +{% endhighlight %} + +This results in the following. Note how recordCount is now 3 (the total number of records matched by the query) but that currentRecords only contains 2 records as we restricted number of returned records using the size attribute. + +
 
+ + + +Full details of the query structure and its options can be found in the reference documentation. + +Also worth noting is that the last run query is stored as a Query instance in the `queryState` attribute of the Dataset object. Modifying `queryState` will also resulting in a query being run. This is useful when building views that want to display or manage the query state (see, for example, Query Editor or Filter Editor widgets). + + +## Listening for Events + +Often you'll want to listen to events on Datasets and its associated objects rather than have to explicitly notify. This is easy to do thanks to the use of Backbone model objects which have a [standard set of events](http://backbonejs.org/#FAQ-events). + +Here's an example to illustrate: + +{% highlight javascript %} +{% include tutorial-basics-ex-events.js %} +{% endhighlight %} + +
 
+ + + +Here's a summary of the main objects and their events: + +* Dataset: + + * Standard Backbone events for changes to attributes (note that this will **not** include changes to records) + * *query:start / query:end* called at start and completion of a query + +* Dataset.currentRecords: Backbone.Collection of "current" records (i.e. those resulting from latest query) with standard Backbone set of events: *add, reset, remove* + +* Dataset.queryState: queryState is a Query object with standard Backbone Model set of events + +* Dataset.fields: Backbone Collection of Fields. + diff --git a/docs/tutorial-views.markdown b/docs/tutorial-views.markdown index 750bb065..7e22f018 100644 --- a/docs/tutorial-views.markdown +++ b/docs/tutorial-views.markdown @@ -17,7 +17,7 @@ root: ../ Before writing any code with Recline, you need to do the following preparation steps on your page: -1. [Download ReclineJS](download.html) and relevant dependencies. +1. [Download ReclineJS]({{page.root}}download.html) and relevant dependencies. 2. Include the relevant CSS in the head section of your document: {% highlight html %} @@ -34,7 +34,6 @@ Before writing any code with Recline, you need to do the following preparation s diff --git a/download.markdown b/download.markdown index fd8d381c..412715b5 100644 --- a/download.markdown +++ b/download.markdown @@ -9,9 +9,10 @@ title: Download
-Besides the library itself, the download package contains full source code, -unit tests, files for debugging and a build system. The production files -(included the same way as in the code above) are in the dist folder. +Besides the library itself, the download package contains full source +code, unit tests, external vendor libraries and documentation. The +production files (included the same way as in the code above) are in the +dist folder.

Download Recline v0.5 (master) (in-progress version)

diff --git a/src/model.js b/src/model.js index 9453ce5c..1651559d 100644 --- a/src/model.js +++ b/src/model.js @@ -225,6 +225,8 @@ my.Dataset = Backbone.Model.extend({ return data; }, + // ### getFieldsSummary + // // Get a summary for each field in the form of a `Facet`. // // @return null as this is async function. Provides deferred/promise interface. @@ -250,6 +252,19 @@ my.Dataset = Backbone.Model.extend({ return dfd.promise(); }, + // ### recordSummary + // + // Get a simple html summary of a Dataset record in form of key/value list + recordSummary: function(record) { + var html = ''; + this.fields.each(function(field) { + if (field.id != 'id') { + html += '
' + field.get('label') + ': ' + record.getFieldValue(field) + '
'; + } + }); + return html; + }, + // ### _backendFromString(backendString) // // See backend argument to initialize for details @@ -344,16 +359,6 @@ my.Record = Backbone.Model.extend({ return val; }, - summary: function(fields) { - var html = ''; - for (key in this.attributes) { - if (key != 'id') { - html += '
' + key + ': '+ this.attributes[key] + '
'; - } - } - return html; - }, - // Override Backbone save, fetch and destroy so they do nothing // Instead, Dataset object that created this Record should take care of // handling these changes (discovery will occur via event notifications)