Here is some broilerplate code I've come up with as a code-template for object factory in AngularjS. I've used a Car/CarFactory as an example to illustrate. Makes for simple implementation code in the controller.
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function() {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null,
hasFancyRadio: false
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple',
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
Here is a simpler example. I'm using a few third party libraries that expect a "Position" object exposing latitude and longitude, but via different object properties. I didn't want to hack the vendor code, so I adjusted the "Position" objects I was passing around.
angular.module('app')
.factory('PositionFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Position = function() {
// initialize instance properties
// (multiple properties to satisfy multiple external interface contracts)
angular.extend(this, {
lat : null,
lon : null,
latitude : null,
longitude : null,
coords: {
latitude: null,
longitude: null
}
});
this.setLatitude = function(latitude) {
this.latitude = latitude;
this.lat = latitude;
this.coords.latitude = latitude;
return this;
};
this.setLongitude = function(longitude) {
this.longitude = longitude;
this.lon = longitude;
this.coords.longitude = longitude;
return this;
};
}; // end class definition
// instance factory method / constructor
this.Position.prototype.instance = function(params) {
return new
this.constructor()
.setLatitude(params.latitude)
.setLongitude(params.longitude)
;
};
return new this.Position();
}) // end Factory Definition
.controller('testCtrl', function($scope, PositionFactory) {
$scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
$scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller
;