22
Oli Griffiths - @oligriffiths Custom Ember Data Adapters Self Defining Apps

Ember.js Self Defining Apps

Embed Size (px)

Citation preview

Page 1: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data

Adapters

Self Defining

Apps

Page 2: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adapters

Page 3: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adapters

• Interface between Ember Data identity mapper store and some external data store

• Provides methods to find, create, update and delete records in external data store

• External data store can be anything you like, REST API, SOAP API, RSS Feed, LocalStorage…

Page 4: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adapters

//Set the adapter as the application adapter//Rest API adapterApp.ApplicationAdapter = DS.RestAdapter.extend() //Fixture (in memory only)App.ApplicationAdapter = DS.FixtureAdapter.extend()//Rails active record adapterApp.ApplicationAdapter = DS.ActiveModelAdapter.extend() //A custom adapterApp.ApplicationAdapter = CustomAdapter.extend()

Page 5: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adaptersvar CustomAdapter = DS.Adapter.extend({ /** @method find @param {DS.Store} store @param {subclass of DS.Model} type @param {String} id @return {Promise} promise */ find: function(store, type, url) {}, /** @private @method findAll @param {DS.Store} store @param {subclass of DS.Model} type @param {String} sinceToken @return {Promise} promise */ findAll: function(store, type) {},

Page 6: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adapters/** @private @method findQuery @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} query @param {DS.AdapterPopulatedRecordArray} recordArray @return {Promise} promise */findQuery: function(store, type, query, array) {},/** @method createRecord @param {DS.Store} store @param {subclass of DS.Model} type @param {DS.Model} record @return {Promise} promise */createRecord: function(store, type, record) {},

Page 7: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adapters

/** @method updateRecord @param {DS.Store} store @param {subclass of DS.Model} type @param {DS.Model} record @return {Promise} promise */updateRecord: function(store, type, record) {},/** @method deleteRecord @param {DS.Store} store @param {subclass of DS.Model} type @param {DS.Model} record @return {Promise} promise */deleteRecord: function(store, type, record) {}

Page 8: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

REST Adapter Example

find: function(store, type, id) { return this.ajax(this.buildURL(type.typeKey, id), 'GET');}, findAll: function(store, type, sinceToken) { var query; if (sinceToken) { query = { since: sinceToken }; } return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });}, findQuery: function(store, type, query) { return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });},

Page 9: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

REST Adapter ExamplecreateRecord: function(store, type, record) { var data = {}; var serializer = store.serializerFor(type.typeKey); serializer.serializeIntoHash(data, type, record, { includeId: true }); return this.ajax(this.buildURL(type.typeKey), "POST", { data: data });}, updateRecord: function(store, type, record) { var data = {}; var serializer = store.serializerFor(type.typeKey); serializer.serializeIntoHash(data, type, record); var id = get(record, 'id'); return this.ajax(this.buildURL(type.typeKey, id), "PUT", { data: data });}, deleteRecord: function(store, type, record) { var id = get(record, 'id'); return this.ajax(this.buildURL(type.typeKey, id), "DELETE"); },

Page 10: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Custom Ember Data Adapters

• Do not store data within the adapter

• Merely transport data from the local data store to some “external” data store

• Serializers are used to convert the data format to/from the local object representation to/from the “external” data store format

Page 11: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Self Defining Apps

Page 12: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

What is a Self Defining App?

• When the full functionality of an app is unknown at “build time” (when the developer writes the application)

• Additional app functionality is created at runtime based on external dependencies

• Thus the app “builds” itself whilst running

Page 13: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Ember: route first mentality

PizzaRoute

PizzaController

PizzaModel

PizzaView

Page 14: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

What if your routes are unknown at build time?

?Route

?Controller

?Model

?View

Page 15: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

What if your routes are unknown at build time?

• You have a problem, everything depends on routes

• Without defined routes, transitioning to a view is impossible

• Some websites do not have pattern-able routes, so how can you define routes at “build time”

Page 16: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

So how can we handle this?

• Wild card routes allow you to register a route in the eventuality that no corresponding route is found

• Wild card routes are intended to catch when a user tries to transition to an undefined route and show an error page

• We can use this functionality to our advantage to build new routes at runtime

Page 17: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

So how can we handle this?• Here is the flow:

1. In the model hook, create an ember valid route name based off the URL being transitioned to

2. Make an ajax request to the URL you’re attempting to transition to (swap .html to .json, or however your API works)

3. Extract an identifying property from the response, perhaps “type” or “model”

4. Register the URL (path) against the created route name from (1)

Page 18: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

So how we can handle this?

5. Register a new route instance in the application container, manually setting the controller, view and template name

6. Transition to the newly defined route

Page 19: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

What’s this look like?App.CatchAllRoute = Ember.Route.extend({ model: function(params, transition) { //Get the URL and convert to route name var url = transition.intent.url; var route_name = Ember.String.classify(url.replace(/[\.|\-|\/]+/g,'_')); //Check if route already exists, if so, transition to it var route = route_name ? this.container.resolve('route:'+route_name) : null; if(route) return this.transitionTo(route_name); //Get the data loader and load the data for the destination url var resolver = this.container.lookup(‘resolver:entity'); //Make an ajax request to the endpoint to get the endpoint data return resolver.request(url).then(function(data){ //Get the type from the response model property var type = data.model; //If no route is set (index) then set the route name to the type if(!route_name) route_name = type;

Page 20: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

What’s this look like?

//Add a new route for the url in questionApp.Router.map(function(){ this.resource(route_name, {path: url});});//Register new route, manually setting the controller,template and view namesthis.container.register('route:'+route_name, Ember.Route.extend({ controllerName: type, viewName: type, templateName: type, !

model: function(){ var plural = type.substr(-1) == 's'; var name = plural ? type.substr(0, type.length-1) : type; if(!plural) return this.store.find(name, url); return this.store.filter(name, {url: url}, function(entity){

//filter model data if applicable }.bind(this)); }

}));

Page 21: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

What’s this look like?!//Transition to new routereturn this.transitionTo(route_name); }.bind(this), function(data){ //Force a manual page change document.location.href = url; });

! } }) !App.ApplicationView = Ember.View.extend({ didInsertElement: function() {

//Setup click handler to trigger transitionthis.$().on('click', 'a', function(e){ var a = $(e.target).closest('a'); //Ensure only links on this domain are captured if(a.prop('origin') != document.location.origin) return; //Stop default browser handler e.preventDefault(); ! //Now you can transition to any route within a view using a links url this.controller.transitionToRoute(a.prop(‘pathname’)); })

} })

Page 22: Ember.js Self Defining Apps

Oli Griffiths - @oligriffiths

Demo time