Benefits/drawbacks of additional abstraction layer within Angular's $scope - javascript

I have slightly modified the example from the following URL (http://docs.angularjs.org/cookbook/helloworld) as follows, placing the name value within an attrs object property:
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
<script>
function HelloCntl($scope) {
$scope.attrs = {
name : 'World'
}
}
</script>
</head>
<body>
<div ng-controller="HelloCntl">
Your name: <input type="text" ng-model="attrs.name"/>
<hr/>
Hello {{attrs.name || "World"}}!
</div>
</body>
</html>
One benefit I can see is that the HTML source code can be searched for /attrs\.\w+/ (e.g.) if there is ever a need to easily find all such attributes within the view rather than the controller (e.g. a search for name could collide with form element names). Also within the controller I can only imagine that partitioning attributes necessary for the front end might lend itself to better organization.
Is anybody else using such a level of abstraction. Are there any possible specific further benefits to it's usage? And most importantly, might there be any specific drawbacks to it.

It's recommended that you always use a dot in your ngModels in order to avoid potential issues with prototypal inheritance that are discussed in Angular's Guide to Understanding Scopes:
This issue with primitives can be easily avoided by following the
"best practice" of always have a '.' in your ng-models – watch 3
minutes worth. Misko demonstrates the primitive binding issue with
ng-switch.
Prototypal inheritance and primitives
In javascripts' approach to inheritance reading and writing to a primitive act differently. When reading, if the primitive doesn't exist on the current scope it tries to find it on any parent scope. However, if you write to a primitive that doesn't exist on the current scope it immediately creates one on that scope.
You can see the problem this can cause in this fiddle that has 3 scopes- one parent and two children that are siblings. First type something in the "parent" and you'll see that both children are updated. Then type something different in one of the children. Now. only that child is updated, because the write caused the child to creates it's own copy of the variable. If you now update the parent again, only the other child will track it. And if you type something into the sibling child all three scopes will now have their own copies.
This can obviously cause lots of issues.
Prototypal inheritance and objects
Try the same experiment with this fiddle in which each ngModel uses a property of an object instead of a primitive. Now both reading and writing act consistently.
When you write to a property of an object it acts just like reading does (and the opposite of how writing to a primitive does). If the object you're writing to does not exist on the current scope it looks up it's parent chain trying to find that object. If it finds one with that name then it writes to the property on that found object.
So, while in the primitive example we started with 1 variable and then after writing to the children ended up with 3 copies of the variable- when we use an object we only ever have the one property on the one object.
Since we almost always, perhaps just always, want this consistent behavior the recommendation is to only use objects properties, not primitives in an ngModel or, said more commonly, "always use a dot in your ngModel"

I do this as well. I also put all action functions (button clicks etc) into a $scope.actions object. And since i use socket.io i put those callbacks into a $scope.events object it usually keeps my controllers nice and organized and easily able to find the function i need to if i need to do any editing.
app.controller('Ctrl',['$scope', function ($scope) {
$scope.data = {
//contains data like arrays,strings,numbers etc
};
$scope.actions = {
//contains callback functions for actions like button clicks, select boxes changed etc
};
$scope.events = {
//contains callback functions for socket.io events
}
]);
Then in like my templates I can do like
<input ng-click="actions.doSomething()">
I also do a partial of this for services. I use a private and public data object
app.factory('$sysMsgService',['$rootScope',function($rootScope){
//data that the outside scope does not need to see.
var privateData = {};
var service = {
data:{
//contains the public data the service needs to keep track of
},
//service functions defined after this
};
return service;
}]);

Related

AngularJS - Which scope is better performance wise? Object.key or Some Variable?

Let's say I have to store customer information, and to manage two-way binding I'll use $scope here.
So my doubt here is, which approach is better?
$scope.firstname = "foo";
$scope.lastname = "bar";
$scope.cellno = "1234567890";
$scope.email = "foobar#example.com";
OR
$scope.customerDetailsObj = {};
$scope.customerDetailsObj.firstname = "foo";
$scope.customerDetailsObj.lastname = "bar";
$scope.customerDetailsObj.cellno = "1234567890";
$scope.customerDetailsObj.email = "foobar#example.com";`
I've been wondering about this because I have a large angular application and sometimes the scope watchers count goes beyond 1500. I'm using a chrome extension to see watchers count.
Please share your views. Thank You.
In my opinion and as-per angularjs guide first approach (binding to properties directly) will be more efficient. Excerpt from the guide:
Dirty checking can be done with three strategies: By reference, by
collection contents, and by value. The strategies differ in the kinds
of changes they detect, and in their performance characteristics.
Watching by reference (scope.$watch (watchExpression, listener)) detects a change when the whole value returned by the watch expression
switches to a new value. If the value is an array or an object,
changes inside it are not detected. This is the most efficient
strategy.
Watching collection contents (scope.$watchCollection (watchExpression, listener)) detects changes that occur inside an
array or an object: When items are added, removed, or reordered. The
detection is shallow - it does not reach into nested collections.
Watching collection contents is more expensive than watching by
reference, because copies of the collection contents need to be
maintained. However, the strategy attempts to minimize the amount of
copying required.
Watching by value (scope.$watch (watchExpression, listener, true)) detects any change in an arbitrarily nested data structure. It is the
most powerful change detection strategy, but also the most expensive.
A full traversal of the nested data structure is needed on each
digest, and a full copy of it needs to be held in memory.
Talking only about performance, I think option 1 (having plain variables) it's more efficient.
Watching plain properties
the $watch() function, by default only checks object reference equality. So within each $digest it will check to see if the new and old values pointing to the same object.
Watching objects and arrays
If you want to $watch() an object, you have to switch to the deep watch and that means that within each $digest, it will check the whole tree to see if the structure or values are changed. So, bigger the object, more expensive the check.
$watchGroup(), an alternative to objects/array watchers
If you have a group of related properties like ie a person (name, surname, age), you could define it like plain properties, and use $watchGroup(), that works on the same way like a common $watch() but taking a list of properties to watch rather than one.

Angular data binding - ng-book claims you should bind by object attribute. why?

“it’s considered a best-practice in Angular to bind references in the views by an attribute on an object, rather than the raw object itself.”
Excerpt From: Ari Lerner. “ng-book.” (page 66 in the latest revision).
I've not seen this reference anywhere else and wonder if it really makes any difference?
It's to avoid child scoping issues. There are weird things with the scope on angular objects. Basically, there is scope inheritance for objects on scopes, but not for primitives. Here's a problem I've had.
<input ng-model="theModelOnMyScope" />
$scope.theModelOnMyScope = "This is the model";
Looks fine right? But in some cases it won't update on the scope in the controller you're editing because angular may create a childScope for the ng-model in input, depending on how your page is structured. Now, this is the solution to this particular problem.
<input ng-model="anObject.theModelOnMyScope" />
$scope.anObject = {theModelOnMyScope:"This is the model};
And this will work. The reason is it will is because, if the referenced property on the view is a property of an object, Angular will try to find an object on the current scope, and if it can't, it will go UP a level and try to find an object on the scope's parent. So you can make use of scope inheritance with objects. It doesn't do that with primitives, for some reason. So to avoid child scoping issues, it's just best to attach your properties to objects.

How to communicate different levels in the same javascript object

I am trying to namespace my jQuery app.
Example:
var app = {
data : {
data1: ''
},
fn: {
setData1: function(value){
app.data.data1 = value
}
}
}
This works, but is there a better solution which doesn't use the full path? Moreover, is this a good code structure for a medium-sized application?
Javascript does not have syntax for specifying shortcuts to a parent element in a nested literal object definition. And, in fact, Javascript a nested object inside another object could have been defined anywhere and the reference assigned into the object and could be assigned into many objects so there is no real such thing as a parent at runtime as far as Javascript is concerned. Javascript just doesn't work that way.
As such, if you want to reference another element of the object that is not below it, then you will have to use the full path of object names starting from the top of the object.
As to whether this is a good way to do this, that is entirely context-specific. At first glance (and with no other context supplied), I don't see why you need the fn or data levels in your object. Data properties and methods can be at the same level and that is commonly done without adding extra levels. You will find that extra levels that aren't necessary just increase the amount of typing in your code and do not improve performance. You should give your methods and data properties meaningful enough names that it's very clear what they are and what they are used for. A name like data1 is not a particularly good example.
In addition, there is generally not a reason to make a setData1() method for a public data1 property, but if you put them at the same level, you can do use the this pointer in the method which will be set to app if someone calls app.setData1():
var app = {
data1: ''
setData1: function(value){
this.data1 = value;
}
}

AngularJS - Best practice: model properties on view or function calls?

For quite sometime I've been wondering about this question: when working with AngularJS, should I use directly the model object properties on the view or can I use a function to get the that property value?
I've been doing some minor home projects in Angular, and (specially working with read-only directives or controllers) I tend to create scope functions to access and display scope objects and their properties values on the views, but performance-wise, is this a good way to go?
This way seems easier for maintaining the view code, since, if for some reason the object is changed (due to a server implementation or any other particular reason), I only have to change the directive's JS code, instead of the HTML.
Here's an example:
//this goes inside directive's link function
scope.getPropertyX = function() {
return scope.object.subobject.propX;
}
in the view I could simply do
<span>{{ getPropertyX() }}</span>
instead of
<span>{{ object.subobject.propX }}</span>
which is harder to maintain, amidst the HTML clutter that sometimes it's involved.
Another case is using scope functions to test properties values for evaluations on a ng-if, instead of using directly that test expression:
scope.testCondition = function() {
return scope.obj.subobj.propX === 1 && scope.obj.subobj.propY === 2 && ...;
}
So, are there any pros/cons of this approach? Could you provide me with some insight on this issue? It's been bothering me lately, on how an heavy app might behave when, for example a directive can get really complex, and on top of that could be used inside a ng-repeat that could generate hundreds or thousands of its instances.
Thank you
I don't think creating functions for all of your properties is a good idea. Not just will there be more function calls being made every digest cycle to see if the function return value has changed but it really seems less readable and maintainable to me. It could add a lot of unnecessary code to your controllers and is sort of making your controller into a view model. Your second case seems perfectly fine, complex operations seems like exactly what you would want your controller to handle.
As for performance it does make a difference according to a test I wrote (fiddle, tried to use jsperf but couldn't get different setup per test). The results are almost twice as fast, i.e. 223,000 digests/sec using properties versus 120,000 digests/sec using getter functions. Watches are created for bindings that use angular's $parse.
One thing to think about is inheritance. If you uncomment the ng-repeat list in the fiddle and inspect the scope of one of the elements you can see what I'm talking about. Each child scope that is created inherits the parent scope's properties. For objects it inherits a reference, so if you have 50 properties on your object it only copies the object reference value to the child scope. If you have 50 manually created functions it will copy each of those function to each child scope that it inherits from. The timings are slower for both methods, 126,000 digests/sec for properties and 80,000 digests/sec with getter functions.
I really don't see how it would be any easier for maintaining your code and it seems more difficult to me. If you want to not have to touch your HTML if the server object changes it would probably be better to do that in a javascript object instead of putting getter functions directly on your scope, i.e.:
$scope.obj = new MyObject(obj); // MyObject class
In addition, Angular 2.0 will be using Object.observe() which should increase performance even more, but would not improve the performance using getter functions on your scope.
It looks like this code is all executed for each function call. It calls contextGetter(), fnGetter(), and ensureSafeFn(), as well as ensureSafeObject() for each argument, for the scope itself and for the return value.
return function $parseFunctionCall(scope, locals) {
var context = contextGetter ? contextGetter(scope, locals) : scope;
var fn = fnGetter(scope, locals, context) || noop;
if (args) {
var i = argsFn.length;
while (i--) {
args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText);
}
}
ensureSafeObject(context, expressionText);
ensureSafeFunction(fn, expressionText);
// IE stupidity! (IE doesn't have apply for some native functions)
var v = fn.apply
? fn.apply(context, args)
: fn(args[0], args[1], args[2], args[3], args[4]);
return ensureSafeObject(v, expressionText);
};
},
By contrast, simple properties are compiled down to something like this:
(function(s,l /**/) {
if(s == null) return undefined;
s=((l&&l.hasOwnProperty("obj"))?l:s).obj;
if(s == null) return undefined;
s=s.subobj;
if(s == null) return undefined;
s=s.A;
return s;
})
Performance wise - it is likely to matter little
Jason Goemaat did a great job providing a Benchmarking Fiddle. Where you can change the last line from:
setTimeout(function() { benchmark(1); }, 500);
to
setTimeout(function() { benchmark(0); }, 500);
to see the difference.
But he also frames the answer as properties are twice as fast as function calls. In fact, on my mid-2014 MacBook Pro, properties are three times faster.
But equally, the difference between calling a function or accessing the property directly is 0.00001 seconds - or 10 microseconds.
This means that if you have 100 getters, they will be slower by 1ms compared to having 100 properties accessed.
Just to put things in context, the time it takes sensory input (a photon hitting the retina) to reach our consciousness is 300ms (yes, conscious reality is 300ms delayed). So you'd need 30,000 getters on a single view to get the same delay.
Code quality wise - it could matter a great deal
In the days of assembler, software was looked like this:
A collection of executable lines of code.
But nowadays, specifically for software that have even the slightest level of complexity, the view is:
A social interaction between communication objects.
The latter is concerned much more about how behaviour is established via communication objects, than the actual low-level implementation. In turn, the communication is granted by an interface, which is typically achieved using the query or command principle. What matters, is the interface of (or the contract between) collaborating objects, not the low-level implementation.
By inspecting properties directly, you are hit the internals of an object bypassing its interface, thus couple the caller to the callee.
Obviously, with getters, you may rightly ask "what's the point". Well, consider these changes to implantation that won't affect the interface:
Checking for edge cases, such as whether the property is defined at all.
Change from getName() returning first + last names rather than just the name property.
Deciding to store the property in mutable construct.
So even an implementation seemingly simple may change in a way that if using getters would only require single change, where without will require many changes.
I vote getters
So I argue that unless you have a profiled case for optimisation, you should use getters.
Whatever you put in the {{}} is going be evaluated A LOT. It has to be evaluated each digest cycle in order to know if the value changed or not. Thus, one very important rule of angular is to make sure you don't have expensive operations in any $watches, including those registered through {{}}.
Now the difference between referencing the property directly or having a function do nothing else but return it, to me, seems negligible. (Please correct me if I'm wrong)
So, as long as your functions aren't performing expensive operations, I think it's really a matter of personal preference.

How to obtain true de-referenced object instances in javascript

I'm trying to get a better understanding of object oriented patterns in JavaScript. I particulary like the way EmberJS implements their classes with .extend and .create from Parent class Objects.
I've tried to implement a basic version of this on my own, but to no success, my newly instantiated Objects reference the same Object. I.e If I increment a private counter var in instance a via a public method, then separately do the same to instance b, b will reflect both increments.
I was able to achieve a de-referenced object via Object.create(myClass), however this is undesirable as I'd like to achieve this internally and also not rely on client support for that native method.
Here's a jsbin of what I've got: http://jsbin.com/zepaju/6/edit?js,console
Thanks for any help!
This is a pretty big subject, because there isn't a perfect way to make JavaScript work like Java-- you'll always have to invent some new coding idiom, and different people have different preferences.
Looking at your linked code, it's hard to be sure what you're gunning for but it looks like the problem is that you're thinking of an object's prototype as a "class", which is copied into each "instance" (like in Java)-- this isn't the case.
Your create() function is creating each "instance" by doing Object.create(Poll), which makes a new object with the Poll object as its prototype. When you refer to properties of the resulting objects, and those properties are not directly defined on the object, what you get is a reference to a property of the single Poll object.
The fact that you've sealed the Poll object's internal variables within a closure doesn't make any difference to this; the closure variables are hidden from the outside world, but they are accessible to the methods of the Poll object, and those methods are shared between all "instances".
If you want a function that spits out objects with a particular set of methods, and which hide their internal data in a closure, that might look like:
function Poll(challenger,incumbent) {
var challengerVotes=0;
var incumbentVotes=0;
return {
voteForChallenger: function() {challengerVotes++},
voteForIncumbent: function() {incumbentVotes++},
winner: function() {return challengerVotes>incumbentVotes ? challenger : incumbent}
}
}
var poll1 = Poll("Edward","Jacob");
var poll2 = Poll("Vanilla","Stilton");
poll1 and poll2 would not affect one another, and there would be no way to access the vote counts of either except through the supplied methods. I appreciate you're looking for a more generic approach but this is an example of how you might start.

Categories

Resources