1 . How backbonejs models handle server side errors?
 

Answer :

In my client-side code I check for the presence of the errors attribute and react as necessary.

For example, I was using the Collection.create function, which calls the add function of the Collection if the request was successful. So, I overrode my Collection's add function to prevent the model from being added if it has an 'errors' attribute, and if it doesn't call the "super" method.

add: function(object, options) {
    if (_.isArray(object) || !object.get('errors')) {
        Backbone.Collection.prototype.add.call(this, object, options)
    }
},

Having my app return a non-success status code would work too, as it prevents success callbacks from being run. But, I didn't like the idea of returning a 400 error just because the submission was invalid. That's something I've never had to do in non-Backbone.js apps. ("Invertebrates"?)

None of the descriptions for 4XX status codes seemed to really match the concept of failed validation. 400 and 403 come close, but still come off as if they were intended for other uses. On the other hand, the user really doesn't care what status code you return; might as well be a 404.

It's really a matter of whether you want to write more code server-side or client-side. My application more or less ignores the outcome of validation and returns the record serialized to JSON whether it was saved or not, so I chose to work from that angle.


Leave a Comment

Name  
  Email   
Message
1 . Backbone.js application using CommonJS structure to work with node.js and client?
 

Answer :

ou have a number of options for using CommonJS structured modules in the browser:

  1. RequireJS 2.0.2 supports the configuration option cjsTranslate. Setting this to cjsTranslate: true in your r.js optimizer configuration will wrap any included modules that appear to be in the CommonJS format with the define boilerplate. See details here.
  2. Cajon is new a module loader built on top of RequireJS that supports modules in the CommonJS format (also written by the RequireJS author @jrburke).
  3. The Volo dependency management tool (again by @jrburke) has the ability to include and translate cjs modules into amd modules. This is probably not a great option for you but worth including for completeness.
  4. You could write a server component that automatically wraps your code in the AMD defineboilerplate. I believe this is the approach they're taking at SoundCloud - see this blog post.

Edit Aug 29, 2014: The current best practice here is arguably Browserify with generated source maps for easier client-side debugging.


2 . Questions regarding authentication workflow with REST, and Backbone?
 

Answer :

From what I understand this should all be handled with SSL, but with Backbonejs, you can't simply say that the login page should be accessed with HTTPS, as Backbone is a one-page framework. So will this force me to use HTTPS through out the application?

Ok, there's a lot to unpack there. Let's start with SSL/HTTPS. HTTPS is a protocol; in other words it defines how you send packets to/from the server. It has nothing whatsoever to do with whether your application is single or multi-page; either type of site can use either HTTP or HTTPS.

Now, that being said, sending login info (or anything else containing passwords) over HTTP is a very bad idea, because it makes it very easy for "bad people" to steal your users' passwords. Thus, whether you're doing a single-page or a multi-page app, you should always use HTTPS when you are sending login info. Since it's a pain to have to support both HTTP and HTTPS, and since other, non-login data can be sensitive too, many people choose to just do all of their requests through HTTPS (but you don't have to).

So, to answer your actual question, Backbone isn't forcing you to use HTTPS for your login at all; protecting your users' passwords is forcing you.

In the next step, the REST server validates the credentials, and they are approved, then the REST server sends an access token to the client. Is this token saved (on the client-side) in local storage or a cookie?

While any given framework might do it differently, the vast majority use cookies to save the token locally. For a variety of reasons, they're the best tool for that sort of thing.

Also is the login stored at the server, so that the REST server can log the user out after a certain amount of time?

You've got the basic right idea, but the server doesn't exactly store the login ... it's more like the server logs the user in and creates a "session". It gives that session an ID, and then whenever the user makes a new request that session ID comes with the request (because that's how cookies work). The server is then able to say "oh this is Bob's session" and serve the appropriate content for Bob.

Now, the client sends this access token along with other request, so that the server can identify the client, and approve the request or not. So the access token is also stored on the REST server?

If you're running two separate servers they're not going to magically communicate; you have to make them talk to each other. For this reason your life will be easier if you can just have one (probably REST-ful) server for your whole app. If you can't, then your REST server is going to have to ask your other server "hey tell me about session SESSION ID" every time it gets a request.

Lastly is this what the smart people call "oauth", or does it relate to it?

