angularjs with oop inheritance in action - oop
Abstract
I'm working on an application that uses angular as a client side framework, angular currently rocks and I'm really happy using it, though now I find that I use to much copy and paste code that I would like to organize into class hierarchy. For example dialogs share a common set of functionality, they need to be opened, closed, the code that provides typeahead functionality is also a first candidate to inherit from some parent BaseTypeaheadClass, though one thing I didn't find in angular is a standard way of organising these hierarchies. Both controllers, services, providers use ordinary javascript functions underneath which can be extended by the means of prototype, so my question is:
Question
What is the angular way of organising my class functions, are there any standard mechanisms that will allow to derive one class from another
P.S.
My guesses on the problem:
Define implementation of base classes as services, as a result they will be easily injected into any controller or other services where that specific class will be needed
Define OOP service and provide methods such as define, derive, etc. that will be used to create base / derived classes
Edit
Some time has passed from time when I was initially asking my question. Since then I have come out with approach that I'm successfully using in several projects, that I like very much and want to share with everyone.
Currently angular doesn't provide any constructs for organising class hierarchies and it's a pity since more or less large application can't suffice only Model/View/Controller/... constructs, it has to organise it's code into OOP objects.
I'm working in the field of web-development for quite a long time already and I haven't seen even one enterprise project that was taking advantage of OOP with JavaScript massively. What I seen was huge and nicely organised server side / database side logic + close to infinite javascript spaghetti greased with zoo of frameworks and libraries on client side.
No MVVM, MVP frameworks such as knockout.js, backbone, other... are capable of replacing the OOP as such. If you are not using core principles of oriented programming such as Classes, Objects, Inheritance, Abstraction, Polymorphism you are in deep trouble, what you will end up is a mega long javascript spaghetti.
Regarding Angular I think it is a framework very much different from knockout.js / backbone.js / any other MVV-anything frameworks but according to my practice also it is not a silver bullet capable of replacing OOP. When I'm trying not to use the OOP with Angular I end up with duplicate logic located mostly in controllers. And unfortunately there is no (I have found no) clean and angular-way of beating that problem.
But I have successfully (I think) solved that problem.
I've used compact, zero-dependency lib that just implements John Resig's Simple JavaScript Inheritance (https://github.com/tracker1/core-js/blob/master/js-extensions/040-Class.js). With the help of that library I was able to create / inherit / create abstract methods / override them, in other words do everything that I've accustomed to on server side.
Here is an example usage:
Application.factory('SomeChildObject', ['$http', 'SomeParentClass', function ($http, SomeParentClass) {
var SomeChildClass = SomeParentClass.extend({
init: function() { // Constructor
this._super.init(123, 231); // call base constructor
},
someFunction: function() {
// Notice that your OOP now knows everything that can be injected into angular service, which is pretty cool :)
$http({method: 'GET', url: '/someUrl'}).then(function(){
this._super.someFunction(); // call base function implementation
});
}
});
// return new SomeChildClass(); // We are not returning instance here!
return SomeChildClass; // Service is a function definition not an instance of an object
}]);
// So now we can both use this service in angular and have the ability to extend it using the `extend` method call, like so:
Application.controller('MegaController', ['$scope', 'SomeChildClass', function ($scope, SomeChildClass) {
$scope.someObject = new SomeChildClass();
}]);
OOP + Angular play together very nicely, objects created under angular context can take advantage of dependency injection via services automatically, so you don't have to inject instances into your OOP constructors and this fact makes your OOP hierarchy very slim and free of irrelevant stuff that needs to be (and is) handled by angular.js
So play with this approach and give feedback here with results you gained or problems you encountered,
Another edit
Recently I've faced few problems with original Class.js implementation, as follows:
1) If you will be passing a reference to your instance methods as callbacks to other methods, these methods might work not the way you expect them to work. They will loose reference to this. In such case you will be expecting to see your current object inside this but it will be either top level Window or some other context object depending on how the callback calls your method. It happens due to JavaScript architecture. In order to fight this problem a special ClassMember function is provided which instructs Class to bind your method to object context when it is being created (check Usage below for further guidance).
2) Obviously original Class.js implementation doesn't know anything about angular type of controller method declarations i.e.
Class.extend('YourClassDisplayName', {
ctor: function () {
// Some useful constructor logic
},
controller: ['$scope', '$attrs', function ($scope, $attrs) {
// Do something with $scope and $attrs
}]
});
Current implementation understands above syntax
3) When using above approach without appropriate handling it would break angular $$annotate'on process so referring to above example it would make impossible to inject $scope and $attrs into into ClassMember method, or overridden method which is using this.base(...) calls. So this is also fixed.
Gotchas:
1) When using this.base(...) within async operation handler (something like $http.get(..., function() { self.base(...); })) please note that this.base(...) call has a limited lifetime and as soon as the method returns this.base(...) stops existing. So you should save reference to base method explicitly if you are planning to call base methods in asynchronous fashion. i.e:
...
var self = this;
var base = this.base;
...
$http.get(..., function () {
base.call(self, ...); // or base.apply(self, ...), or base() if you don't care about `this`
})
I've resolved all of the above problems (except one gotcha which can not be resolved due to JavaScript architecture) and would like to share with everyone, hope you will benefit from it:
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*
* Inspired by base2 and Prototype
* Angular adaptations by Denis Yaremov http://github.com/lu4
* Usage:
---------------------------------
var X = Class.extend('X', {
ctor: function () {
this.name = "I'm X";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var Y = Class.extend('Y', {
ctor: function () {
this.name = "I'm Y";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var x = new X();
var y = new Y();
x.myClassMemberMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myClassMemberMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
x.myOrdinaryMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myOrdinaryMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
y.theirOrdinaryMethod = x.myOrdinaryMethod;
y.theirClassMemberMethod = x.myClassMemberMethod;
y.theirOrdinaryMethod('a', 'b', 'c'); // ["I'm Y", "a", "b", "c"]
y.theirClassMemberMethod('u', 'v', 'm'); // ["I'm X", "u", "v", "m"]
*/
angular.module('app').factory('ClassMember', function () {
return function ClassMember(fn) {
if (this instanceof ClassMember) {
this.fn = fn;
} else {
return new ClassMember(fn);
}
};
});
angular.module('app').factory('Class', function (ClassMember) {
var runtime = { initializing: false },
fnTest = /xyz/.test(function() { xyz; }) ? /\bbase\b/ : /.*/,
FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var toString = Object.prototype.toString;
// The base Class implementation (does nothing)
function Class() { };
Class.members = { };
// Create a new Class that inherits from this class
Class.extend = function extend(displayName, properties) {
var array;
var targetMembers = {};
var sourceMembers = this.members;
for (var memberName in sourceMembers) {
if (sourceMembers.hasOwnProperty(memberName)) {
targetMembers[memberName] = sourceMembers[memberName];
}
}
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the ctor constructor)
runtime.initializing = true;
var prototype = new this();
runtime.initializing = false;
// Copy the properties over onto the new prototype
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
// Check if we're overwriting an existing function
var property = properties[name];
// Support angular's controller/service/factory declaration notation
if (toString.call(property) === '[object Array]') {
array = property;
var item = array[array.length - 1];
if (toString.call(item) === '[object Function]' || item instanceof ClassMember) {
property = array[array.length - 1];
} else {
array = null;
}
} else {
array = null;
}
var isClassMember = property instanceof ClassMember;
if (isClassMember) {
property = property.fn;
}
if (typeof property === "function") {
if (typeof base[name] === "function" && fnTest.test(property)) {
property = (function (propertyName, fn) {
var args = fn.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];
return (new Function('propertyName', 'fn', 'base', 'return function (' + args + ') {\n\
var prevBase = this.base;\n\
var hasBase = "base" in this;\n\
\n\
// Add a new .base() method that is the same method\n\
// but on the super-class\n\
\n\
this.base = base[propertyName];\n\
\n\
// The method only need to be bound temporarily, so we\n\
// remove it when we\'re done executing\n\
var ret = fn.call(this' + (!!args ? (', ' + args) : args) + ');\n\
\n\
if (hasBase) {\n\
this.base = prevBase;\n\
} else {\n\
delete this["base"];\n\
}\n\
return ret;\n\
}'))(propertyName, fn, base);
})(name, property);
}
if (isClassMember) {
targetMembers[name] = property;
} else if (name in targetMembers) {
delete targetMembers[name];
}
if (array) {
array[array.length - 1] = property;
property = array;
}
prototype[name] = property;
} else {
prototype[name] = property;
}
}
}
var membersArray = [];
for (var i in targetMembers) {
if (targetMembers.hasOwnProperty(i)) {
membersArray.push({ name: i, fn: targetMembers[i] });
}
}
// All construction is actually done in the ctor method
var ChildClass = (new Function("runtime", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {\n\
if (!runtime.initializing && this.ctor)\n\
{\n\
var length = members.length;\n\
for (var i = 0; i < length; i++)\n\
{\n\
var item = members[i];\n\
this[item.name] = (function (me, fn) {\n\
var args = fn.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];\n\
return args ? (new Function('me', 'fn', 'return function (' + args + ') { return fn.call(me, ' + args + '); }'))(me, fn) : function () { return fn.call(me); };\n\
})(this, item.fn);\n\
\n\
}\n\
this.ctor.apply(this, arguments);\n\
}\n\
}"))(runtime, membersArray, FN_ARGS, STRIP_COMMENTS);
ChildClass.members = targetMembers;
// Populate our constructed prototype object
ChildClass.prototype = prototype;
// Enforce the constructor to be what we expect
ChildClass.prototype.constructor = ChildClass;
// And make this class extendable
ChildClass.extend = extend;
return ChildClass;
};
return Class;
});
Another edit
Eventually I've stumbled upon another problem related to original John Resig's implementation in relation to angular, and the problem is related to angular's annotation process (used for dependency injection) which uses Function.prototype.toString() and some Regex'es for the purpose of extracting the names of dependencies. And the problem with original implementation is that it doesn't expect this and so you are not able to declare methods that accept dependencies, so I've tweaked the implementation a little bit to deal with previously described problem and here it is:
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*
* Inspired by base2 and Prototype
* Angular adaptations by Denis Yaremov http://github.com/lu4
* Usage:
---------------------------------
var X = Class.extend('X', {
ctor: function () {
this.name = "I'm X";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var Y = Class.extend('Y', {
ctor: function () {
this.name = "I'm Y";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var x = new X();
var y = new Y();
x.myClassMemberMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myClassMemberMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
x.myOrdinaryMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myOrdinaryMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
y.theirOrdinaryMethod = x.myOrdinaryMethod;
y.theirClassMemberMethod = x.myClassMemberMethod;
y.theirOrdinaryMethod('a', 'b', 'c'); // ["I'm Y", "a", "b", "c"]
y.theirClassMemberMethod('u', 'v', 'm'); // ["I'm X", "u", "v", "m"]
*/
angular.module('homer').factory('Class', function () {
function ClassMember(fn) {
if (this instanceof ClassMember) {
this.fn = fn;
return this;
} else {
return new ClassMember(fn);
}
}
function ClassEvent() {
if (this instanceof ClassEvent) {
return this;
} else {
return new ClassEvent();
}
}
var runtime = { initializing: false },
fnTest = /xyz/.test(function () { xyz; }) ? /\bbase\b/ : /.*/,
fnArgs = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
stripComments = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var toString = Object.prototype.toString;
// The base Class implementation (does nothing)
function Class() { };
Class.events = {};
Class.members = {};
// Create a new Class that inherits from this class
Class.extend = function Extend(displayName, properties) {
var array;
var targetEvents = {};
var sourceEvents = this.events;
var targetMembers = {};
var sourceMembers = this.members;
for (var eventName in sourceEvents) {
if (sourceEvents.hasOwnProperty(eventName)) {
targetEvents[eventName] = sourceEvents[eventName];
}
}
for (var memberName in sourceMembers) {
if (sourceMembers.hasOwnProperty(memberName)) {
targetMembers[memberName] = sourceMembers[memberName];
}
}
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the ctor constructor)
runtime.initializing = true;
var prototype = new this();
runtime.initializing = false;
// Copy the properties over onto the new prototype
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
// Check if we're overwriting an existing function
var property = properties[name];
// Support angular's controller/service/factory declaration notation
if (toString.call(property) === '[object Array]') {
array = property;
var item = array[array.length - 1];
if (toString.call(item) === '[object Function]' || item instanceof ClassMember) {
property = array[array.length - 1];
} else {
array = null;
}
} else {
array = null;
}
var isClassMember = property instanceof ClassMember;
if (isClassMember) {
property = property.fn;
}
var isClassEvent = property instanceof ClassEvent;
if (isClassEvent) {
property = (function() {
function Subscriber(fn) {
Subscriber.listeners.push(fn.bind(this));
};
Subscriber.listeners = [];
Subscriber.fire = function() {
var listeners = Subscriber.listeners;
for (var i = 0; i < listeners.length; i++) {
var result = listeners[i].apply(this, arguments);
if (result !== undefined) return result;
}
return void 0;
}
return Subscriber;
})();
}
if (typeof property === "function") {
if (typeof base[name] === "function" && fnTest.test(property)) {
property = (function (propertyName, fn) {
var args = fn.toString().replace(stripComments, '').match(fnArgs)[1];
return (new Function('propertyName', 'fn', 'base', 'return function (' + args + ') {\n\
var prevBase = this.base;\n\
var hasBase = "base" in this;\n\
\n\
// Add a new .base() method that is the same method\n\
// but on the super-class\n\
\n\
this.base = base[propertyName];\n\
\n\
// The method only need to be bound temporarily, so we\n\
// remove it when we\'re done executing\n\
var ret = fn.call(this' + (!!args ? (', ' + args) : args) + ');\n\
\n\
if (hasBase) {\n\
this.base = prevBase;\n\
} else {\n\
delete this["base"];\n\
}\n\
return ret;\n\
}'))(propertyName, fn, base);
})(name, property);
}
if (isClassEvent) {
targetEvents[name] = property;
} else {
delete targetEvents[name];
}
if (isClassMember) {
targetMembers[name] = property;
} else if (name in targetMembers) {
delete targetMembers[name];
}
if (array) {
array[array.length - 1] = property;
property = array;
}
prototype[name] = property;
} else {
prototype[name] = property;
}
}
}
var eventsArray = [];
for (var targetEventName in targetEvents) {
if (targetEvents.hasOwnProperty(targetEventName)) {
eventsArray.push({ name: targetEventName, fn: targetEvents[targetEventName] });
}
}
var membersArray = [];
for (var targetMemberName in targetMembers) {
if (targetMembers.hasOwnProperty(targetMemberName)) {
membersArray.push({ name: targetMemberName, fn: targetMembers[targetMemberName] });
}
}
// All construction is actually done in the ctor method
var ChildClass = (new Function("runtime", "events", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {\n\
if (!runtime.initializing && this.ctor)\n\
{\n\
var length = members.length;\n\
var bind = function (me, $$fn$$) {\n\
var args = $$fn$$.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];\n\
var result = args ? (new Function('me', '$$fn$$', 'return function (' + args + ') { return $$fn$$.apply(me, arguments); }'))(me, $$fn$$) : function () { return $$fn$$.apply(me, arguments); };\n\
return result;\n\
};\n\
for (var i = 0; i < length; i++)\n\
{\n\
var item = members[i];\n\
var fn = item.fn;\n\
var name = item.name;\n\
var property = this[name] = bind(this, fn);\n\
if (fn.fire) {\n\
property.fire = bind(this, fn.fire);\n\
}\n\
if (fn.listeners) {\n\
property.listeners = fn.listeners;\n\
}\n\
}\n\
\n\
var length = events.length;\n\
for (var i = 0; i < length; i++)\n\
{\n\
var item = events[i];\n\
var fn = item.fn;\n\
var name = item.name;\n\
var property = this[name] = bind(this, fn);\n\
if (fn.fire) {\n\
property.fire = bind(this, fn.fire);\n\
}\n\
if (fn.listeners) {\n\
property.listeners = fn.listeners;\n\
}\n\
}\n\
this.ctor.apply(this, arguments);\n\
}\n\
}"))(runtime, eventsArray, membersArray, fnArgs, stripComments);
ChildClass.members = targetMembers;
// Populate our constructed prototype object
ChildClass.prototype = prototype;
// Enforce the constructor to be what we expect
ChildClass.prototype.constructor = ChildClass;
// And make this class extendable
ChildClass.extend = Extend;
ChildClass.event = ClassEvent;
ChildClass.member = ClassMember;
return ChildClass;
};
Class.member = ClassMember;
Class.event = ClassEvent;
return Class;
});
Your guesses sounds perfectly applicable.
You can reuse functionality defined in parent controllers by simply calling methods attached to the parent scope:
HTML
<div ng-controller="ParentCtrl">
<!-- Something here ... -->
<div ng-controller="ChildCtrl">
<!-- Something here ... -->
</div>
<!-- Something here ... -->
</div>
JavaScript
function ParentCtrl($scope) {
$scope.parentMethod = function () {
//method body
};
}
function ChildCtrl($scope) {
$scope.childMethod = function () {
//functionality
$scope.parentMethod();
//functionality
};
}
If you want to use the JavaScript approach with prototype inheritance you can use:
var myApp = angular.module('myApp',[]);
function Parent($scope) {
$scope.name = 'Superhero';
$scope.clickParent = function() {
$scope.name = 'Clicked from base controller';
}
}
function Child($scope, $injector) {
debugger;
$injector.invoke(Parent, this, {$scope: $scope});
$scope.name = 'Superhero Child';
$scope.clickChild = function(){
$scope.clickParent();
}
}
Child.prototype = Object.create(Parent.prototype);
http://jsfiddle.net/mhevery/u6s88/12/
For services, for example, you can use:
(function () {
function ParentService(arg1) {
this.arg1 = arg1;
}
function ChildService(arg1, arg2) {
ParentService.call(this, arg1);
this.arg2 = arg2;
}
ChildService.prototype = new ParentService();
app.service('ChildService', ChildService);
}());
Also check this discussion and the blog post about inheritance in AngularJS I posted.
Let me give you my opinion on Angular / inheritance situation.
You don't do class/prototypical inheritance in Angular.js. It can be hard to test, and that is a problem. For those, who are looking for 'inheritance' in Angular, I recommend this:
Your base class is the controller. The controller is an abstract model anyways, so it is perfect for that purpose. Use a $scope.init() function in your controller, but don't call it from there!
If you want to 'extend' your controller's functionality, use directives. In you directive link() function, call the controller's $scope.init(). (when compiling, angular runs controllers first, and directive link functions after). If scope had a $scope.name='base', in the directive link you will be able to redefine $scope.name=child, and after that, run $scope.init().
But wait! But this only allows a single-level inheritance. - Yes, thats true. But if you are looking for multilevel inheritance, you should use Services.
Multilevel inheritance is nothing else, but sharing the same code in a hierarchical class structure. For this purpose, use Services, and throw in these services with the dependency injector into your directives. Soo easy. This should be easy to accomplish, easy to understand, and tests run smooth.
Directives are very powerful tools, because you can dynamically combine partials with controllers.
I think your guesses are pretty good and I played with a few approaches like that, but they all turned out more verbose than I had hoped.
I had a problem where I had developed a complex dialog as a tab in our admin interface, but I wanted an almost identical dialog in a popup in the user section, but the data would be populated from a different source and there would be a few additional buttons. Basically a great candidate for classical inheritance. For the UI side I used a template which was included in two places with different controllers. But to avoid duplicating the complex UI logic in the controllers I wanted to use inheritance.
The scope inheritance method relies somewhat on the structure of the application and wasn't appropriate because the two UIs were in effectively different applications. The approach of putting reused code into services would end up being verbose as I would have needed to have each controller method call an equivalent method on the service. So I used the following simple approach to JavaScript inheritance:
/**
* Effective base class for Thing Controllers.
* This should be considered abstract since it does not define
* $scope.readData() or $scope.saveData() which may be called from its
* other functions.
*/
function BaseThingController($scope, $http){
$scope.data = []; // local data store;
$scope.validateForm(){...}
$scope.edit(){...}
$scope.cancel(){...}
$scope.reset(){...}
$scope.otherMethod1(){...}
$scope.otherMethod2(){...}
$scope.otherMethod3(){...}
}
/**
* AdminThingController effectively extends BaseThingController
*/
function AdminThingController($scope, $http){
// Calling BaseThingController as a function defines all the needed
// functions and properties in our scope.
BaseThingController($scope, $http)
$scope.readData(){
// $scope.data = data from admin data source
}
$scope.saveData(newData){
// save to special admin service
}
// initialize local data
$scope.readData()
}
/**
* UserThingController effectively extends BaseThingController
*/
function UserThingController($scope, $http){
// Calling BaseThingController as a function defines all the needed
// functions and properties in our scope.
BaseThingController($scope, $http)
$scope.readData(){
// $scope.data = data from user data source
}
$scope.saveData(newData){
// save to user service
}
/**
* Overriding base class behaviour here
*/
$scope.otherMethod1(){...}
// initialize local data
$scope.readData()
}
So I've not used prototype inheritance as the $scope is readily available. But I have gained all the behaviour from the base controller and only added or overridden what I want to. My views could be configured with either controller and would work with no modifications.
Related
How to mock and expect a method with Action delegate as one of the parameter with Moq
I am using Automapper in my .net core application to map. I have a method like below public MyEntity TransformtoToEntity(MyDTO dto) { var entity = _mapper.Map<MyEntity, MyDTO>(dto, opts => opts.Items["isUpdate"] = "N"); return entity; } My test method looks like [Fact] public void Returns_Data_After_Mapping() { // Arrange var mockEntityData = new MyEntity { Id = 1, Name = "John" }; var mockDto = new MyDTO { Id = 1, Name = "John" }; var mappingOperationMock = new Mock<IMappingOperationOptions<MyDTO, MyEntity>>(MockBehavior.Strict); mappingOperationMock.Setup(x => x.Items).Returns(new Dictionary<string, object>() { { "isUpdate", "N" }}); _mapper.Setup(x => x.Map(It.IsAny<MyDTO>(), It.IsAny<Action<IMappingOperationOptions<MyDTO, MyEntity>>>())) .Returns(mockEntityData); // Act var result = _myMapper.TransformDtoToEntity(mockDto); // Assert Assert.NotNull(result); _mapper.VerifyAll(); mappingOperationMock.VerifyAll(); } Here how can I verify that IMappingOperationOptions parameters are correctly passed. Or is there any better way to do a unit test here. Basically I am stuck with how to effectively unit test methods who are having Action delegate parameters. I referred the thread Testing a method accepting a delegate with Moq, but could not find anything I can assert or verify inside the callback.
If you would like to test what is happening in your action delegate you can use the callback from moq. Something like Action<IMappingOperationOptions<MyEntity, MyDto>> mappingOperationAction = default; _mapper.setup(x.Map(myDto, It.IsAny<Action<IMappingOperationOptions<MyEntity,MyDto>>>()) .callBack<MyDto, Action<IMappingOperationOptions<MyEntity,MyDto>>>( (callbackMyDto, callbackMappingOperationAction) => mappingOperationAction = callbackMappingOperationAction); var mappingOperation = new MappingOperationOptions<MyEntity, MyDto>(_ => default); mappingOperationAction.Invoke(mappingOperation); Assert.AreEqual("N", mappingOperation.Items["isUpdate"])
can not read get property of undefined angular 2 error
hi I am trying to get city name from google api but getting that error below is my code appcomponent class import {Component, OnInit} from 'angular2/core'; import {marketComponent} from './market.component'; import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; import {introComponent} from './intro.component'; import {geoService} from './service.geo'; import {JSONP_PROVIDERS} from 'angular2/http'; declare var google: any; #Component({ selector: 'my-app', templateUrl: 'app/app.component.html', directives: [ROUTER_DIRECTIVES], providers: [JSONP_PROVIDERS, geoService] }) #RouteConfig([ { path: '/intro', name: 'Intro', component: introComponent, useAsDefault: true }, { path: '/market', name: 'Market', component: marketComponent }, ]) export class AppComponent { constructor(private _http: geoService) { } public maps; public cat_error: Boolean = false; public xml_Latitude :string; public xml_Lang: string; ngOnInit() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(this.showPosition); } else { alert("Geolocation is not supported by this browser."); } var input: any = document.getElementById('google_places_ac'); var autocomplete = new google.maps.places.Autocomplete(input, {}); google.maps.event.addListener(autocomplete, 'place_changed', function () { var place = autocomplete.getPlace(); console.log(place) }); } showPosition(position) { this.xml_Latitude = position.coords.latitude; this.xml_Lang = position.coords.longitude; this._http.getPlaces(this.xml_Latitude, this.xml_Lang).subscribe( data => { this.maps = data }, err => { this.cat_error = true } ); var result = this.maps.results; var city = result[0].address_components[4].long_name + "," + result[0].address_components[6].long_name; alert(city); } } and geoservice file import {Injectable} from 'angular2/core'; import { Response, Jsonp} from 'angular2/http'; import 'rxjs/add/operator/map'; #Injectable() export class geoService { constructor(private http: Jsonp) { } public xml_Latitude: string; public xml_Lang: string; public getPlaces(xml_Latitude, xml_Lang) { return this.http.get(`http://maps.googleapis.com/maps/api/geocode/json?latlng= '${this.xml_Latitude}','${this.xml_Lang}'&sensor=true`) .map((res: Response) => res.json()) .catch(this.handleError); } private handleError(error: Response) { console.error(error); return error.json().error || 'Server error'; } } error also says getplaces is not a function, I think I am missing something but don't know what....
In addition to the callback ordering problem identified by Thierry, you have a lost this context on this line: navigator.geolocation.getCurrentPosition(this.showPosition); The Problem You have the classic JavaScript problem known as the incorrect this context. The this keyword in JavaScript behaves differently than in does in other languages like C# and Java. How this works The this keyword, in a function, is determined as follows: * If the function was created through a call to .bind, the this value is the argument provided to bind * If the function was invoked through a method call, e.g. expr.func(args), then this is expr * Otherwise * If the code is in strict mode, this is undefined * Otherwise, this is window (in a browser) Let's look at how this works in practice: class Foo { value = 10; doSomething() { // Prints 'undefined', not '10' console.log(this.value); } } let f = new Foo(); window.setTimeout(f.doSomething, 100); This code will print undefined (or, in strict mode, throw an exception). This is because we ended up in the last branch of the decision tree above. The doSomething function was invoked, the function wasn't a result of a bind call, and it wasn't invoked in a method syntax position. We can't see the code for setTimeout to see what its invocation looks like, but we don't need to. Something to realize is that all doSomething methods point to the same function object. In other words: let f1 = new Foo(); let f2 = new Foo(); // 'true' console.log(f1.doSomething === f2.doSomething); We know that setTimeout can only see the function we passed it, so when it invokes that function, there's no way for it to know which this to provide. The this context has been lost due to our referencing the method without invoking it. The Red Flag Once you know about this problems, they're easy to spot: class Foo { value = 10; method1() { doSomething(this.method2); // DANGER, method reference without invocation } method2() { console.log(this.value); } } The Solution You have a few options here, each with its own trade-offs. The best option depends on how often the method in question is invoked from differing call sites. Arrow Function in Class Definition Instead of using the normal method syntax, use an arrow function to initialize a per-instance member. class DemonstrateScopingProblems { private status = "blah"; public run = () => { // OK console.log(this.status); } } let d = new DemonstrateScopingProblems(); window.setTimeout(d.run); // OK Good/bad: This creates an additional closure per method per instance of your class. If this method is usually only used in regular method calls, this is overkill. However, if it's used a lot in callback positions, it's more efficient for the class instance to capture the this context instead of each call site creating a new closure upon invoke. Good: Impossible for external callers to forget to handle this context Good: Typesafe in TypeScript Good: No extra work if the function has parameters Bad: Derived classes can't call base class methods written this way using super. Bad: The exact semantics of which methods are "pre-bound" and which aren't create an additional non-typesafe contract between your class and its consumers. Function Expression at Reference Site Shown here with some dummy parameters for explanatory reasons: class DemonstrateScopingProblems { private status = "blah"; public something() { console.log(this.status); } public run(x: any, y: any) { // OK console.log(this.status + ': ' + x + ',' + y); } } let d = new DemonstrateScopingProblems(); // With parameters someCallback((n, m) => d.run(n, m)); // Without parameters window.setTimeout(() => d.something(), 100); Good/bad: Opposite memory/performance trade-off compared to the first method Good: In TypeScript, this has 100% type safety Good: Works in ECMAScript 3 Good: You only have to type the instance name once Bad: You'll have to type the parameters twice Bad: Doesn't easily work with variadic parameters
I think that you should move the result block into the subscribe callback associated the getPlaces method call: showPosition(position) { this.xml_Latitude = position.coords.latitude; this.xml_Lang = position.coords.longitude; this._http.getPlaces(this.xml_Latitude, this.xml_Lang).subscribe( data => { this.maps = data; var result = this.maps.results; // <---------- var city = result[0].address_components[4].long_name + "," + result[0].address_components[6].long_name; alert(city); }, err => { this.cat_error = true } ); } It's because this.maps is undefined before the callback is called. And you try tyo get the result attribute before (this.maps.results). Edit I also see a problem at the line navigator.geolocation.getCurrentPosition. You could refactor your code this way: if (navigator.geolocation) { navigator.geolocation.getCurrentPosition((position) => { // <---- this.showPosition(position); }); } else { alert("Geolocation is not supported by this browser."); }
Creating new upshot js entities
I'm building a site as a Single Page Application using ASP.NET MVC 4 Beta . The sample app talks about adding new entities and it uses a constructor function for it's product entity. However I have many entity types and I'm not going to write a constructor function for each one. This is how I am creating a new entity (name is the name of the datasource and dataTarget.upshot.upshotData is the list of entities I get back from the GetEntities method in coffeeScript... newItem = {} for field, def of upshot.metadata(upshot.dataSources[name]._entityType).fields do (field, def) -> if def.array newItem[field] = new ko.observableArray() else newItem[field] = new ko.observable() upshot.addEntityProperties newItem, upshot.dataSources[name]._entityType dataTarget.upshot.upshotData.push newItem my question is if this is the best way to do it or am I missing something? I'm surprised that upshot does not seem to have a createEntity method. in javascript... newItem = {}; _ref = upshot.metadata(upshot.dataSources[name]._entityType).fields; _fn = function(field, def) { if (def.array) { return newItem[field] = new ko.observableArray(); } else { return newItem[field] = new ko.observable(); } }; for (field in _ref) { def = _ref[field]; _fn(field, def); } upshot.addEntityProperties(newItem, upshot.dataSources[name]._entityType); dataTarget.upshot.upshotData.push(newItem);
var newThing = {}; var typeName = "MyType:#MyNamespace"; upshot.map({ SomeProperty: "my value" }, typeName, newThing); upshot.addEntityProperties(newThing, typeName); This will create your object with the entity properties mapped to observables, and will allow you to set properties (see SomeProperty:"my value").
How can I modify the result of a method call on a mocked object before it is returned?
Given the following streamlined example, using RhinoMocks and MSpec: [Subject(typeof (LocationController))] public class when_creating_a_location_with_invalid_model : context_for_location_controller { static LocationModel model = new LocationModel(); static SelectList states = new SelectList(new Dictionary<string,string> { { "IN", "Indiana" }, { "NY", "New York" } }); static ActionResult result; Establish context = () => { LocationModelBuilder.Stub(x => x.Build(Arg<LocationModel>.Is.Equal(model))).Return(model); } Because of = () => result = subject.Create(model); It should_automatically_select_a_state = () => result.Model<LocationModel>() .States.ShouldNotBeEmpty(); } How can I modify the object contained in the model variable before it is returned from the stubbed call of LocationModelBuilder.Build()? I want to perform an assignment like model.States = states just before return on Build(). I tried playing with the Do() handler but I give up...
Try using WhenCalled(). The parameter to WhenCalled allows access to the mocked method's arguments and you can also set the return value. .WhenCalled(m => { Model model = (Model) m.Arguments[0]; model.States = ...; });
Trouble defining method for Javascript class definition
I'm somewhat new to object oriented programming in Javascript and I'm trying to build a handler object and library for a list of items I get back from an API call. Ideally, I'd like the library functions to be members of the handler class. I'm having trouble getting my class method to work however. I defined as part of the class bcObject the method getModifiedDateTime, but when I try to echo the result of the objects call to this method, I get this error: Error on line 44 position 26: Expected ';' this.getModifiedDateTime: function(epochtime) { which leads me to believe that I simply have a syntax issue with my method definition but I can't figure out where. response( { "items": [ {"id":711,"name":"Shuttle","lastModifiedDate":"1268426336727"}, {"id":754,"name":"Formula1","lastModifiedDate":"1270121717721"} ], "extraListItemsAttr1":"blah", "extraListItemsAttr2":"blah2" }); function response(MyObject) { bcObject = new bcObject(MyObject); thing = bcObject.getModifiedDateTime(bcObject.videoItem[0].lastModifiedDate); SOSE.Echo(thing); } function bcObject(listObject) { // define class members this.responseList = {}; this.videoCount = 0; this.videoItem = []; this.responseListError = ""; // instantiate members this.responseList = listObject; this.videoCount = listObject.items.length; // populate videoItem array for (i=0;i<this.videoCount;i++) { this.videoItem[i] = listObject.items[i]; } this.getModifiedDateTime: function(epochtime) { var dateStringOutput = ""; var myDate = new Date(epochtime); dateStringOutput = myDate.toLocaleString(); return dateStringOutput; }; }
You use = to assign values in JS, not :: this.getModifiedDateTime = function(epochtime) {
You should use the = operator for methods defined as you did there (this.<methodName> = function (...) {). The colon notation is used when declaring object literals.