Where do you declare objects in AngularJS? - javascript

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.

Related

dojo: instantiate an object within its own class

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();
});

Angularjs retain local variable

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>

Angular Profile service with property getter / setters?

Is it possible to have a singleton Angular service with getters and setters with logic? I was given the following snippet and asked to mimic it in an Angular service. It may sound simple but I'm losing my mind:
public class Profile
{
private AuthSvc _auth = new AuthSvc();
private string _userId = null;
private string _displayName = null;
public string UserId
{
get
{
if (_userId != null) { return _userId; }
_userId = AuthSvc.getUserId();
return _userId;
}
}
public string DisplayName
{
get
{
if (_displayName != null) { return _displayName; }
if (_userId == null) { return null; }
_displayName = AuthSvc.getDisplayName(_userId);
return _displayName;
}
set (string value) {
if (value == null && value.trim().length < 1) { return; }
if (_displayName != null && _displayName == value.trim()) { return; }
_displayName = value.trim();
AuthSvc.setDisplayName(_userId, _displayName);
}
}
}
My failed attempt before I started crying:
(function () {
'use strict';
angular
.module('myapp')
.service('Profile', ProfileService);
ProfileService.$inject = ['common', 'dataService'];
function ProfileService (common, dataService) {
var userInfo = {
id : '',
name : ''
};
var service = {
id : $get getUserId(),
name : $get getUserId(), $set(value, setUserId);
};
return service;
/////////////////////////
function getUserId () {
if (!userInfo.id) { userInfo.id = common.getUserId(); }
return userInfo.id;
}
function setName (value) {
}
function getName () {
if (userInfo.name) { return userInfo.name; }
var userId = getUserId();
if (!userId) { return ''; }
dataService.users.getDisplayName(userId).then(function(name){
});
}
}
})();
You have written the service as a factory.
An angular service is a constructor that uses this for all properties and a factory is a function that returns an object
You should be fine switching the component from service to factory
angular
.module('myapp')
.factory('Profile', ProfileService);
But you should also be passing function and object variable references to the returned object also
Along the lines of:
var service = {
userInfo : userInfo ,
getUserId : getUserId,
getName : getName
};
// or
service.myfunc = someNamedFunction;
Alternatively keeping it as as service switch all variables to be members of this
Actually service is just a plain object and you can use Object.defineProperty on it. I use factory syntax.
(function () {
'use strict';
angular.module('mymodule', [])
.factory('myService', function () {
var service = {};
var userInfo = {
id : '',
name : ''
};
serivce.getUserInfo = function(){ return userInfo;};
var myPropertyPrivateVal;
Object.defineProperty(service, 'myProperty', {
get: function () { return myPropertyPrivateVal; },
set: function(value) { myPropertyPrivateVal = value; }
});
return service;
});
})();
And you are good to go :)
All the dirrefece when you use service syntax is that you use this instead of an object literal var service = {};
(function () {
'use strict';
angular.module('mymodule', [])
.service('myService', function () {
var userInfo = {id : '', name : '' };
this.getUserInfo = function(){ return userInfo;};
var myPropertyPrivateVal;
Object.defineProperty(this, 'myProperty', {
get: function () { return myPropertyPrivateVal; },
set: function(value) { myPropertyPrivateVal = value; }
});
});
})();

is it Possible (partial class) concept for controller in angularjs?

Is there any way to do code grouping using partials in angularjs?
Reason --- I have a controller which contains too much code. This controller contains the code For several Methods and a lot of functionalities, it reduces the readability of the code. I want to keep controller name the same and do code grouping.
Ex:-
app.controller('MainController', function ($scope, router) {
$scope.Read = function() {
};
$scope.Write = function() {
};
$scope.Update = function() {
};
$scope.Delete = function() {
};
});
Partial:
app.controller('MainController', function ($scope, router) {
$scope.firstName = firstname;
$scope.middleName = middleName;
$scope.lastName = lastName;
});
Another Partial:
app.controller('MainController', function ($scope, router) {
$scope.Print = function() {
};
$scope.PrintPreviw = function() {
};
});
I need to implement it like this.
Is there any other way? yes please update..
Thanks
You could try to sort the code into logical chunks. after that, you could merge logical chunks into objects.
//Do NOT do this!
$scope.firstName = firstname;
$scope.middleName = middleName;
$scope.lastName = lastName;
//instead do this
var person = {
firstname: "name",
middleName: "mName",
lastName: "Lname"
}
//then in your view access them like this
{ { person.firstname } }
Also, you could move some code into services or factories. then use those methods inside of your controller.
//take things out of your controller and put then in a service or factory.
app.service('notePad', function () {
return {
Read: function (newState) {
return state += state;
},
Write: function (state) {
return state += state;
},
Update: function (state) {
state = state;
},
Delete: function () {
state = null;
}
};
});
//then in your controller access them like this
//Note you do not need everything on $scope if you are not going to use it in the view.
app.controller('MainController', function ($scope, router, notePad) {
$scope.Read = notePad.Read();
$scope.Write = notePad.Write();
$scope.Update = notePad.Update();
$scope.Delete = notePad.Delete();
});
If you need the functionality of a controller inside of a service you can still access scope and other controller properties like this.
NOTE: Make sure you create an onDestroy method to clean up any leftover variables.
//pass your scope to your service
app.controller('MainController', function ($scope, router, notePad) {
notePad.changeView($scope);
});
//munipulate your scope just like you would in a controller
app.service('notePad', function () {
function changeView(scope) {
scope.write = 'example';
}
});
//the result of the scope change in the service will show up in the view
{ { write } } == 'example'

Should my factory return an object with helper methods or should I use prototype?

I'm a beginner with angular and I try to understand if I should user a factory like that:
app.factory('FoobarServices', ['$http', function ($http) {
var Foobar = {
// Model
};
return {
getFoobar: function () {
},
setFoobar: function (Foobar) {
},
update: function (foobar) {
},
delete: function (id)
}
};
}]);
Or something like:
app.factory('Fooba', ['$http', function($http) {
function Foobar(foobar) {
// Initialize foobar
};
Foobar.prototype = {
getFoobars: function() {
},
setFoobar: function(foobar) {
},
update: function(foobar) {
},
delete: function(id) {
},
};
return Foobar;
}]);
I'm not sure to understand what's the pros and cons of each pattern, and which one is more suitable for an angular project.
Could you please tell me which one should I use?
It depends on how you want to use your service.
Factory is usually being used to store some constructor from which you can later instantiate some objects.
For example:
app.factory('Client', function () {
function Client (name) {
this.name = name;
}
Client.prototype.sayHello = function () {
console.log('Hello, my name is ' + this.name + '!');
}
return Client;
})
.controller('ClientController', function (Client) {
var bob = new Client('Bob');
})
If your service is singleton, you can register it as service instead of factory and angular will create an instance for you.
Or you can register it as factory but return some object with methods. It is useful when you don't want to deal with context (this) inside your service logic:
app.factory('ClientStorage', function () {
function set () {
// to be implemented
}
function get () {
// to be implemented
}
return {
get: get,
set: set
};
})

Categories