Intro


My name is David Colwell
I am... 
1st - a Front-End Application Architect  & UX Specialist
2nd - a Full Stack Developer

I work at an AWESOME company named Stackdriver
www.stackdriver.com

(p.s. - we're hiring ... looking especially hard for good front-end developers!)


I've been doing Front-End for a while


Have been developing web based UI/UX for server apps since 1996
Started doing enterprise level apps in 1999.
A lot has changed since then.

I'm rather opinionated about how I like things to work.
Not Everyone agrees with me.

I'm okay with that ... they are entitled to be "wrong".

Disclaimer



I don't support IE8

The concepts we'll be covering here do not play nice with IE8 or below.

Don't ask me to...
THE ANSWER IS "NO!"


A personal resource I'll share...

I keep a running set of evernote notes and google docs.
I'll add some google doc links in the next day or two.
Most of the material in this presentation came from my personal evernote .
link below!



Resources I "highly recommend'


egghead.io  -  short videos that teach you a lot.


Dan Wahlin
google for more

MANAGING THE MISSING MODEL
IN ANGULAR JS

Boston AnguarJS Meetup
April 23, 2014


A couple precursory comments....

If your a front end developer
Javascript is your friend.

But you should know...

  • ...your friend has some interesting quirks
  • ...can be bipolar at times
  • ...and may refuse to see eye to eye with you on how to view the world you share 
  • (specifically...the state or value of objects in the active Javascript memory space)

Angular is NOT an "MVC" framework

it is maybe an "mVC"
(note the LITTLE "m")

but really it's not even that...it's more like a "WVC" framework
where the "W" stands for "whatever"

Angular doesn't care...it leaves the implementation up to you.

THAT'S A GOOD THING!!!


Implementing Your model is "up to You"!


Angular DOES give you some handy binding mechanisms,
but in the end they leave it to us developers to implement logic for managing our data...our models...our "state" data.
But it doesn't provide any predefined "Data Model Management" magic that many expect.
: (

So.... we have to think about our "Models", consider our options, 
and implement the solution we find best for OUR situation!
: )


Before we talk about "Managing Models in Angular",
we need to talk about...

WHAT MAKES UP A MODEL?

...and why should you care?


We're going to use MY perspective.

In my world...




"Models" are describable and definable data structures.


Models and State are the foundation and lifeblood of an app.

And - if you boil it down  - "state" is just data.
...and can be modeled.


So we just said that Models are "data"
...and that "state" is "data".

If we flip that a bit...this means we can expect that... 
"Your data WILL drive your state"
Whether you know it or not!

"State is data?!!?'    Need Proof??


Is my data loaded?
Is my data being reloaded?
Has my data reloaded?
Is my data being saved?
Is my data successfully saved?
Were there errors?
Have the functions that format my data run?
Is the related information to populate a list ready?
Does a user have permission to... ???

HOW DOES THIS AFFECT MY VIEW???

Model "Types" 


In my world it's not enough to simply define what a "model" is. 
We have different model 'types'...
...for different uses within the code base .


...it's important to specify 
...differentiate 
...understand

DTO Model

DTO = Data Transfer Object
A description of what will be sent back and forth between the server and the client. 
(the browser in our case).

// EXAMPLE DTO MODELvar User_1234_DtoModel = {
	first_name: 'Fred',
	last_name: 'Smith',
	birthdate: '19400511',
	zipcode: 01906
	children_count: 0,
	has_dog: 'true',
	has_cat: 'false',
	is_married: 'null'
	spouse_name: 'null'
	registered: '20140422';
	showSpecials: 'true'
}

Business Model

The model you WANT to work with in JS.
// EXAMPLE BUSINESS MODEL var User_1234_BusinessModel = {
	// has all the same properties as User_1234_DtoModel 
	// ...plus... 
	fullname: 'Fred Smith',
	age: 71,
	birthdate: Date("11/05/1940"),  // for doing date math
	birthdayForDisplay: "May 11, 1940", 
	registeredDate: Date("04/22/2014"), // for doing date math
	registeredDateForDisplay: "Yesterday",
	hasChildren: false,
	hasPets: true,
	isOlder40: true,
	locationForDisplay: "Saugus, Ma",
	isLoaded: true,
	errors: [{field: is_married, err_msg: "Married status is required" }]
}

View Model

