js-data

Eugen Istoc

About Me

  • Georgia Tech Alumni, (BS, 2012, MS 2016)
  • AT&T 3 years
  • Front end developer 2 years

Fun Facts

  • Originally from Romania
  • Working on a theology degree at DTS
  • Love to play soccer

js-data

"Respect your data"

Agenda

  • Background

  • What problem is JS-Data solving?

  • Examples

  • More resources

angular.module('app').controller('Ctrl1', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });

    $http.get('/posts').then(function(posts){
        $scope.posts = posts;
    });
    
    $http.get('/comments').then(function(comments){
        $scope.users = comments;
    });
});

Simple Example

angular.module('app').controller('Ctrl2', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });  

    $http.get('/profiles').then(function(users){
        $scope.profiles = profiles;
    });  
});

A more complex example

A more complex example (cont)

angular.module('app').controller('Ctrl1', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });

    $http.get('/posts').then(function(posts){
        $scope.posts = posts
    });

    $http.get('/comments').then(function(comments){
        $scope.comments = comments;
    });
});

angular.module('app').controller('Ctrl2', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });

    $http.get('/profiles').then(function(profiles){
        $scope.profiles = profiles
    });
});

angular.module('app').controller('Ctrl3', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });

    $http.get('/comments').then(function(comments){
        $scope.comments = comments;
    });
});

angular.module('app').controller('Ctrl5', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });

    $http.get('/comments').then(function(comments){
        $scope.comments = comments;
    });

    $http.get('/profiles').then(function(profiles){
        $scope.profiles = profiles
    });
});

Common Solution: Services

Introducing a service layer

Introducing a service layer

angular.module('app').controller('Ctrl1', function ($scope, $http) {
    $http.get('/users').then(function(users){
        $scope.users = users;
    });

    $http.get('/posts').then(function(posts){
        $scope.posts = posts
    });

    $http.get('/comments').then(function(comments){
        $scope.comments = comments;
    });
});
angular.module('app').controller('Ctrl1', function ($scope, UesrService, PostService, CommentService) {
    UserService.get().then(function(users){
        $scope.users = users;
    });

    PostService.get().then(function(posts){
        $scope.posts = posts;
    });

    CommentService.get().then(function(comments){
        $scope.comments = comments;
    });
});

Advantages

  • Singleton
  • Progressive updates

Disadvantages

  • Hard to model complex data
  • Hard to work with complex relational data
  • Tightly coupled to application and framework (Angular)

Complex Data

Complex Data (cont)

angular.module('app').service('EventService', function ($q, $http) {
    this.getAll = function(){
        return $http.get('/events');
    }

    this.getEventsAndLocations = function(){
        var deferred = $q.defer(), eventsAndLocations = [];

        // One to Many relations (One location can have multiple events)
        $http.get('/events').then(function(events){
            events.forEach(function(event){
                $http.get('/locations', {id: event.Location_ID}).then(function(location){
                    event.location = location
                    eventsAndLocation.push(event);
                });
            });

            deferred.resolve(eventsAndLocations);
        });

        return deferred.promise;
    }
});
angular.module('app').service('EventService', function ($http) {
    this.getAll = function(){
        return $http.get('/events');
    }
});

Complex Data (cont)

angular.module('app').service('EventService', function ($q, $http) {
    this.getAll = function(){
        return $http.get('/events');
    }

    this.getEventsAndLocations = function(){
        ...
    }

    this.getEventsAndEventDefinitionCodes = function(){
        ...
    }

    this.getPeopleInEvent = function(event_id){
        ...
    }

    this.getPatternsInEvent = function(event_id){
        ...
    }
});

Enter JS-Data

Easy to set up

bower install js-data --save

Recognizable API

DS.find(id).then(function(){...});
DS.findAll().then(function(){...});

DS.destroy(id).then(function(){...});

DS.create(data).then(function(){...});

DS.update(id, data).then(function(){...});

Resource Definitions

var Event = store.defineResource({
  name: 'event',
  relations: {
    hasOne: {
      location: {
        localKey: 'Location_ID',
        localField: 'location'
      },
      event: {
        localKey: 'Next_Event_ID',
        localField: 'next_event'
      },
      event_definition: {
        localKey: 'Event_Definition_Code',
        localField: 'event_definition'
      }
    }
  }
});
var Location = store.defineResource({
  name: 'location',
  relations: {
    belongsTo: {
      event: {
        foreignKey: 'Location_ID',
      }
    }
  }
});
var EventDefinition = store.defineResource({
  name: 'event_definition',
  relations: {
    belongsTo: {
      event: {
        foreignKey: 'Event_Definition_code',
      }
    }
  }
});
Event.findAll() // http://www.example.com/events
Event.find(1) // http://www.example.com/event/1
Event.loadRelations(1, ['Location', 'event_definition'])

Features

Model Lifecycle Hooks

beforeCreate

beforeUpdate

afterUpdate

afterCreate

...etc

Relations

belongsTo

hasMany

hasOne

Features (cont.)

var User = store.DefineResource({
  name: 'user',
  actions: {
    fooStaticMethod: {
      method: 'POST'
    }
  }
});

User.barStaticMethod = function () {...};

User.fooStaticMethod();

User.barStaticMethod();

Static Methods

Instance Methods

var User = store.DefineResource({
  name: 'user',
  methods: {
    say: function () {
      return this.name;
    }
  }
});

var user = User.createInstance({
  name: 'John'
});

user.say(); // "John"

Features (cont.)

var User = store.DefineResource({
  name: 'user',
  computed: {
    fullName: ['first', 'last', function () {
      return this.first + ' ' + this.last;
    ]
  }
});

var user = User.inject({
  id: 1,
  first: 'John',
  last: 'Anderson'
});

user.fullName; // "John Anderson"

Computed Properties

Features (cont.)

var User = store.DefineResource('user'});

User.filter({
  where: {
    age: {
      '>': 18
    }
  }
}); // [{ id: 1, age: 30 }]

User.filter({
  age: 15
}); // [{id: 1,age: 15},{id: 3,age: 15}]

Queries

Features (cont.)

  • Change Detection
  • Cache expiration
  • Schemas + Validation

More Resources

Questions?

js-data

By genuchelu

js-data

  • 399