This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Create a Model Base Class

3:12 Angular 1.x lesson by

You're going to test drive the creation of a robust model layer for an AngularJS application. To get started, we need a solid base class to encapsulate common functionality. In this lesson you'll use Javascript's prototypical inheritance to create the model base class.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

You're going to test drive the creation of a robust model layer for an AngularJS application. To get started, we need a solid base class to encapsulate common functionality. In this lesson you'll use Javascript's prototypical inheritance to create the model base class.

Avatar
Andrew

I've enjoyed the thought you have put into this approach, and have returned several times to these videos. I do have a few comments about your approach to subclassing:

  • the resulting instances are not terribly lightweight. When you
    define a method function in the constructor, that function is
    duplicated across each instance.

    • The more functions added and inherited the more heavyweight each instance will be.
    • Defining methods on the prototype outside of the constructor uses prototypal inheritance of a single instance of the method function object.
    • Changes to the prototype are immediately reflected in existing objects, although such monkey-patching is unhealthy.
    • You can demonstrate the space-inefficiency simply by testing the methods for equality with a single mock function, rather than existence.
  • I'm not sanguine about monkey patching this functionality on
    Function. I would far prefer to see it defined on Object, much
    as we have seen for Object.create.

You might consider a solution along the lines of:

Object.prototype.subclass = function(baseclass, initializer){
  var S = function(){
    baseclass.call(this, arguments);
    initializer.call(this, arguments);
  };
  angular.extend(S, baseclass);
  S.prototype = Object.create(baseclass.prototype);
  S.prototype.constructor = S.constructor;
  return S;
};

so that you might write something like var Post = Object.subclass(Base, function(){... initializer for Post ...} This would pass not only corresponding tests, but there would be an identicality, not only an existence relationship for existing and inherited instance and class variables and methods.

Further, the attachment would be dynamic, not static upon creation, with the exception of course of Class methods and variables in the baseclass, which are only copied over upon creation.

In reply to egghead.io
Avatar
Kevin

Can Brett Shollenberger follow-up on how he would've done this using ES6's class syntax, particularly any steps he would've done drastically in a different way?

Avatar
Shaun

Extending native objects is generally a bad practice and I don't see a compelling reason to make an exception here.

Avatar
Nolan

Shaun, I'm interested to know why in JavaScript this is bad practice? I'm fairly new to JS, but in backend programming decorating native classes would be the right approach. Is there something in JS that causes this to be a bad practice?

In reply to Shaun
Avatar
Nolan

Brett, first, humbled by your JS knowledge. A lot of this type of model functionality can be found in server MVC frameworks like RoR or Laravel Eloquent, etc. whereas this series and the ActiveSupport provides very similar syntax and functionality for Angular / JS. I'm assuming that if you already using a rich MVC backend model framework, that you would not find much value in implementing this model approach? Other than maybe the local features ActiveSupport. Is that a fair assessment or am I missing the point? Again, great content!

Avatar
Francois

Hi, I understand everything in this video except for the attributes parameter that is being passed to the base class and it's new function. It seems that it is never used and creates a lot of confusion for me. Why would they be there and if there is implementation missing for it where can I see the implementation?

Avatar
Evan Gillogley

Where do I get the code for this?

Brett: Hey everyone. In the previous video in this series we looked at using $resource to build models, and we discovered that doesn't provide us with all the functionality that we're going to need and expect out of a base class, so in this and future videos we're going to take a look at building a base class ourselves and everything that goes into that, so let's get started.

Here we have a mock model that's going to use our base class. It's the most basic model we could possibly write at the moment and we're just injecting the base class, which we've creating up here in our lib, which also is similarly pretty empty, and we're injecting all of these through a spec_helper, so these will be available to each of our tests. That way we can isolate different portions of the functionality and test them separately, which will keep things easy to read as the code base gets larger.

Right here we have our first test. We know that one equals one, so obviously this works. Let's get started writing some real tests.

We want to do some work before each of our tests, just a little setup, and we're going to say that we're going to define and inherit a method that's going to allow our constructors to inherit functionality from a base class, so we'll define some arbitrary base class here, and what we really want to test is that it add functionality to both the child constructor and the prototype, which will add instance properties and methods.

On the constructor, we'll say that we'll define a new method, and this is something that we're actually going to do in a real base class, but here's a very simple implementation of it. It's literally just creating a new instance of the constructor and returning it, and on the prototype we'll just create a save method and assign that to angular.noop, which is an empty function, and then what we'll do here is just test that it adds methods to the child class.

We want to expect that host.new is define, simple enough, and we'll do the exact same thing for the prototype, so we're going to expect that instances of the class, scoop this down here, so a post, which is a new instance of the post class, will have the save method defined on it, and again, that's just an empty function, but it will be defined. We see in our test here the inherits method doesn't exist yet. Good to go.

Let's make these tests pass. Let's go over to the base class. We'll add to the function prototype this inherits method, so every function has access to it, and this is going to take a base class as argument. The constructor will again be the value of this, and we're going to change the value of the constructor by running it through the base class function, so we'll call base class.apply on the constructor, and we'll see here that this makes our test pass exactly as we'd expect, so why does this work?

Well, what happens when we call apply is we're setting the value of this to what we pass in, which is the constructor, so that means that we can add methods to the constructor and the prototype exactly as we'd expect, because we know the exact value of this, so now we're able to add functionality to the base class as we'd like to, so let's move on to the next video and see how we're going to start building out the class.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?