DailyJS

DailyJS

The JavaScript blog.


Tagmv*
Featured

browser mv* client-side frameworks

The jsblocks Framework

Posted on .

Antonio Stoilkov sent in jsblocks (GitHub: astoilkov/jsblocks, License: MIT, npm: jsblocks), a new client-side framework that claims to have a rendering performance that is faster than React. It's a full-featured framework, and has some unique features. For example, it aims to improve the debugging experience of client-side apps, so rather than getting lost in confusing stack traces and DOM trees, it attempts to display very clear error information.

jsblocks debug examples

jsblocks is made of three main modules: blocks.query, blocks.mvc, and jsvalue. You can use all three libraries, or create builds with the ones you need. Here's what each library does:

  • blocks.query: The core library
  • blocks.mvc: The "Model View Collection" implementation
  • jsvalue: A utility library that works like Underscore or lodash

Models in jsblocks are used to represent values that are rendered in views. For example:

var User = App.Model({  
  init: function () {
  },
  firstName: blocks.observable(),
  lastName: blocks.observable(),
  fullName: blocks.observable(function() {
    return this.firstName() + ' ' + this.lastName();
  })
});

App.View('Profile', {  
  profile: User({
    firstName: 'John',
    lastName: 'Doe'
  })
});

Models use observables, so this example should make complete sense to those of you who are experienced with Knockout -- in some ways it reminds me of a blend of ideas from React, Backbone, and Knockout.

Collections are actually built out of observables, but the author suggests that they add an extra architectural layer to your application that can make it clearer. This definitely reminds me of Backbone.

Collections and models can also talk to the server -- both have a sync method:

var Products = App.Collection({  
  options: {
    create: {
      url: 'serviceURL/CreateProduct'
    }
  }
});

App.View('Products', function () {  
  products: Products(),

  init: function () {
    this.products.push({
      ProductName: 'Fish'
    });

    // sends AJAX request to the create.url with the new item
    this.products.sync();
  }
});

Models even support validation, so you can validate user input. Because jsblocks lets you work with data it also has a utility library for iterating and filtering data. This is the jsvalue library I mentioned earlier:

blocks  
  .range(1, 100)
  .map(function (value) {
    return value * 2;
  })
  .filter(function (value) {
    return value % 2 == 0 && value < 50;
  })
  .contains(0)
  .or()
  .contains(22);

Views support routing, and the routing implementation supports hash URLs and pushState history. Views can also be rendered on the server.

jsblocks has very quickly earned a big following -- it has over 1,500 stars on GitHub. I think the reason for this is it combines almost everything you need for modern web development: data modelling with validation, server sync and filtering, server-side view rendering, client-side view components and data binding, and client-side routing.

If you're a Backbone user and want to try something new then jsblocks may appeal to you. Equally, if you're a React user but struggle with dealing with data then jsblocks might make things easier for you.

Featured

frameworks localStorage mv*

MV* and Local Storage

Posted on .

Most AngularJS and Backbone.js projects that I've worked on have persisted data to a remote API. What about those times when storing data in the browser is sufficient? Enterprising developers have added support for localStorage to some MVC frameworks, but before dropping one of these plugins or libraries into your project you need to know a little background about the API and its limitations.

Browser Support

If you're already set on building a modern, single page web application, legacy browser support probably isn't a huge deal. The Can I use Web Storage page shows most browsers we typically target are supported. It refers to "name/value pairs" because it's talking about the localStorage API.

The localStorage API

If you've never used it before, then you can think of window.localStorage as a key/value store for strings. You can stick any JavaScript value you like in there, but a string will be returned on retrieval.

window.localStorage.setItem('age', 18);  
window.localStorage.getItem('age');  
// "18"

This means you should think carefully about what data you store. Aspirations of creating a browser-based Photoshop backed by localStorage isn't architecturally sensible -- it would be nice if binary data could be stored, but for now you'll have to make do with strings.

The storage limit in most browsers is 5 MB, which probably doesn't sound like much, but it's actually 1000 times more than is supported by cookies.

AngularJS

There are examples of apps that use localStorage on the AngularJS blog. One that I downloaded and picked apart was FoodMe by Igor Minar. In FoodMe, Igor creates a localStorage service which basically just wraps window.localStorage so it can be loaded with dependency injection. The $scope is then watched, and a string version of a given record is dumped into localStorage using JSON.stringify:

foodMeApp.factory('customer', function($rootScope, localStorage) {  
  var LOCAL_STORAGE_ID = 'fmCustomer';
  var customerString = localStorage[LOCAL_STORAGE_ID];

  var customer = customerString ? JSON.parse(customerString) : {
    name: undefined,
    address: undefined
  };

  $rootScope.$watch(function() { return customer; }, function() {
    localStorage[LOCAL_STORAGE_ID] = JSON.stringify(customer);
  }, true);

  return customer;
});

The record is loaded from localStorage, and serialised using JSON.parse and JSON.stringify. Notice that Igor has used the object-style API: localStorage.setItem(key, value) and localStorage[key] = value are equivalent.

Backbone.js

Jerome Gravel-Niquet created Backbone.localStorage (GitHub: jeromegn / Backbone.localStorage, License: MIT, bower: backbone.localStorage), which allows collections to store data with localStorage. It's a drop-in solution -- barely any configuration is required. All you need to do is add a localStorage property to your collection classes.

Backbone.localStorage has tests, and the author is still updating it. GitHub currently lists 31 contributors.

Knockout

This isn't meant to be an exhaustive review of localStorage libraries, but I thought I'd also mention Knockout. knockout.localStorage (GitHub: jimrhoskins / knockout.localStorage) by Jim Hoskins makes ko.observable and ko.observableArray objects able to persist data to localStorage. You'll need to specify a persist property which includes the key to store the observable's data under.

It's not quite as well-maintained or tested as Backbone.localStorage, but it does the job. There are some open pull requests that add things like AMD support.

Events

The Web Storage specification also defines a "storage" event. It fires when data changes, but you can't stop it unlike other DOM events. This might make a more convenient bridge to data-binding frameworks.

Sync

If you've made an amazing single page app that persists data to localStorage, and you're interested in adding a server-side API so users can save and sync data, what do you do? Well, step back and redefine the problem. Since localStorage is limited in size, why not use it like a caching layer? Your application could store data locally until a server is available, which suits a lot of use-cases, including mobile deployment. This is exactly what Backbone Caching Sync by Yiorgis Gozadinos does.

Cache

Another use people have found for localStorage is caching client-side assets. One example of this is basket.js by Addy Osmani.

Bing and Google Search make extensive use of localStorage for stashing SCRIPT blocks that are used on subsequent page views. None of the other top sites from my previous post use localStorage in this way. Are Bing and Google Search onto something? Yes, definitely.

Summary

If you need to persist data, localStorage can slot into data-binding and MVC/MVVC frameworks rather nicely. There are libraries out there, but with JSON.parse and JSON.stringify it's trivial to store data. For applications with a server, then localStorage can be used as a temporary cache, which has the added benefit of helping support devices with intermittent network access.