Kind of, sort of, not really. OAuth is an authorization standard, so it's sort of tangentially related, but unless your login system involves a whole separate server you have no reason to use it. You coulduse OAuth to solve your "two servers, one REST-ful one not" problem, but that would probably be overkill (and regardless it's outside the scope of what I can explain in this one Stack Overflow post)


3 . Is Google's Polymer a fully functioning Frontend Framework to Subsitute OR Complement other Frontend Frameworks?

Answer :

Polymer is almost fully functional. Currently it is missing routing for example but this doesn't mean you can't do this with Polymer.

There is now https://elements.polymer-project.org/elements/app-route

In Dart also dependency injection works fine with Polymer because of the types. If it's possible in Dart, it's possible in JS as well because Dart transpiles to JS. DI in plain JS might be more cumbersome though.

In this package (Dart) https://github.com/bwu-dart/bwu_polymer_routing I made the routing and DI packages used by Angular.dart available for Polymer. There are also routing packages for Polymer.js available.


4 . Backbone Collection?

Answer :

When you call fetch on your collection, it makes an AJAX request to:

 http://backbonejs-beginner.herokuapp.com/books

However, there is no API set up there. Either one of two things needs to happen:

1) you need to modify your code to point to a different URL, one that does have an existing API (perhaps whatever tutorial you are using has such an API)

2) you need to create such an API yourself on yoursever.com (and then make your Backbone code point to that API's URL instead)

Without a server to support it, operations like save and fetch and such in Backbone simply cannot function.

As a side note, Django is a web site framework. While you can use it to create server-side APIs, that's not really Django's focus. Because of this, several good third party libraries exist for doing RESTful APIs (ie. the kind that Backbone likes) in Django; personally I'd recommend either Django REST Framework (I use it and it works great) or TastyPie (never used it, but it's very popular).


5 . BackboneJS best way to rearrange models in a collection while maintaining 0-indexed ordinal property for each model?

Answer :

If you look at the backbone.js source code, you'll find out that for example the add method supports adding models to certain indexes with

collectionName.add(model, {at: index});

removing from position might need you to make a custom function to the collection, like:

// Your Collection

removeAt: function(options) {
  if (options.at) {
    this.remove(this.at(options.at));
  }
}

for +1 / -1 you can make a custom function and make use of the built-in underscore indexOf-function

// Your Collection

moveUp: function(model) { // I see move up as the -1
  var index = this.indexOf(model);
  if (index > 0) {
    this.remove(model, {silent: true}); // silence this to stop excess event triggers
    this.add(model, {at: index-1});
  }
}

moveDown: function(model) { // I see move up as the -1
  var index = this.indexOf(model);
  if (index < this.models.length) {
    this.remove(model, {silent: true}); // silence this to stop excess event triggers
    this.add(model, {at: index+1});
  }
}

This way you can also implement the moveUp and moveDown to the models themselves for more easily readable code!

// Your Model

moveUp: function() {
  this.collection.moveUp(this);
}

// And the same for moveDown

But now the index property is not saved in the models themselves. To read the index just use collection.indexOf(model), but if you want to store that information in the models at all times, you could bind to the add and remove events to update all indexes when changes to the collection are made:

// Your collection

initialize: function(options?) {
  ...
  this.on('add remove', this.updateModelOrdinals);
  ...
},

...

updateModelOrdinals: function() {
  this.each(function(model, index) {
    this.model.set('ordinal', index);
  });
}

et voilà! Now you should have the functionality you need without reinventing the wheel and still keeping the 0-indexing in place with Backbone's own functionality! Sorry for getting a bit carried off, ask if I went over your head. And read the backbone.js source, you can find seriously useful stuff there!



6 . Backbonejs Search Collection with Model with Object default?
 

Answer :

Use the find() function, which iterates over the collection and returns the first model that matches your conditions. Something like this:

result = myCollection.find(function (model) {
  return model.get("c").indexOf(5) != -1;
});

Or use filter() instead of find(), to get all of the models that pass the condition.


7 . Backbonejs collection.fetch() not working: Cannot call method 'apply' of undefined?
 

Answer :

Following the error trace, somewhere in your view you seem to have called bind on the collection's "add" event with an undefined function. So look for something like this within the view:

mycollection.bind('add', this.func, this);

In your code, this.func (whatever it really is) seems to be undefined, or at least it's not a function. Maybe you tried to bind a function before it was created? I'm not sure without seeing the full view code.


8 . How to use multiple parameters in backboneJS events?

Answer :

You can pass values from trigger to listener using option argument (2nd) of trigger.

It'll be sent to your listener as third argument.

Code :

var Sidebar = Backbone.Model.extend({
    setElementAttributes: function (value, cssAttribute) {
        this.set({
            property: value
        }, {
            cssAttribute: cssAttribute
        });
    }
});

window.sidebar = new Sidebar;

sidebar.on('change:property', function (model, value, options) {
    console.log(options.cssAttribute);
});

9 . Model not being pushed into collection of backbonejs?
 

Answer :

You are setting the id as 3 for all new models as your defaults hash contains id: 3. The collection thinks it is the same model as it already has a model with that id.

So first you need to change your defaults with id:null:

var MessageModel = Backbone.Model.extend({
    defaults:{
        id: null,
        message: "This is the message",
        sender: "gabriel",
        receiver: "gabriel",
        has_been_read: false,
        has_been_reported: false,
        created_at: "2014-10-23T19:55:20+0200",
        is_friend: false
    }
});

Then you need to fix the code getting the formData. First of all you are using jQuery children()method which only looks at immediate childrens. That means you will never get the inputs inside the form as there is an intermediate div. You could use find.

Secondly, you need to make sure that formData has a property named message so it can override the default message: "This is the message". I would add a name attribute message to the input element and use it like formData[el.name] = $(el).val();. (You could later use one of the jquery serializeObject plugins to automatically serialize all input elements this way).

So the addMessage would look like this:

addMessage: function(e){
    e.preventDefault();
    var formData = {};

    $("#addMessage").find("input").each(function (i, el) {
        formData[el.name] = $(el).val();
    });                

    messagesjson.push(formData);
    this.collection.add(new MessageModel(formData));
}

10 . How to use Web Workers into a Module build with Requirejs?
 

Answer :

You can use requireJS from web workers: see the API docs for more info.

The only requirement is to load requireJS at the start of the web worker with importScripts(…). Once that is loaded, you can use define and use requireJS like normal.

The key part for me when I was getting it to work was to make sure that you are also loading the same bootstrap configuration (e.g. config.js or main.js) in the web worker that you are using in the rest of your app. This is what the doc is talking about when it says:

You will likely need to set the baseUrl configuration option to make sure require() can find the scripts to load.

Another thing is that you can load the worker from your traffic.js file with a module ID (instead of hardcoding the script path) utilizing this requireJS plugin.



11 . Creating/Accessing Global object with requirejs and backbonejs?
 

Answer :

The list of dependencies in a define or require (the first argument in your require or the simplified wrapper you use in your other modules) tells RequireJS that it should load and interpretthose modules before interpreting the current file.

Here's what happens:

  1. The first require has backboneappmodels/session as dependencies
  2. before its function is evaluated, it loads its dependencies and in turn looks for their dependencies
  3. Rinse and repeat until you reach views/logout
  4. views/logout is interpreted, you try to assign App.session to your view.model but that does not exist at that point and you get a App is not defined error

One solution would be to create a singleton of your Session object and require it when you need it.

For example, let's say you have globals/session

define(['models/session'], function (SessionModel) {
    return new SessionModel();
});

You would define your app as

require([
    'backbone',
    'app',
    'globals/session'
], function (Backbone, Application, session) {

    //new Application();
    window.App = {
      session: session
    };

    new Application();

    Backbone.history.start();
});

and the same change in your view/logout

define(function(require){
    'use strict';

    var Backbone = require('backbone'),
        JST = require('templates')

    return Backbone.View.extend({
        model: require('globals/session'),
        ...
    });
});

12 . Dynamically filtering by parent node in nested JSON (BackboneJS)?
 

Answer :

your form collection should take in your data structure.

then it should make form models. those form models have entry collections.

FormCollection

  parse: (res) ->

    {@_meta} = res
    _.map res._data, (data, formName) =>
      {formName, data}  # we have 2 attributes on the form model

FormModel

  initialize: ->
    @on 'reset', ->
      # Since each form also has a collection of entries, we create a collection
      @entries ?= new EntryCollection
      @entries.parent = this # this circular dependency will create memory leaks
      @entries.reset @get('data'), parse: true #remember data is an array

EntryCollection

  parse: (res) ->
    @meta = parent.collection._meta
    res

EntryModel

models within EntryCollection can access @collection.meta

You should note that this sort of nesting is prone to memory leaks, so if your page stays open for days, you should consider delete @parent, etc, but you might not need to worry about it.

