Code Monkey home page Code Monkey logo

backbone-sails's Introduction

Backbone.Sails

Backbone.Sails is a plugin that aims to leverage to best of a Sails backend within a Backbone frontend.

Intro

Sails is a nodejs framework built on top of express. It features fantastic support for web sockets, straight out of the box. As well as the extremely useful CRUD blueprint routes, which make GET'in, POST'in & DELETE'in a breeze. What's more, Sails supports these http 'verbs' through the client side web socket SDK sails.io.js. Allowing web developers to quickly build real-time applications that leverage the resourceful pub/sub events.

Backbone is an extremely popular and incredibly light weight javascript library that

gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling

In a nut shell, Backbone gives structure to client side javascript for single page applications. However, Backbone was never built with sockets in mind. Those familiar will know the default sync method delegates to $.ajax which itself delegates to XMLHttpRequest. Furthermore, Backbone Model's and Collection's only fire purely clientside events - making it fiddly to respond to server side events on the client.

This Plugin

This plugin attempts to bridge the gap between a Backbone frontend and a Sails backend. It has it's own Model and Collection class which support syncing over sockets (delegating to sails.io.js internally). Whats more, if the web socket isn't available, there are options to delegate to the original sync function.

Perhaps more importantly, this plugin triggers the resourceful pub/sub events on client side Model and Collection instances. This allows you to respond to server side changes on your models and collections, within the 'Backbone ecosystem'. This ultimately reduces development time, increases maintainability and can serve as a pillar of programming architecture for larger socket based applications.

Sails blueprints also features great support for associations, population and filter/sort criteria. Backbone.Sails has built in functionality that helps streamline these powerful server side features into your Backbone workflow.

A quick look at the API...

var Address;
var Person = Backbone.Sails.Model.extend({
  modelName: "person",
  assoc: {
    address: function(){ return Address } // function returning address since circular dependence
  },
  config: {
    populate: "address" // populate address by default (on fetch, save, etc)
  }
})
var PersonCollection = Backbone.Sails.Collection.extend({ model: Person })

Address = Backbone.Sails.Model.extend({
  modelName: "address"
  assoc: {
    occupants: PersonCollection
  }
  config: {
    populate: "occupants"
  }
})

var fred = new Person({ name: "fred", address: { street: "maple grove" } });

fred.save(); // will create address and a person, address will be populated

addressRaw = fred.get("address"); // this will grab the raw data for address (a POJO)
address = fred.get("address", true); // passing true will wrap the data with an Address constructor
address.set("number", 4).save();

// fetch is overloaded to call the 'populate' action, resolving with the address as a model
fred.fetch("address").done(function(address){
  var jack = new Person({ name: "jack" })
  address.addTo('occupants', jack) // will call the 'addTo' action, updating both the address and jack
  .done(function(){
    jack.isNew(); // false
    address.get("occupants", true).findWhere({ name:"jack" }); // truthy (since occupants populated)
  })
})

// you can specify filter criteria like this
var persons = new PersonCollection();
persons.query({
  skip: 1,
  limit: 1,
  sort: "name ASC", // an object also works, e.g. { name: 1, street: -1 }
  where: { name: { contains: "a" } }
}).fetch()

// unlike sails, populate can take filter criteria as well
address.populate({
  occupants: {
    limit: 2,
    where: {
      name: "fred"
    }
  }
}).fetch()

Releases

A 0.1 release is currently available. Sails v0.10 is required as well as io.sails v0.9.

Dependencies

Backbone.Sails depends on

The server side blueprints depend on lodash and bluebird, so you'll need to run

  • npm install bluebird --save
  • npm install lodash --save

Integration

  • On The Client

    Include backbone.sails.js after it's dependencies have been included. Backbone.Sails should be available thereafter.

  • On The Server

    Copy/paste the blueprints folder to api/blueprints. The blueprints are backwards compatible with the original sails blueprints.

Configuration

Whilst you are familiarizing yourself with the API, I suggest setting the following blueprint options within config/blueprints.js:

  • mirror: true

    mirror return's socket event's back to the client they originated from - utterly crucial for testing/learning and DRY'ing up your front end.

  • autowatch: true

    autowatch is a flag to the find blueprint indicating to subscribe the client to created events. A good default is true, whilst your learning. (There is also a configuration option to dynamically flag this on or off from the client with Backbone.Sails)

Documentation/Learning

The documentation currently available is:

There is also an example chat client application that can be found here that was developed with Backbone.Marionette in coffeescript.

You can also get a good idea of what Backbone.Sails is capable of by looking at the test code.

A Note from the Author

Thanks for your interest! Please see my GitHub or Linkedin to stay updated.


The MIT License (MIT)

Copyright (c) 2022 Ian Haggerty

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

backbone-sails's People

Contributors

ianhaggerty avatar

Stargazers

Marcus Williams avatar Burkhard Reffeling avatar Joseba Legarreta avatar Martin Jantošovič avatar Artod avatar  avatar Austris avatar

Watchers

Burkhard Reffeling avatar Marcus Williams avatar James Cloos avatar  avatar

Forkers

markandrewj

backbone-sails's Issues

Watched collection doesn't update

Hey Oscar (Ian?),

First of all, thanks for such a great plugin and the effort you put into documentation!

I'm experiencing an issue when updating a fetched (and subscribed) collection (PersonCollection containing PersonModel).
If I add another Person (via CURL or in a seperate window), PersonCollection correctly fires a "created" event. However, the PersonCollection itself is not being updated with the new Person. Only when I manually call personCollection.add(person) inside the event callback does the PersonCollection reflect the update.

Is this by design? Could I be doing something wrong?

            var personCollection = new PersonCollection();

            personCollection.on('created', function (model) {
                // personCollection does not contain the new model yet :(
                // I have to add it manually
                personCollection.add(model);
            });

            React.render(new (React.createFactory(HomeComponent))({
                collection: personCollection
            }), mountPoint);

            personCollection.fetch({
                sync: ['socket', 'ajax', 'subscribe', 'set']
            });

Pageable Collection

I'm looking to change one of my existing apps to using Backbone.Sails but a lot of the collections use backbone.paginator and I'm assuming the 2 plugins wont work with each other.

Some of the functionality can be achieved by skip and limit in the query but I can't think of a sensible way of getting the total records so number of pages can be calculated as I don't believe there is a way to do a count without fetching the entire collection.

Any suggestions would be greatly appreciated.

Sails V11

Just out of curiosity will this be compatible with sails v11 or will some work be required on that?

Using addTo returns error

Firstly thank you for what looks to be an amazing plugin.

Just having a little difficulty using the addTo feature. I'm trying to add and existing model to another model which has a many to many association.

membersListView.on("itemview:user:add", function(childview, model) {
                      addingUser = team.addTo("users", model);
                      addingUser.done(function(teamData) {
                        console.log(teamData);
                      });
});

but I get an error of Uncaught TypeError: Cannot read property 'users' of undefined

team has already been fetch and users populated.

I'm not sure if misinterpreting to use of addTo or doing something wrong.

Separate the blueprints to another repository

Hey!

That's a really awesome work, the project and the docs!!

I think that it would be interesting if you separate the blueprints to another repository just to make a git clone http://whaterver (inside of /api folder of our projects), instead of a copy paste of blueprints folder after downloading all this repo.

That will be cleaner and easier to start using your custom blueprints...

Btw, from where can I download the Backbone.Sails.js file? I've only found the Backbone.Sails.coffee file. Maybe it will be interesting to use another repo for that too, or adding it to Bower also.

Really cool job!

Can't get socket events working.

Hopefully this will be the last of my getting start questions but I can't seem to get any socket events working. I've looked at your example app and can't see the difference that's stopping it working.

In the example below I would expect that once a new list item is saved the "created" event would fire on the lists collection, but nothing is happening.

The only thing I've noticed but not sure if it's related is undefined showing at the end of my socket request i.e.

socket request: get /api/lists?where={"team":"533951b78972167e2d3c5d10"}&limit=30&watch=true undefined 
var lists = new App.Entities.ListCollection;
return lists.query({
  where: {
    team: team.id
  }
}).fetch({
  socketSync: true
}).then(function() {

  var listsListView = new View.Lists({
    collection: lists
  });

  listsListLayout.on("show", function() {
    listsListLayout.panelRegion.show(listsListPanel);
    listsListLayout.listsRegion.show(listsListView);
  });

  listsListPanel.on("list:new", function() {
    require(["apps/lists/new/new_view"], function(NewView) {

      var newList = new App.Entities.List({
        team: team.id
      });

      var view = new NewView.List({
        model: newList
      });

      view.on("form:submit", function(data) {
        newList.save(data).done(function() {
          lists.add(newList);
          view.trigger("modal:close");
          var newListView = listsListView.children.findByModel(newList);
          if (newListView) {
            newListView.flash("success");
          }
        });
      });

      App.modalRegion.show(view);
    });
  });


  App.sideRegion.show(listsListLayout);

  return lists.on("created", function(data) {
    console.log('list created');
    var list = new App.Entities.List(data);
    return list.fetch().done(function() {
      lists.add(list);
      var newListView = listsListView.children.findByModel(list);
      if (newListView) {
        newListView.flash("success");
      }
    });
  });
});

Populating a nested association

I have the following Comment model with a user association, but is it possible to populate the user on the child collection or would it require modifying the blueprint to achieve this?

module.exports = {
  attributes: {
    comment: 'string',
    parent: {
        model: 'Comment'
    },
    children: {
        collection: 'Comment',
        via: 'parent'
    },
    user: {
        model: 'User'
    }
  }
};

Cannot read property 'id' of null

I'm get the following error when fetch a single model and not really sure what would be causing it, and it's not happening on every model in the collection.

/Users/marcus/hosts/dbapi/api/blueprints/helpers/actionUtil.js:121
          console.log(record[AssociatedModel.primaryKey]);
                            ^
TypeError: Cannot read property 'id' of null
    at /Users/marcus/hosts/dbapi/api/blueprints/helpers/actionUtil.js:121:29
    at Function.forEach (/Users/marcus/hosts/dbapi/node_modules/lodash/dist/lodash.js:3297:15)
    at Object.module.exports.subscribeDeep (/Users/marcus/hosts/dbapi/api/blueprints/helpers/actionUtil.js:112:14)
    at /Users/marcus/hosts/dbapi/api/blueprints/findone.js:21:20
    at bound (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/lodash/dist/lodash.js:957:21)
    at applyInOriginalCtx (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:416:80)
    at wrappedCallback (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:315:18)
    at _normalizeCallback.callback.success (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/node_modules/node-switchback/lib/normalize.js:33:31)
    at _switch (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/node_modules/node-switchback/lib/factory.js:35:28)
    at returnResults (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:163:9)
    at /Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:74:16
    at /Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:77:45
    at bound (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/lodash/dist/lodash.js:957:21)
    at applyInOriginalCtx (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:416:80)
    at wrappedCallback (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:315:18)
    at _normalizeCallback.callback.success (/Users/marcus/hosts/dbapi/node_modules/sails/node_modules/waterline/node_modules/node-switchback/lib/normalize.js:33:31)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.