Skip to content

Instantly share code, notes, and snippets.

@millermedeiros
Created September 20, 2011 20:39
Show Gist options
  • Select an option

  • Save millermedeiros/1230246 to your computer and use it in GitHub Desktop.

Select an option

Save millermedeiros/1230246 to your computer and use it in GitHub Desktop.
AbstractModel.js
define(['jquery'], function($){
var DEFAULT_DATA_TYPE = 'json';
/**
* Abstract REST service model.
* @author Miller Medeiros
* @version 0.3.1 (2011/09/21)
* @param {object} [services] Services
* @see AbstractModel.services
* @constructor
*/
function AbstractModel(services){
/**
* Object that contains info about ajax calls
* `normalize` is a function that gets called after data is loaded
* `params` is an alias to jquery.ajax.data (since data is a bad name)
* it accepts all settings of a $.ajax() call.
* @type {id:string, {url:string [, normalize:function, dataType:string, type:string, params:(object|string)]}}
*/
this.services = services;
this._deferreds = {}; //cache deferreds and consequently the data as well
}
AbstractModel.prototype = {
/**
* Make an ajax request and
* @param {string} serviceId ID of the service that should be called.
* @param {object|string} [params] Request parameters (will overwrite service.params)
* @return {$.Deferred}
*/
loadData : function(serviceId, params){
var uid = this._getUid(serviceId, params),
dfd = this._getDeferred(uid),
service = this.services[serviceId],
settings;
if(! dfd.isResolved()){ //only load if data not cached yet
settings = $.extend({}, service, {
dataType : service.dataType || DEFAULT_DATA_TYPE,
data : params || service.params || service.data
});
$.ajax(settings).done(function(info){
info = service.normalize? service.normalize(info) : info;
dfd.resolve(info);
});
}
return dfd.promise();
},
_getUid : function(id, params){
params = params || '';
params = (typeof params === 'object')? $.param(params) : params;
return id +'-'+ params;
},
_getDeferred : function(id){
return (this._deferreds[id] = this._deferreds[id] || new $.Deferred());
},
/**
* Search items by matching a property with a value.
* @param {array} items Haystack.
* @param {string} propName Property to search for (e.g. 'id', 'name')
* @param {*} val Value to match against.
*/
find : function(items, propName, val){
var i = 0, n = items.length, cur;
while(i < n){
cur = items[i++];
if(cur[propName] === val){
return cur;
}
}
}
};
return AbstractModel;
});
{
"projects" : [
{
"id" : "1",
"title" : "Foo bar",
"clientName" : "Foo",
"thumb" : "portfolio/foo-tmb.jpg",
"video" : "portfolio/foo.mp4",
"quote" : "Excepteur sint occaecat cupidatat non proident.",
"copy" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt."
},
{
"id" : "222",
"title" : "Lorem Ipsum",
"clientName" : "qwe qweqwe",
"thumb" : "portfolio/lorem-tmb.jpg",
"video" : "portfolio/lorem.mp4",
"quote" : "Ut enim ad minim veniam.",
"copy" : "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia."
},
{
"id" : "55",
"title" : "Duis aute irure",
"clientName" : "qwe qweqwe",
"thumb" : "portfolio/lorem-tmb.jpg",
"video" : "portfolio/lorem.mp4",
"quote" : "Duis aute irure dolor in reprehenderit.",
"copy" : "Consectetur adipisicing elit, sed do eiusmod tempor incididunt."
}
]
}
define(
[
'jquery',
'core/AbstractModel'
],
function($, AbstractModel){
var _model = new AbstractModel();
//register RESTful services
_model.services = {
projects : {
url : 'rest/projects.json',
dataType : 'json',
normalize : normalizeProjectsData
}
};
function normalizeProjectsData(data){
if(data && data.projects){
$.each(data.projects, function(i, project){
project.slug = project.title.toLowerCase().replace(/\s+/g, '-');
});
data = data.projects;
}
return data;
}
function loadAllProjects(){
return _model.loadData('projects');
}
//depending on the project it would be a better to have a different
//service just to grab info by Id, but on this case since app will
//always need "all projects" data just reuse same service and create
//a new deferred object at each call (also to show how to use
//`AbstractModel.find()` and why it exists)
function loadProjectById(id){
var dfd = new $.Deferred();
loadAllProjects().done(function(data){
dfd.resolve( _model.find(data, 'id', id) );
});
return dfd.promise();
}
//API
return {
loadAllProjects : loadAllProjects,
loadProjectById : loadProjectById
};
}
);
@millermedeiros
Copy link
Author

Just an example of how to use $.Deferred to cache Ajax responses and how to use an AbstractModel to simplify logic and make code reusable... you can just keep adding new services to the Model class while keeping the code organized.

The service.normalize setting is also very useful when you need to do some processing on the data before returning it (it will cache the processed data) - for me it's very common to need some kind of manipulation before actually consuming the data...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment