The "Dot" in the model

178 views
Skip to first unread message

Łukasz Bachman

unread,
Oct 10, 2014, 3:25:44 AM10/10/14
to ang...@googlegroups.com
Hi guys!

Some time ago I watched the Angular Best Practices Video where Miško Hevery make the following, very important statement: "Scope is not the model, scope has references to the model". Later he also states that "(when)... using ng-model, there's got to be a dot in there somewhere".

So recently I'm applying this rule to my model and developed a habit of creating a "$scope.model = {}" object which is then populated with whatever is necessary in the view. For instance, to show selectable list of users I might write:

$scope.model = {
   users: [ { id: 1, username: "Łukasz Bachman", age: 29 }, { id: 2, username: "John Doe", age: undefined } ],
   selectedUserId: undefined
};

And then ofcourse I iterate over ng-repeat="user in model.users" and create some click handler like so: ng-click="model.selectedUserId = user.id".

This looks fine for me and haven't found any issues with this approach so far. But lately the first sentence that I quoted has been constantly roaring in my head. Am I really using it right? Perhaps I should only keep references to the model there, not attach the data to this universal "model" container! An example:

var usersArray = [ { id: 1, username: "Łukasz Bachman", age: 29 }, { id: 2, username: "John Doe", age: undefined } ];
var selectedUserId = undefined;

$scope.model = {
   users: usersArray,
   selectedUserId: selectedUserId
};

Can anyone tell me if this is having any benefits over my current approach? I'm most interested in:
  • does either of the solutions hides some bugs or flaws?
  • is the overhead of watching the scope is higher/lower in any case (performance implications)?
  • is there any recommended way of doing this?
If you have some references that explain this in depth, then please let me know. I'll be glad to read and learn more about it, but if some of Angular Masters can simply say "you are doing it wrong/right" then I'd highly appreciate it.

Thanks!

Eric Eslinger

unread,
Oct 10, 2014, 10:12:29 AM10/10/14
to ang...@googlegroups.com
The problem with the dot (as I understand it) is that child scopes work by prototypally inheriting from parent scopes. 

So if you have a situation where you've got a scope property, let's call it $scope.tuber = 'potato', and you've got some child scopes which access the same tuber property. If they just read the property, it's no big deal. But if a child scope sets the tuber property = 'carrot', in the child scope that will just set the tuber property directly on the child scope (as well it should with prototypal inheritence).

If, however, there was $scope.vegetables = {tuber: 'potato'} and a child scope sets $scope.vegetables.tuber = 'carrot', then the javascript runtime will find the vegetables object on the parent scope and set the tuber attribute of vegetables (so vegetables.tuber will be carrot in all child scopes).

If at any time in a child scope you end up doing $scope.vegetables = {tuber: 'beet'}, you'll break prototypal inheritance just like you would if you had done it the other way. The child scope will get the new field direct on its object, and not look up the prototype chain to find its parent.

Generally, I try to just put all my scope-relevant view variables (collapsed this or searchfield that) in a $scope.view object that I create in all my controllers, so I'm always doing view.tuber = 'potato', and I never set $scope.view directly outside of its initialization (which I will do with a conditional initialization). In coffeescript it looks like

$scope.view ?= {}
$scope.view.tuber = 'potato'
$scope.view.planted = true
  $scope.view.tuberModel = potato

etc etc.



--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Sander Elias

unread,
Oct 11, 2014, 2:05:27 AM10/11/14
to ang...@googlegroups.com

Hi Łukasz,

  • does either of the solutions hides some bugs or flaws?

No, it’s basically exactly the same thing. However, I think the second approach might confuse you. let me explain.
you decide to do some assigning in your controller, like setting the selectedUserIs so you do in your controller:
selectedUserId = fetchAUser();. This will not update $scope.model.selectUserId. You have to remember that
JavaScript primitives, are never passed by reference.

  • is the overhead of watching the scope is higher/lower in any case (performance implications)?

No. As I said, it is exactly the same thing. there is no difference in the $scope. All that you have done is
put some extra visual clues in your code. with exception of the primitives as mentioned above. those will
consume some extra memory (the extra reference to the array will do to, but this is such a small amount,
you can safely ignore that)

  • is there any recommended way of doing this?

Your first way is the recommend way if you still want to use $scope. The current recommend way is to
use the controllerAs syntax, in where the $scope inheritance is mostly mitigated.
I created a sample plunk here, that I created for someone that needed localized events. There are a
couple of controllers in there that follow the new recommend way.
When you have any questions left, don’t’ hesitate to ask!

Regards
Sander

Łukasz Bachman

unread,
Oct 11, 2014, 11:59:22 AM10/11/14
to ang...@googlegroups.com
Hi guys!

Thx Eric, I understand the ins and outs of prototypical inheritance in handling scopes. I think that your example also is using my 1st approach, which my current way of doing thigs. So I think that we are on the same page here.

Thx Sander, I was looking for explanation like that! You are absolutely right about passing primitives by value, I shouldn't use a primitive in my example. I was writing this up in a hurry :-)

I assumed that the 2nd approach might be a bit faster, because if the whole object would have changed, then it would be enough to notice different references (for instance: old usersArray was using #1234 reference, the new one is #4567, so we already know that the scope is dirty without checking array elements).

Good point about the new "controller as" syntax, but I think that you can still have the same doubts about attaching model to this reference. Or perhaps the "dot in model" does not apply to this new approach? Frankly, inheritance won't be a problem here anymore, so perhaps Angular team would prefer to bind model to this directly?

You guys made me think that I'm not doing anything wrong, but I think that I would rest assured if I found some info about it in the official Angular documentation.

Best regards,
Łukasz Bachman

--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/zAjgjeyWptI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

Sander Elias

unread,
Oct 11, 2014, 12:40:30 PM10/11/14
to ang...@googlegroups.com

hi Łukasz,

Nope, no speed difference. If you are putting in information pro reference, it’s just that. 2 pointers to the same data.
There is some documentation and recorded talk in where the core team hints the controllerAs syntax is from now on the
preferred way to do things. But as I see it, they are nudging us that direction, not pushing.
So it boils down to your preferences.

In the controllerAs, an dot in your data is less important. There is no technical reason anymore for the dot rule
(well, kind off, that happens technically is that this gets put on the scope automatically. so, $scope.controlleAsName is
available on the scope hierarchy)
I think it still is a good plan to put your models in their own object, and attach that to the this.

Does this all make sense to you?

Regards
Sander

Łukasz Bachman

unread,
Oct 14, 2014, 1:59:28 AM10/14/14
to ang...@googlegroups.com
I think it all falls into places nicely now. Thanks!

Best regards,
Łukasz Bachman

--
Reply all
Reply to author
Forward
0 new messages