A data structure with that extends a business model,
and adds view specific info to help us render our view.
 var User_1234_Homepage_ViewModel = {
	// + all the properties/methods User_1234_BusinessModel  ...plus... 
	isRegistered: true,
	isNewSignup: true,
	showNewSignupSpecial: true,
	showSeniorSpecial: true,
	showFamilySpecial: false,
	showPetOwnerSpecial: true,
	showSeniorCitizenPetOwnerSpecial: true,
	showDogOwnerSpecial: true,
	showCatOwnerSpecial: false,
	isUserBirthday: false,
	specialMessage: 
	 	"Welcome Fred, we have some specials for you near the 
	 	Saugus, MA area specifically for you.  
	 	Get additional savings with your senior citizen discount!"
}


okay...enough of that
let's start talking about
Models in Angular!

...not so fast!

First... 
Let's take a moment to do a QUICK overview of one 
BIG area of frustration for A LOT of front end developers.


"Understand the magic"


Before you dive into picking a solution for your model, you should get a quick grasp of some key javascript concepts that are often considered "not easy".

They will likely be important for you to understand - even if only at a high level - in whatever solution you end up implementing.

How do you transform one model type into anther?


One option...
Utility "helper functions" in a service or factory?
function UserDtoToBusinessModel(userDtoModel) {     ...     return usrBizModel; }
function UserBusinessToDashboardViewModel(userBusinessModel) {    ...     return usrDashViewModel;}
maybe there's something better?
 


Javascript
Scope, Closures, Prototype,
and Assignment


in 10 minutes...or less!

Scope, Closures, and COntext



If you don't define your scope and context...

When a function or reference is called in your code...,

you may find it points to something entirely
UNEXPECTED!




Scope and Context

From Ryan Morr

"JavaScript’s implementation of scope and context is a unique feature of the language, in part because it is so flexible. Functions can be adopted for various contexts and scope can be encapsulated and preserved. These concepts lend to some of the most powerful design patterns JavaScript has to offer. However, this is also a tremendous source of confusion amongst developers, and for good reason. "


It's worth reading more on...


http://doctrina.org/JavaScript:Why-Understanding-Scope-And-Closures-Matter.html

http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/


...google for more

Prototypes

Every object you create has a hidden "prototype" object associated with it.  

You get it whether you want it or not.
For larger application development...YOU WANT IT!

At a HIGH level, it's simply
a way to allow objects to share properties and references.
...and they can be "chained" together.

This has become Javascript's answer to "Classes" and "inheritance"




When you try to reference a property on an object,       Javascript will first try to find in that object's own scope.

If it's not found...it will look to see if that objects "prototype" has a property of that name, and will use that value if found.

If NOT found, it will look to see if that objects prototype references another prototype,
...and will continue looking up the chain.


Again...worth reading more on...



One of my favorites....



In the context of our Angular apps...
there is a bit more to understand.

READ THIS!

most important tidbit... bind to properties of objects on scope (i.e. your models)
NOT directly to properties directly on scope!

Your bindings and watch references should have a "." in them!
Good:   <H1>{{ user.name }}</H1>
Bad:   <H1>{{ userName }}</H1>


 10
changed // <- This is the one using the "." object reference! unchanged
produces console output:
Turns out this isn't just Angular
...this is how javascript works!
function changeStuff(num, obj1, obj2){
    num = num * 10;
    obj1.item = "changed";  // see the "."?  It makes a difference!
    obj2 = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);    
console.log(obj2.item);




Now...back to our Models


Let's describe a set of features we want for our models




