DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Securing Your Software Supply Chain with JFrog and Azure
Register Today

Trending

  • Transactional Outbox Patterns Step by Step With Spring and Kotlin
  • From On-Prem to SaaS
  • Essential Architecture Framework: In the World of Overengineering, Being Essential Is the Answer
  • The SPACE Framework for Developer Productivity

Trending

  • Transactional Outbox Patterns Step by Step With Spring and Kotlin
  • From On-Prem to SaaS
  • Essential Architecture Framework: In the World of Overengineering, Being Essential Is the Answer
  • The SPACE Framework for Developer Productivity
  1. DZone
  2. Coding
  3. JavaScript
  4. Building Models in Backbone.js and AngularJS

Building Models in Backbone.js and AngularJS

Victor Savkin user avatar by
Victor Savkin
·
Nov. 26, 13 · Interview
Like (0)
Save
Tweet
Share
15.35K Views

Join the DZone community and get the full member experience.

Join For Free

This is the second article in the series contrasting how Backbone and Angular help with the things we have to deal with day to day when building web applications. This time we will look into how we build models and implement business logic in both frameworks.

Series

  • Contrasting Backbone and Angular. Overview.

Backbone

Backbone, similar to many client-side frameworks, is built around observable properties. Therefore, in order for the view to reflect the changes of a particular model, that model has to emit events. In most applications it is not just the view that listens to those events, but other models as well.

Since this need of keeping multiple components in sync is so common, a large chunk of the business logic of the application goes into Backbone models and collections. Quite often these objects also correspond to resources on the backend.

Let’s look at an example of the Account model implemented in Backbone:

var Transaction = Backbone.Model.extend({
  amount: function(){
    return this.get('amount');
  },

  isDebit: function(){
    return this.amount() > 0;
  },

  isCredit: function(){
    return this.amount() < 0;
  }

  //...
});


var Transactions = Backbone.Collection.extend({
  model: Transaction

  //...
});


var Account = Backbone.Model.extend({
  //...

  balance: function(){
    return this.get('balance');
  },

  transactions: function(){
    return this.get('transactions');
  },

  addTransaction: function(transaction){
    this.transactions().add(transaction);
  }
});

This is how it can be used:

var account = new Account({
  number: '87654321',
  transactions: new Transactions([
    {id: 1, amount: 10}
  ])
});

account.addTransaction(new Transaction({id: 2, amount: -5}));

Having to extend Backbone.Model and Backbone.Collection adds quite a bit of complexity.

POJOs and Models

First, it separates all domain objects into POJOs (or JSON data) and Backbone models. POJOs are used when rendering templates and talking to the server. Backbone models are used when observable properties are needed (e.g., setting up data bindings).

This often leads to having two versions of the same object: one for data bindings, and the other one for rendering. Calling toJSONis a standard way to convert one into the other.

var Account = Backbone.Model.extend({

  // View uses toJSON to render the template
  toJSON: function(){
    return _.merge(this.attributes, {
      transactions: this.transactions().toJSON()
    })
  }
});

Computed Properties

Second, extending Backbone.Model and Backbone.Collection promotes mutability. Since Backbone does not support observing functions, every computed property has to be reset when any of the source properties changes. This adds a lot of accidental complexity, which results in code that is hard to understand and test. On top of that, all the dependencies have to be explicitly specified.

The following is an example of a computed property:

var Account = Backbone.Model.extend({
  //...

  initialize: function(){
    this.transactions().on("add remove", this._recalculateBalance, this);
    this._recalculateBalance();
  },

  balance: function(){
    return this.get('balance');
  },

  transactions: function(){
    return this.get('transactions');
  },

  _recalculateBalance: function(){
    var newBalance = this.transactions().reduce(function(sum, transaction){
      return sum + transaction.amount();
    }, 0);
    this.set('balance', newBalance);
  }
});

Using Add-ons

Even though using add-ons can mitigate this issue, they do not solve the main problem: computed properties are mutable and have to be proactively recalculated.

Angular

Since Angular does not use observable properties, it does not restrict you when it comes to implementing the model. There is no class to extend and no interface to comply. You are free to use whatever you want (including existing Backbone models). In practice, most developers use plain old JavaScript objects.

Let’s look at an example of how we would implement the Account model in Angular.

function Transaction(attrs) {
  _.extend(this, attrs);
}
_.extend(Transaction.prototype, {
  isDebit: function(){
    return this.amount > 0;
  },

  isCredit: function(){
    return this.amount < 0;
  }
});


function Account(attrs){
  _.extend(this, attrs);
}
_.extend(Account.prototype, {
  addTransaction: function(transaction){
    this.transactions.push(transaction);
  }
});

We can use it as follows:

var account = new Account({
  number: '87654321',
  transactions: [
    new Transaction({id: 1, amount: 10})
  ]
});

account.addTransaction(new Transaction({id: 2, amount: -5}));

Just POJOs

  • Same objects are used to render views and implement business logic, so there is no need to implement toJSON.
  • They are framework-agnostic, which makes reusing them across applications easier.
  • They are close to the data that is being sent over the wire, which simplifies the client-server communication.

Computed Properties

Computed properties can be modeled as functions:

function Account(attrs){
  _.extend(this, attrs);
}
_.extend(Account.prototype, {
  //...

  balance: function(){
    return this.transactions.reduce(function(sum, transaction){
      return sum + transaction.amount;
    }, 0);
  }
});

They are more testable, and, in general, easier to reason about.

Going OO or FP

Angular does not impose any constraints on how your models are built. The Account model in the example is implemented in the traditional object-oriented style, so we can compare it with the Backbone implementation. You, however, are free to use any style you want.

  • A big fan of Domain Driven Deisgn? Like building rich domain models comprising entities and values? Not a problem.
  • Like functional programming, persistent data structures, and data transformations? Use those.

Doing either in Backbone is pretty much impossible.

Summing Up

The two frameworks have very different approaches when it comes to building models.

  • Since Backbone is built around observable propeties, you are forced to extend Backbone.Modeland Backbone.Collection.
  • Angular, on the other hand, does not prescribe anything in this area. You can use DDD, FP, or whatever works for you.

Depending on the complexity of the model it can have a profound effect on the maintainability of your application.

In the next article I will cover constructing the DOM and implementing view logic.

AngularJS Backbone.js

Published at DZone with permission of Victor Savkin, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Transactional Outbox Patterns Step by Step With Spring and Kotlin
  • From On-Prem to SaaS
  • Essential Architecture Framework: In the World of Overengineering, Being Essential Is the Answer
  • The SPACE Framework for Developer Productivity

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: