mgechev / angular-aop Goto Github PK
View Code? Open in Web Editor NEWLibrary for aspect-oriented programming with AngularJS.
Library for aspect-oriented programming with AngularJS.
Hi,
This issue is for a feature
I would like to have a way to change the args in the join-point. Some AOP lib have something like:
joinpoint.proceed(newArg1, newArg2, ...)
where:
I currently am forced to modify the joinpoint.args which is not very clean and also does not allow aspects like memoize as the original method is always invoked.
Cheers,
Jose
I've been trying to integrate aop for logging, and followed both the README
and a post you've made, with no luck.
My typescript:
/// <reference path="/typings/angularjs/angular.d.ts" />
interface Window { TEST : any; }
module MyApp {
"use strict";
export function boot(
$log : ng.ILogService
) {
$log.info("starting");
}
angular
.module("my_app", [
"uuid4",
"ngTouch",
"AngularAOP"
])
.factory("log_aspect", [() => {
return (data : any) => {
console.log("==== HELLO ====");
console.log(data);
};
}])
.factory("DummyService", [() => {
return {
foo: () => { console.log("---- foo ----"); },
bar: (a : any, b : any) => {
console.log("---- bar ----", a, b);
return a * b;
}
};
}])
.controller("BusController", [
"DummyService",
(DummyService : any) => {
DummyService.foo();
DummyService.bar(2, 3.14);
}
])
.config( ($provide : any, executeProvider : any) => {
executeProvider.annotate($provide, {
DummyService: [{
jointPoint: "after",
advice: "log_aspect"
}]
});
})
.run([
"$log",
window.TEST ? () => {} : boot
]);
}
and compiled js:
var MyApp;
(function (MyApp) {
"use strict";
function boot($log) {
$log.info("starting");
}
MyApp.boot = boot;
angular.module("my_app", [
"uuid4",
"ngTouch",
"AngularAOP"
]).factory("log_aspect", [function () {
return function (data) {
console.log("==== HELLO ====");
console.log(data);
};
}]).factory("DummyService", [function () {
return {
foo: function () {
console.log("---- foo ----");
},
bar: function (a, b) {
console.log("---- bar ----", a, b);
return a * b;
}
};
}]).controller("BusController", [
"DummyService",
function (DummyService) {
DummyService.foo();
DummyService.bar(2, 3.14);
}
]).config(function ($provide, executeProvider) {
executeProvider.annotate($provide, {
DummyService: [{
jointPoint: "after",
advice: "log_aspect"
}]
});
}).run([
"$log",
window.TEST ? function () {
} : boot
]);
})(MyApp || (MyApp = {}));
with console output:
TypeError: undefined is not a function
at Object.AspectBuilder._getFunctionAspect (main.js:11417)
at Object.AspectBuilder._getObjectAspect (main.js:11434)
at AspectCollection.AspectBuilder.buildAspect [as after] (main.js:11412)
at main.js:11392
at Object.invoke (main.js:3944)
at Object.origProvider.$get (main.js:3896)
at Object.invoke (main.js:3944)
at main.js:3974
at getService (main.js:3930)
at Object.invoke (main.js:3942)
If there's any help you can provide it would be greatly appreciated! Really want to integrate this~
2015-02-14: Edited to port full typescript and compiled js
It would be great if an aspect had the ability to modify the arguments before they are forwarded to the original method and/or modify the return value before its returned to the consumer.
Thanks
Christian
I wish to use AngularAOP in a project I'm working on, the use case I'm thinking of would really benefit from being able to define pointcuts for the notify callback. Are there any plans of introducing this? If you are not able to work on it yourself: would you accept a pull request?
I'm using angular-aop to put an around advice for the ngResource I use to call server-side API. Like this:
myServices.factory('WelcomeService', [ '$resource', 'execute', 'MyAroundAspect',
function($resource, execute, ServerCommState ) {
return execute(MyAroundAspect).around( $resource('/api/welcome/:id', {
id: '@id'
}, {
create: {
method: 'POST',
params: {
nick: '@nick'
}
},
update: {
method: 'PUT'
}
}));
}
]);
When calling this service's get method, I get an undefined exception, unless I modify angular-aop.js like this:
//Builds specified aspect
AspectBuilder = {
buildAspect: function (advice, pointcut) {
var self = this;
return function (target, rules) {
// if (typeof target === 'function') {
// return self._getFunctionAspect(target, pointcut, advice);
// } else if (target) {
return self._getObjectAspect(target, rules || {}, pointcut, advice);
// }
};
},
As you may see, I modify the code so buildAspect always return an object aspect. With this modification, the MyAroundAspect gets called, twice per service call.
My solution is not an ideal one, but I'm not using function aspects, so that's fine for me. However, what should be done in order to enable AOP for ngResource without disabling function advices ?
First of all thanks for this awesome package.
My issue is that I noticed that the resolveArgs parameter seems to be always an empty object. I replicated this with the example ArticlesCollection service.
Service:
angular.module('core').factory('ArticlesCollection', function ($q, $timeout) {
var sampleArticles = [
{ id: 0, title: 'Title 1', content: 'Content 1' },
{ id: 1, title: 'Title 2', content: 'Content 2' },
{ id: 2, title: 'Title 3', content: 'Content 3' }
],
privateArticles = [
{ id: 3, title: 'Title 4', content: 'Content 4' },
{ id: 4, title: 'Title 5', content: 'Content 5' }
],
api = {
loadArticles: function () {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve(sampleArticles);
}, 1000);
return deferred.promise;
},
getArticleById: function (id) {
for (var i = 0; i < sampleArticles.length; i += 1) {
if (sampleArticles[i].id === id) {
return sampleArticles[i];
}
}
return undefined;
},
getPrivateArticles: function () {
return privateArticles;
}
};
return api;
});
Logger:
angular.module('core').factory('Logger', function () {
return function (args) {
console.log(angular.toJson(args));
};
});
Angular-aop config:
angular.module('core').config(function ($provide, executeProvider) {
executeProvider.annotate($provide, {
ArticlesCollection: [
{
jointPoint: executeProvider.ON_RESOLVE,
advice: 'Logger'
},
{
jointPoint: executeProvider.AFTER_RESOLVE,
advice: 'Logger'
}
]
});
});
Karma test:
(function () {
ddescribe('ArticlesCollection Service Tests', function () {
var service;
// Then we can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function ($templateCache, $rootScope, _ArticlesCollection_, $timeout) {
service = _ArticlesCollection_;
}));
it('loadArticles should return articles', inject(function ($timeout) {
service.loadArticles().then(function(articles) {
console.log('articles:' + articles);
expect(articles.length).toEqual(3);
});
$timeout.flush();
}));
});
}());
Test Results:
Running "karma:unit" (karma) task
INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Windows 8 0.0.0)]: Connected on socket vJLU_9iOvsW-83cbU21Z with id 41041485
LOG: '{"when":"onResolve","method":"loadArticles","args":[],"resolveArgs":{}}'
LOG: 'articles:[object Object],[object Object],[object Object]'
LOG: '{"when":"afterResolve","method":"loadArticles","args":[],"resolveArgs":{}}'
PhantomJS 1.9.8 (Windows 8 0.0.0): Executed 1 of 228 SUCCESS (0.121 secs / 0.038 secs)
To me the resolveArgs attribute sounds like it should contain the argument the deferred.resolve() returns, in this case the sampleArticles array. Please correct me if my understanding is wrong. Thanks.
While it's logical when you're thinking about, it would be nice to have this outlined in the documentation. This was surprising to stumble upon considering that it was caused by indirect dependency.
Hello,
This lib seems not to work with IE9. Is IE9 supported?
Please provide an example using AngularAOP to intercept every controller and directive methods()
Minko,
One BIG downside of AOP is it makes it harder to debug methods that have aspects applied. One pain point is that when inspecting objects in say chrome developer tools you no longer can hover over a method on an object and see a preview of the method.
Now you have to drill down through multiple levels of wrappers to see this preview as per the attached screen shot
One way to reduce this pain is to reduce this nesting. Instead of creating a wrapper for each aspect that is applied to a method, I think a better alternative would be to maintain a single wrapper that collects all the aspects that have been applied to the method. This single wrapper would maintain a stack for each pointcut.
When inspecting an object in the locals window of chrome you would be able to expand each stack to see the list of aspects applied.
Without the above, I think code decorated using the angular-aop library will be too much of a pain to work with once aspects start to pile up on top of one another.
What do you think?
Christian
It's possible that a public method of an angular service will be called as a "standalone" function without a function receiver being defined - eg: someFunction.call(null)
When this happens and the original method was created as an anonymous function then the name of the function cannot be determined.
I have a solution to this: remember the name of the service property to which the function was originally bound. I'm going to send a pull request for this...
Hi there,
Currently, I see that AngularAOP on has the support for advising Angular's service. However, it might be useful if it can support advising controllers as well, because you can have Authorization, Exception handling in controllers, not only in services.
Would be very nice to have that,
Cheers
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.