Required essentials...

  • RESTFUL but "configurable" - Map to API REST service, with the ability to override defaults.
  • Ability to add "computed properties" to create my Business Models as the data is coming in (don't want to have extra adapter or filter functions for this if not necessary)
  • Caching - if I just requested it...I don't want to see it requested in the network traffic again


...nice to have...

  • Relationships - parent child references between models
    • Maybe with configurable auto load of children
  • Configurable caching on the individual model definitions
    • Limit cache size by number
    • Set expiration timeframe
    • Define which models cache, and which don't.
  • Configurable integration - Websockets???

Know where your Model should live

...even if it's taken care of by the solution you choose

It's actually helpful to understand where NOT to implement it.

Some guidelines:
Your model should NOT be managed in 
Angular Controllers or Directives.  
That leads to what is becoming termed as "scope soup".




Okay...now let's look at our options


  • Roll your own
  • Restangular
  • ngActiveResource
  • Breeze
  • Angular-Models



"Roll Your Own"
Angular model objects with Javascript classes
Cons:
You can already figure that out.
Pros:
You'll own the solution, and know it inside and out!

KEEP TRACK OF THIS ONE!
You'll use this approach for your ViewModels!

Roll Your Own ...continued
My Rules:
  • Your data objects should "live" in a Service, or a Factory
    ...NOT your Controllers or Directives!
  • You should persist your models in your Service/Factory
    ...and simply "inject & reference" in your Controllers and Directives.

  • Ideally you should create "constructors" that return an object with your "Business Model"...dynamically populated with your expected properties, CRUD handlers, and any transformational or "state management" properties or functions ... all in a nice neat package.
  • Any code responsible for initiating a request to the server to populate your Model  instances should live in/with them as references to your API integration layer.
  • Any code that transforms your data objects should live in either a filter, a utility/helper Service - and be injected here, or in the same Service as your data objects.
     

    As we're talking about updating data...

    One big "GOTCHA" to watch out for!

    DON'T CLOBER YOUR OBJECTS WITH OTHER OBJECTS!
    angular.module('MyThingModule') .service('MyThingModelService', function (MyRestSvc) {// assumes data loaded...  var _listModel = [{id:1, name: 'thing1}, {id: 5, 'thing 5'}, ....];  var _selectedModel = {id: 1, name: 'thing1', color: 'blue'};
    var getList = function(){// request list, update & return _listModel}; var getById = function(id) { // could wrap in check to see if exists in list MyRestSvc.get('thing', id).then(function(data) { /* DON'T DO: _selectedModel = data; BAD! Clobbers object & bindings */ /* DO: "copy" - Preserve object & bindings! */ angular.copy(data, _selectedModel);
    });   return _selectedModel; } return {getList: getList, getThing: getById};});


    Roll Your Own ... continued
    My Rules:
    • Your controllers should be kept SKINNY!   - Only expose handler references to your Service and view specific properties and methods.  (html will be shown on next slide)
    angular.module('myUser').controller('UserViewController', function($scope, MyThingModelService) {  var _thingModelSvc = MyThingModelService;  $scope.selectedId = 1;  // this might instead be passed in on $scope  $scope.initDone = false;  $scope.getNewThing = function(){ // don't care about the return this time                    _thingModelSvc.getThing($scope. selectedId)};  if (!$scope.initDone) { // don't process if multiple pass-throughs!    $scope.thingList = _thingModelSvc.getList();    $scope.currentThing = _thingModelSvc.getThing($scope.selectedId);  };});


    Roll Your Own... continued

           The view
     <div ng-controller="UserViewController">    <select ng-model="selectedId" ng-change="getNewThing()">     ...logic for creating option list...    </select>
    <p>   <b>name:</b> {{ currentThing.name }} <br/>   <b>color:</b> {{ currentThing.color }}  </p></div>


    But remember, you don't have to write
    ALL of the data integration and model layer!


    Projects/Modules/Libs to consider


    Disclaimer:   Rather than replicate what can be found elsewhere,  from here on we're going to look at the reference pages for these projects on the web...included on the following pages.


    Restangular


    Pros:
    The most widely used.
    Quite robust.
    A lot of community support.
    Actively developed.

    Cons:
    Not many that I can see.
    Caching is maybe not as robust as it could be.
    (personal preference)

    ngActiveResource


    Pros:
    nice implementation!
    Pretty robust

    Cons:
    Small community usage
    Doesn't feel like there's a ton of activity on it lately.

    BreezeJS


    Pros:
    Strong development
    Well supported
    Robust

    Cons:
    BIG
    Feels a bit cumberson
    NOT exclusively "Angular"

    Angular-Models



    Pros:
    NICE implementation
    Very cool features

    Cons:
    Still feels a little rough around the edges at times.

    Angular-Data


    Pros:  
    Clearly thought through...
    the developer has domain knowledge.

    Cons: 
    STILL BETA!   Argh!

    side note:  the sister project to this... Angular-Cache is quite nice!

    Wrap up


    You SHOULD manage your models.
    You will start to REALLY hate your job after  a while if you dont!

    Angular doesn't have built in features to support this.
    You have to select and/or implement a solution that works for you.

    If you don't yet understand the concepts of Javascript scope, closures, prototypes, etc... 
    Don't be afraid to learn a little bit more about them!
    Use the links here...google a bit.  
    Even a high level understanding will take you FAR!
    You'll want it if you intend to properly implement Models.

    Thank you!


    Stop by our website

    Check out our jobs
    It really is a GREAT place to work!


    Check out our Blog
    I've begun posting articles about "Front End Dev" there.
    Some Angular topics will be appearing there in the not too distant future!

    Managing the missing model in Angular JS

    By David Colwell

    Managing the missing model in Angular JS

    • 8,425