mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
added $xhr service with bulk and cache, hooked up $resource
This commit is contained in:
parent
913729ee01
commit
c7913a4b7a
8 changed files with 197 additions and 11 deletions
4
scenario/cross-site-post/People.json
Normal file
4
scenario/cross-site-post/People.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[
|
||||
{ name: 'Misko', favorite: ['water melon', 'persimmon', 'passion fruit'] },
|
||||
{ name: 'Lenka', favorite: ['strawberry'] }
|
||||
]
|
||||
10
scenario/cross-site-post/index.html
Normal file
10
scenario/cross-site-post/index.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<script type="text/javascript" src="../../src/angular-bootstrap.js#autobind"></script>
|
||||
</head>
|
||||
<body ng:init="$window.$scope = this; People = $resource('People.json')">
|
||||
<button ng-click="people = People.query()">Load People</button>
|
||||
<pre>people = {{people}}</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -231,12 +231,12 @@ function isLeafNode (node) {
|
|||
|
||||
function copy(source, destination){
|
||||
if (!destination) {
|
||||
if (!source) {
|
||||
return source;
|
||||
} else if (isArray(source)) {
|
||||
if (isArray(source)) {
|
||||
return copy(source, []);
|
||||
} else {
|
||||
} else if (isObject(source)) {
|
||||
return copy(source, {});
|
||||
} else {
|
||||
return source;
|
||||
}
|
||||
} else {
|
||||
if (isArray(source)) {
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@ Browser.prototype = {
|
|||
head.append(link);
|
||||
},
|
||||
|
||||
xhr: function(method, url, callback){
|
||||
xhr: function(method, url, post, callback){
|
||||
var xhr = new this.XHR();
|
||||
xhr.open(method, url, true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
callback(xhr.status, xhr.responseText);
|
||||
callback(xhr.status || 200, xhr.responseText);
|
||||
}
|
||||
};
|
||||
xhr.send('');
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ function createScope(parent, services, existing) {
|
|||
}
|
||||
|
||||
function inject(name){
|
||||
var service = getter(servicesCache, name), factory, args = [];
|
||||
var service = getter(servicesCache, name, true), factory, args = [];
|
||||
if (isUndefined(service)) {
|
||||
factory = services[name];
|
||||
if (!isFunction(factory))
|
||||
|
|
@ -189,7 +189,7 @@ function createScope(parent, services, existing) {
|
|||
foreach(services, function(_, name){
|
||||
var service = inject(name);
|
||||
if (service) {
|
||||
instance[name] = service;
|
||||
setter(instance, name, service);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -189,7 +189,88 @@ angularService('$route', function(location, params){
|
|||
return $route;
|
||||
}, {inject: ['$location']});
|
||||
|
||||
angularService('$resource', function(browser){
|
||||
var resource = new ResourceFactory(bind(browser, browser.xhr));
|
||||
angularService('$xhr', function($browser){
|
||||
var self = this;
|
||||
return function(method, url, post, callback){
|
||||
if (post && isObject(post)) {
|
||||
post = toJson(post);
|
||||
}
|
||||
$browser.xhr(method, url, post, function(code, response){
|
||||
try {
|
||||
if (isString(response) && /^\s*[\[\{]/.exec(response) && /[\}\]]\s*$/.exec(response)) {
|
||||
response = fromJson(response);
|
||||
}
|
||||
callback(code, response);
|
||||
} finally {
|
||||
self.$eval();
|
||||
}
|
||||
});
|
||||
};
|
||||
}, {inject:['$browser']});
|
||||
|
||||
angularService('$xhr.bulk', function($xhr){
|
||||
var requests = [],
|
||||
callbacks = [],
|
||||
scope = this;
|
||||
function bulkXHR(method, url, post, callback) {
|
||||
requests.push({method: method, url: url, data:post});
|
||||
callbacks.push(callback);
|
||||
}
|
||||
bulkXHR.url = "/bulk";
|
||||
bulkXHR.flush = function(callback){
|
||||
var currentRequests = requests,
|
||||
currentCallbacks = callbacks;
|
||||
requests = [];
|
||||
callbacks = [];
|
||||
$xhr('POST', bulkXHR.url, {requests:currentRequests}, function(code, response){
|
||||
foreach(response, function(response, i){
|
||||
try {
|
||||
(currentCallbacks[i] || noop)(response.status, response.response);
|
||||
} catch(e) {
|
||||
self.$log.error(e);
|
||||
}
|
||||
});
|
||||
(callback || noop)();
|
||||
});
|
||||
scope.$eval();
|
||||
};
|
||||
return bulkXHR;
|
||||
}, {inject:['$xhr']});
|
||||
|
||||
angularService('$xhr.cache', function($xhr){
|
||||
var inflight = {};
|
||||
function cache(method, url, post, callback){
|
||||
if (method == 'GET') {
|
||||
var data;
|
||||
if (data = cache.data[url]) {
|
||||
callback(200, copy(data.value));
|
||||
} else if (data = inflight[url]) {
|
||||
data.callbacks.push(callback);
|
||||
} else {
|
||||
inflight[url] = {callbacks: [callback]};
|
||||
cache.delegate(method, url, post, function(status, response){
|
||||
if (status == 200)
|
||||
cache.data[url] = { value: response };
|
||||
foreach(inflight[url].callbacks, function(callback){
|
||||
try {
|
||||
(callback||noop)(status, copy(response));
|
||||
} catch(e) {
|
||||
self.$log.error(e);
|
||||
}
|
||||
});
|
||||
delete inflight[url];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
cache.delegate(method, url, post, callback);
|
||||
}
|
||||
}
|
||||
cache.data = {};
|
||||
cache.delegate = $xhr;
|
||||
return cache;
|
||||
}, {inject:['$xhr']});
|
||||
|
||||
angularService('$resource', function($xhr){
|
||||
var resource = new ResourceFactory($xhr);
|
||||
return bind(resource, resource.route);
|
||||
}, {inject: ['$browser']});
|
||||
}, {inject: ['$xhr.cache']});
|
||||
|
|
|
|||
|
|
@ -120,4 +120,13 @@ describe("resource", function() {
|
|||
nakedExpect(visa).toEqual({id:123});
|
||||
});
|
||||
|
||||
it('should excersize full stack', function(){
|
||||
var scope = angular.compile('<div></div>');
|
||||
var Person = scope.$resource('/Person/:id');
|
||||
scope.$browser.xhr.expectGET('/Person/123').respond('\n{\nname:\n"misko"\n}\n');
|
||||
var person = Person.get({id:123});
|
||||
scope.$browser.xhr.flush();
|
||||
expect(person.name).toEqual('misko');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -159,6 +159,88 @@ describe("service", function(){
|
|||
});
|
||||
});
|
||||
|
||||
describe('$xhr', function(){
|
||||
var log, xhr;
|
||||
function callback(code, response) {
|
||||
expect(code).toEqual(200);
|
||||
log = log + toJson(response) + ';';
|
||||
};
|
||||
|
||||
beforeEach(function(){
|
||||
log = '';
|
||||
xhr = scope.$browser.xhr;
|
||||
});
|
||||
|
||||
it('should forward the request to $browser and decode JSON', function(){
|
||||
xhr.expectGET('/reqGET').respond('first');
|
||||
xhr.expectGET('/reqGETjson').respond('["second"]');
|
||||
xhr.expectPOST('/reqPOST', {post:'data'}).respond('third');
|
||||
|
||||
scope.$xhr('GET', '/reqGET', null, callback);
|
||||
scope.$xhr('GET', '/reqGETjson', null, callback);
|
||||
scope.$xhr('POST', '/reqPOST', {post:'data'}, callback);
|
||||
|
||||
xhr.flush();
|
||||
|
||||
expect(log).toEqual('"third";["second"];"first";');
|
||||
});
|
||||
|
||||
describe('bulk', function(){
|
||||
it('should collect requests', function(){
|
||||
scope.$xhr.bulk.url = "/";
|
||||
scope.$xhr.bulk('GET', '/req1', null, callback);
|
||||
scope.$xhr.bulk('POST', '/req2', {post:'data'}, callback);
|
||||
|
||||
xhr.expectPOST('/', {
|
||||
requests:[{method:'GET', url:'/req1', data: null},
|
||||
{method:'POST', url:'/req2', data:{post:'data'} }]
|
||||
}).respond([
|
||||
{status:200, response:'first'},
|
||||
{status:200, response:'second'}
|
||||
]);
|
||||
scope.$xhr.bulk.flush(function(){ log += 'DONE';});
|
||||
xhr.flush();
|
||||
expect(log).toEqual('"first";"second";DONE');
|
||||
});
|
||||
});
|
||||
|
||||
describe('cache', function(){
|
||||
var cache;
|
||||
beforeEach(function(){ cache = scope.$xhr.cache; });
|
||||
it('should cache requests', function(){
|
||||
xhr.expectGET('/url').respond('first');
|
||||
cache('GET', '/url', null, callback);
|
||||
xhr.flush();
|
||||
xhr.expectGET('/url').respond('ERROR');
|
||||
cache('GET', '/url', null, callback);
|
||||
xhr.flush();
|
||||
expect(log).toEqual('"first";"first";');
|
||||
});
|
||||
|
||||
it('should serve requests from cache', function(){
|
||||
cache.data.url = {value:'123'};
|
||||
cache('GET', 'url', null, callback);
|
||||
expect(log).toEqual('"123";');
|
||||
});
|
||||
|
||||
it('should keep track of in flight requests and request only once', function(){
|
||||
cache.delegate = scope.$xhr.bulk;
|
||||
xhr.expectPOST('/bulk', {
|
||||
requests:[{method:'GET', url:'/url', data: null}]
|
||||
}).respond([
|
||||
{status:200, response:'123'},
|
||||
]);
|
||||
cache('GET', '/url', null, callback);
|
||||
cache('GET', '/url', null, callback);
|
||||
cache.delegate.flush();
|
||||
xhr.flush();
|
||||
expect(log).toEqual('"123";"123";');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue