Suppose I have a class (let's say, LinkedListNode.js) defined below:
// LinkedListNode.js
define([
"dojo/_base/declare"
] , function (declare) {
return declare(null, {
constructor: function(data) {
this._data = data;
},
addNext: function(data) {
}
});
});
How can I instantiate an instance of this class within its own definition, like below:
// LinkedListNode.js
define([
"dojo/_base/declare"
] , function (declare) {
return declare(null, {
constructor: function(data) {
this._data = data;
},
addNext: function(data) {
this._next = new LinkedListNode(data);
}
});
});
Here is an example of what I am trying to do in Java:
class LinkedListNode {
private int data;
private LinkedListNode next;
public LinkedListNode(int data) {
this.data = data;
}
public void addNext(int data) {
// How can I execute this same statement in JavaScript/Dojo?
this.next = new LinkedListNode(data);
}
}
You don't do it like that in Dojo. You just put your new class in the define section of the place you want to use it and Dojo makes the instatiation for you. So if you saved on Object.js, you would use it like this:
define([
"dojo/_base/declare",
"yourpath/Object"
] , function (declare, object) {
return declare(null, {
constructor: function() {
},
test: function() {
object.whatever();
}
});
});
Complemented based on edits
Well to use the way you want, you can't do it with dojo's declare system. You have to do it in the more traditional way. Js is a free free language, you can do things in many ways. So you have several methods to do something like that in JS. Here are 3:
function LinkedListNode(data) {
this.addNext = function(data) {
this.next = new LinkedListNode(data);
return this.next;
}
this.data = data;
}
var ll1 = new LinkedListNode(777);
ll1.addNext(555).addNext(333);
console.log(ll1.next.data);
console.log(ll1.next.next.data);
function LinkedListNodeV2(data) {
var self = {}
self.addNext = function(data) {
self.next = new LinkedListNodeV2(data);
return self.next;
}
self.data = data;
return self
}
var ll2 = LinkedListNodeV2(777);
ll2.addNext(555).addNext(333);
console.log(ll2.next.data);
console.log(ll2.next.next.data);
class LinkedListNodeV3 {
constructor(data) {
this.data = data;
}
addNext(data) {
this.next = new LinkedListNodeV3(data);
return this.next;
}
}
var ll3 = new LinkedListNodeV3(777);
ll3.addNext(555).addNext(333);
console.log(ll3.next.data);
console.log(ll3.next.next.data);
JSFiddle: https://jsfiddle.net/s1pemgbk/2/
But how do you put that in Dojo ? as allways in JS there are many ways, one of them is this:
// LinkedListHelper.js
define([
"dojo/_base/declare"
] , function (declare) {
class LinkedListNode {
constructor(data) {
this.data = data;
}
addNext(data) {
this.next = new LinkedListNode(data);
return this.next;
}
};
var self = {};
self.getLLInstance = function(data) {
return new LinkedListNode(data);
}
return self;
});
then you would use it like this:
define([
"dojo/_base/declare",
'project/helpers/linkedListHelper',
], function (
declare,
linkedListHelper
) {
return declare([_WidgetBase, _TemplatedMixin], {
postCreate: function () {
this.inherited(arguments);
var ll = linkedListHelper.getLLInstance(777);
ll.addNext(555).addNext(333);
console.log(ll.next.data);
console.log(ll.next.next.data);
}
});
});
Hope it's clearer now :)
As you can see in this example, two dojo classes are created using dojo module declare. Dojo abstracts classes similarly to Java.
When a class is defined using define you can initiate it in your code at will.
In this example YourMainClass's constructor contains a reference to an instance of YourClass were it was initiated.
Live demo here:
https://jsfiddle.net/gibbok/uw17etqg/
require(["dojo/_base/declare", "dojo/_base/lang"], function(declare, lang) {
var YourClass = declare(null, {
constructor: function(name, age, residence) {
this.name = name;
this.age = age;
this.residence = residence;
},
print: function() {
alert(this.name);
}
});
var YourMainClass = declare(null, {
constructor: function(name, age, residence) {
this.yourClassInstance = new YourClass('foo', 'bar', 'zoo');
this.yourClassInstance.print();
}
});
var yourMainClass = new YourMainClass();
});
Related
I have a factory like this:
TestFactory= function () {
var objectName=null;
return {
SetName:function(name) {
objectName = name;
},
GetName:function() {
return objectName;
},
Init:function() {
return angular.copy(this);
}
}
}
A controller like:
TestController = function($scope) {
$scope.TestClick = function () {
var tstA = TestFactory.Init();
var tstB = TestFactory.Init();
tstA.SetName('test A')
tstB.SetName('test B')
console.log('A', tstA.GetName());
console.log('B', tstB.GetName());
}
}
In the console I get Test B for both objects.
How can I make a proper instance of this object?
I would like to use the objectName value in other functions of the factory.
Take into account that in Angular, Factories are singletons, so the instance is always the same.
You can do the following:
TestFactory= function () {
var objectName={};
return {
SetName:function(property,name) {
objectName[property] = name;
},
GetName:function(property) {
return objectName[property];
},
Clear:function(property) {
delete objectName[property]
}
}
}
Then in your controller:
TestController = function($scope, TestFactory) {
$scope.TestClick = function () {
TestFactory.SetName('a','test A')
TestFactory.SetName('b','test B')
console.log('A', TestFactory.GetName('a')); // test A
console.log('B', TestFactory.GetName('b')); // test B
}
}
Couple of issues. First your returning an object rather than a function from your factory.
app.factory('TestFactory', function() {
return function() {
var objectName = null;
var setName = function(name) {
objectName = name;
};
var getName = function() {
return objectName;
};
return {
SetName: setName,
GetName: getName
};
};
});
Then you can just instantiate like this:
var tstA = new TestFactory();
var tstB = new TestFactory();
Services and factories are singletons so I think you can achieve what you want with a more appropriate use of the factory by providing an Init function that returns the common code and unique name like so:
angular.module('app')
.factory('ServiceFactory', serviceFactory);
function serviceFactory() {
return {
Init: function (name) {
return {
objectName: name,
setName: function (name) {
this.objectName = name;
},
getName: function () {
return this.objectName;
}
};
}
};
}
This leaves the possibility to use it as a factory that can initialize many types.
You basically need to create a simple getter/setter.
angular.module('app', [])
.controller('TestController', testController)
.service('serviceFactory', serviceFactory);
testController.$inject = ['serviceFactory'];
function testController(serviceFactory) {
serviceFactory.set('A', {
name: 'test A'
});
serviceFactory.set('B', {
name: 'test B'
});
console.log(serviceFactory.getAll());
console.log(serviceFactory.get('A'));
console.log(serviceFactory.get('B'));
}
function serviceFactory() {
var
_model = {
name: ""
},
_data = {};
return {
set: function(key, data) {
_data[key] = angular.extend({}, _model, data);
},
get: function(key) {
return _data[key];
},
getAll: function() {
return _data;
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<body ng-app="app" ng-controller="testController"></body>
Im trying to seal an object property .
My question is ,here i have given Object.seal(personObject),this particular object is sealed and does not allow to configure or make any extensions in this object,but as i did not mention on personObject_2 it does allow to extend or configure
How can i make it on prototype .I mean like any class of type person should have/respect this seal.Can we achieve such behaviour
"use strict";
var personModule=(function (module) {
var person=function (fname,lname) {
Object.defineProperty(this,'firstName',{
get:function () {
return fname;
}
,set:function (newValue) {
fname=newValue;
},
configurable:true
});
Object.defineProperty(this,'lastName',{
get:function () {
return lname;
}
,set:function (newValue) {
lname=newValue;
},
configurable:true
});
Object.defineProperty(this,'fullName',{
get:function () {
return fname+lname;
},
configurable:true
});
}
module.person=person;
return module;
})(personModule || {});
var personObject=new personModule.person( "Raju","Rani");
console.log(personObject.fullName);
Object.seal(personObject);
//delete personObject.firstName;-->It throws error here
var personObject2=new personModule.person( "Shiva","Kumar");
delete personObject2.firstName;
console.log(personObject2.firstName);
Thanks
Here is Proxy version in case you do not prefer adding Object.seal on constructor
"use strict";
var personModule=(function (module) {
var person=function (fname,lname) {
Object.defineProperty(this,'firstName',{
get:function () {
return fname;
}
,set:function (newValue) {
fname=newValue;
},
configurable:true
});
Object.defineProperty(this,'lastName',{
get:function () {
return lname;
}
,set:function (newValue) {
lname=newValue;
},
configurable:true
});
Object.defineProperty(this,'fullName',{
get:function () {
return fname+lname;
},
configurable:true
});
}
module.person=new Proxy(person, {
construct(target, args){
args.unshift(null);
let ctor = target.bind.apply(target, args);
let result = new ctor();
Object.seal(result);
return result;
}
});
return module;
})(personModule || {});
var personObject=new personModule.person( "Raju","Rani");
console.log(personObject.fullName);
Object.seal(personObject);
//delete personObject.firstName;-->It throws error here
var personObject2=new personModule.person( "Shiva","Kumar");
delete personObject2.firstName;
console.log(personObject2.firstName);
Did you tried - immutable-js
var personObject = new personModule.person("Raju", "Rani");
var sealed = Immutable.Map(personObject);
Here is the my question
var panel = {
_pnlHeaderContainer: $('.panelHeader'),
_pnlHeaderString:"",
//private method
_Write: function (pnlHeaderString) { return this._pnlHeaderContainer.html(pnlHeaderString); },
Clear: function () { return this._pnlBaslikContainer.html(""); },
// _fake:this,
Header: {
AddEvent:"Add Event",
Calendar: "Calendar",
}
};
what I wanna achieve is using the _Write method in Header object
something like this
Header: {
AddEvent:this._Write("Add Event"),
Calendar: "Calendar",
}
trying to run this code like this panel.Header.AddEvent; but it says me Write is not a function
I like to provide a context when creating a class
function Panel(){
var context = this;
this._pnlHeaderContainer = $('.panelHeader');
this._pnlHeaderString = "";
this._Write = function(pnlHeaderString){
return context._pnlHeaderContainer.html(pnlHeaderString);
};
this.Clear = function(){
return context._pnlBaslikContainer.html("");
};
this.Header = {
AddEvent: function(){ return context._Write("Add Event"); },
Calendar: "Calendar",
};
}
var panelObject = new Panel();
// Do whatever you want...
panelObject.Header.AddEvent();
I have the following angularJS service
define(["angular"], function(Angular) {
var dataStorageService = function() {
var serviceConstructor = function() {
var _getColor = function(color) {
return this.config.categoryColorMapping.colors[color];
}
}
var serviceInstance = new serviceConstructor();
angular.extend(serviceInstance.prototype, {
config: {
numberOfMessagesDisplayed: 5,
maxTitleLength: 48,
maxPreambleLength: 140,
categoryColorMapping: {
colors : {
nyheter: '#2B2B2B',
sport: '#F59331',
underholding: '#F9B00D'
},
categories: {
nyheter: _getColor('nyheter'),
sport: _getColor('sport'),
underholding: _getColor('underholding')
}
}
},
get: function(param) {
if(this.config.hasOwnProperty(param)) {
return this.config[param];
} else {
console.warn('Playlist::configService:no "' + param + '" config found');
return false;
}
},
set: function(param, value) {
this.config[param] = value;
}
});
return serviceInstance;
};
return dataStorageService;
});
now my goal is to make public the following methods:
get
set
and I want '_getColor' method private but I want to use it within the JSON object config. When I run the code I have
"ReferenceError: _getColor is not defined"
is it possibie to achievie it this way? (to have _getColor private and use it within the JSON object within angular.extend?)
Functions can be shared and still be private, instance specific private members have to be defined in the constructor though. Since your private function doesn't need to access instance specific private members you can do the following:
define(["angular"], function(Angular) {
var dataStorageService = function() {
var serviceConstructor = function() {
}
var serviceInstance = new serviceConstructor();
//IIFE returning object that will have private members as closure
// privileged methods have to be in the same function body as the
// private fucnction
serviceInstance.prototype = (function() {
var _getColor = function(instance, color) {
return instance.config.categoryColorMapping.colors[color];
};
return {
constructor: serviceConstructor
,config: {
numberOfMessagesDisplayed: 5,
maxTitleLength: 48,
maxPreambleLength: 140,
categoryColorMapping: {
colors : {
nyheter: '#2B2B2B',
sport: '#F59331',
underholding: '#F9B00D'
},
categories: {
//since categories is a sub object of serviceinstance.categorycolormapper
// it is not possible to get the instance of serviceinstance
// at this time unless you set it in the constructor
// solution could be that each serviceinstance has it's own categorycolormaper
// and when categorycolormapper is created pass the serviceinstance instance
nyheter: _getColor(this,'nyheter'),
sport: _getColor(this, 'sport'),
underholding: _getColor(this, 'underholding')
}
}
},
get: function(param) {
if(this.config.hasOwnProperty(param)) {
return this.config[param];
} else {
console.warn('Playlist::configService:no "' + param + '" config found');
return false;
}
},
set: function(param, value) {
this.config[param] = value;
}
}
}());
return serviceInstance;
};
return dataStorageService;
});
More info on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941
Functions added to the prototype are defined outside the lexical scope of the constructor, and therefore have no access to "private" methods.
The former are shared between all instances, and the latter are per-instance. The only way to get around this is to explicitly export the (per-instance) function as a property of the instance, making it non-private.
Within the definition of serviceConstructor add following line, after definition of _getColor
serviceConstructor.prototype._getColor = _getColor ;
I have an object representing a person:
function Person(_name) {
this.name = _name;
this.start = function() {
var that = this
$timeout( function sayHello() {
console.log(that.name);
$timeout(sayHello, 1000);
}, 1000);
}
}
Notice that is uses the angular $timeout service. Where should I put this so that I can declare people in my controller:
function Ctrl($scope) {
// How do I access Person so I can do this?
$scope.p1 = Person('nick');
$scope.p2 = Person('amy');
$scope.p1.start();
$scope.p2.start();
}
I can put the declaration in the controller body, and it works but that doesn't seen like good design. I'm pretty sure a value, or provider is specifically for this. But not sure how it would work given the dependency on $timeout.
You can create objects in a factory
var Person = (function (params) {
angular.extend(this, params);
return {
name: params.name,
};
});
Person.create = function create(params) {
return new Person(params);
};
myApp.factory('Person', function ($timeout) {
return Person;
});
Then in your controller you can inject the factory and create Person objects.
myApp.controller('HomeCtrl', function($scope, Person) {
$scope.person = Person.create({ name: 'Andy' });
});
I would make it a Service that returns a constructor.
var myModule = angular.module('myModule', []);
myModule.service('Person', function($timeout) {
// Actual person constructor defined once when
// the service is first instantiated
function Person(name) {
this.name = name;
this.start = function() {
var that = this
$timeout( function sayHello() {
console.log(that.name);
$timeout(sayHello, 1000);
}, 1000);
}
}
this.create = function (name) {
// Return a new instance
return new Person(name);
};
});
Note that you would use Person.create() to make instances in this case.