This is just a first shot at it, you could probably make improvements, but if you will be building this up more, you want to have a model for every object and a collection for every array. your _data is actually array.

you have

"_data": {
  "Test Alignment Form": [
    {
      "review_form": "Test Alignment Form",
      "rvee_uid": "52",
      "firstName": "Joe",
      "lastName": "Bloggs",
      "status": "NOT_STARTED",
      "status_clean": "Not started"
    },
    {
      "review_form": "Test Alignment Form",
      "rvee_uid": "54",
      "firstName": "Steve",
      "lastName": "Stevenson",
      "status": "NOT_STARTED",
      "status_clean": "Not started"
    },
    {
      "review_form": "Test Alignment Form",
      "rvee_uid": "13",
      "firstName": "Anne",
      "lastName": "Boleyn",
      "status": "COMPLETED",
      "status_clean": "Completed"
    }
  ],
  "Another Form": [
    {
      "review_form": "Another Form",
      "rvee_uid": "10",
      "firstName": "Luther",
      "lastName": "Vandross",
      "status": "NEVER_TOO_MUCH",
      "status_clean": "Never too much, never too much... duh duh duh"
    },
    {
      "review_form": "Another Form",
      "rvee_uid": "54",
      "firstName": "Steve",
      "lastName": "Stevenson",
      "status": "NOT_STARTED",
      "status_clean": "Not started"
    },
    {
      "review_form": "Another Form",
      "rvee_uid": "13",
      "firstName": "Anne",
      "lastName": "Boleyn",
      "status": "COMPLETED",
      "status_clean": "Completed"
    }
  ]
},

it should be

"_data": [
  {
    name: "Test Alignment Form",
    contents: [
      {
        "review_form": "Test Alignment Form",
        "rvee_uid": "52",
        "firstName": "Joe",
        "lastName": "Bloggs",
        "status": "NOT_STARTED",
        "status_clean": "Not started"
      },
      {
        "review_form": "Test Alignment Form",
        "rvee_uid": "54",
        "firstName": "Steve",
        "lastName": "Stevenson",
        "status": "NOT_STARTED",
        "status_clean": "Not started"
      },
      {
        "review_form": "Test Alignment Form",
        "rvee_uid": "13",
        "firstName": "Anne",
        "lastName": "Boleyn",
        "status": "COMPLETED",
        "status_clean": "Completed"
      }
    ],
  },
  {
    name: "Another Form",
    contents: [
      {
        "review_form": "Another Form",
        "rvee_uid": "10",
        "firstName": "Luther",
        "lastName": "Vandross",
        "status": "NEVER_TOO_MUCH",
        "status_clean": "Never too much, never too much... duh duh duh"
      },
      {
        "review_form": "Another Form",
        "rvee_uid": "54",
        "firstName": "Steve",
        "lastName": "Stevenson",
        "status": "NOT_STARTED",
        "status_clean": "Not started"
      },
      {
        "review_form": "Another Form",
        "rvee_uid": "13",
        "firstName": "Anne",
        "lastName": "Boleyn",
        "status": "COMPLETED",
        "status_clean": "Completed"
      }
    ],
  },
];

unless I am misunderstanding, but I think Another Form is user generated.. there could be infinite forms right?

In regard to your follow up

FormView

  render: ->

    @$el.empty().append formTemplate(this)
    @model.entries.each (model) =>

      # if you need more speed or re-render often, you can cache these views later
      entryView = new EntryView {model}
      # assumes you have an entries-container in your form template
      @$('.entries-container').append entryView.render().el

13 . BackboneJS: View renders fine, but refreshes with undefined collection?
 

Answer :

As is, EntryListView.render is not bound to a specific context, which means that the scope (this) is set by the caller : when you click on your button, this is set to your collection.

You have multiple options to solve your problem:

  1. specify the correct context as third argument when applying on

    initialize: function(){
        this.collection.on('add', this.render, this);
    },
  2. bind your render function to your view with _.bindAll:

    initialize: function(){
        _.bindAll(this, 'render');
        this.collection.on('add', this.render);
    },
  3. use listenTo to give your function the correct context when called

    initialize: function(){
        this.listenTo(this.collection, 'add', this.render);
    },

You usually would do 2 or/and 3, _.bindAll giving you a guaranteed context, listenTo having added benefits when you destroy your views

initialize: function(){
    _.bindAll(this, 'render');
    this.listenTo(this.collection, 'add', this.render);
},

And if I may:

  • don't create your main view in a fetch callback, keep it referenced somewhere so you can manipulate it at a later time
  • don't declare collections/models on the prototype of your views, pass them as arguments
  • don't hardwire your DOM elements in your views, pass them as arguments

Something like

var EntryListView = Backbone.View.extend({
    events: {
        'click button': 'addEntry'
    },
    initialize: function(){
        _.bindAll(this, 'render');
        this.listenTo(this.collection, 'reset', this.render);
        this.listenTo(this.collection, 'add', this.render);
    },
    render: function(){
        var els = [];
        this.collection.each(function(item){
            els.push(new EntryView({model:item}).render().el);
        });

        this.$el.empty();
        this.$el.append(els);
        this.$el.append('<button>New</button>');
        return this;
    },
    addEntry: function(){
        entries.add(new Entry({
            title: "New entry", 
            text: "This entry was inserted after the view was rendered"
        }));
    }
});

var view = new EntryListView({
    collection: entries,
    el: '#entries'
});
view.render();

entries.fetch({reset: true});

14 . RequireJS - why should i shim libs like jquery, backbone etc?
 

Answer :

We shim because modules like jQuery and Backbone do not work in the RequireJS model .There is no define( statement defining them so they must be shimmed to work like and with real Require modules directly.

Yes, what you said (just dumping them in the global namespace) works, you're not breaking any 'rules'. When you add a script tag all it does is dump the code in the global namespace - so all your modules will, in fact have access to Backbone and jQuery in the above example.

However it has three disadvantages:

  • One of the thing we gain with Require is that our dependencies are explicit , every time a module needs something we know that - so our dependency management is a lot clearer (We know what modules depend on jQuery and what don't for example - so we know which are safe to use in a new project without jQuery).

  • Another thing is that we stay consistent across our code, we keep declaring every dependency exactly the same way and using it in exactly the same way. RequireJS shims let us keep acting like that's what's done with libraries like jQuery or Backbone.

  • Because of the implicit dependencies, if you ever want to reuse your code - including jQuery after your RequireJS modules will be a run time error which is not always trivial to understand, unlike Require which would tell you that it can't load the module jQuery (and not something like $ is not defined, or even worse "[Object object] is not a function" or something like that.


15 . jquery mobile require.js and backbone?
 

Answer :
equire.config({
  baseUrl: "/js/",
  paths: {
    jquery: 'libs/jquery/jquery-1.7.1',
    'jquery.mobile-config': 'libs/jqm/jquery.mobile-config',
    'jquery.mobile': 'libs/jqm/jquery.mobile-1.1.0',
    'jquery.mobile.asyncfilter': 'libs/jqm/asyncfilter',
    underscore: 'libs/underscore/underscore-1.3.3',
    backbone: 'libs/backbone/backbone-0.9.2',
    templates: '../templates'
  },
  shim: {
          'underscore': {
            exports: "_"
          },
          'backbone': {
              //These script dependencies should be loaded before loading
              //backbone.js
              deps: ['jquery','underscore'],
              //Once loaded, use the global 'Backbone' as the
              //module value.
              exports: 'Backbone'
          },
          'jquery.mobile-config': ['jquery'],
          'jquery.mobile': ['jquery','jquery.mobile-config'],
          'jquery.mobile.asyncfilter': ['jquery.mobile'],
        }
});

require([
  'jquery',
  'app',
  'jquery.mobile','jquery.mobile.asyncfilter'
], function( $, App ){
    $(function(){
      App.initialize();
    });
});

The last bit is very important to get JQM to load correctly (and actually function). This part:

require([
      'jquery',
      'app',
      'jquery.mobile','jquery.mobile.asyncfilter'
    ], function( $, App ){
        $(function(){
          App.initialize();
        });
    });

Since i need jquery for jqm (jquery mobile), i'll load them all and thanks to the shim code above, the dependencies are loaded in the correct order. I don't actually pass any jqm variable into the function call, which only passes $ and App. The next important part is the jqm-config file:

define(['jquery'], function ($) {
      $(document).on("mobileinit", function () {
          $.mobile.ajaxEnabled = false;
          $.mobile.linkBindingEnabled = false;
          $.mobile.hashListeningEnabled = false;
          $.mobile.pushStateEnabled = false;
      });
});