"Overcoming" ngInclude scope

5,379 views
Skip to first unread message

Dave Merrill

unread,
Jan 23, 2013, 10:09:06 AM1/23/13
to ang...@googlegroups.com
I'm finding working with ngInclude a bit awkward. The root of the problem is that it inherently and unavoidable (AFAIK) creates a new scope, when what I want to do is reuse a section of HTML, or pull in an external template on demand.

Say there's a var defined in the parent controller's $scope, and used as the model for a field contained in an ngInclude. Changes to that far in the parent controller's $scope are reflected inside the ngInclude initially. However, as soon as the field gets modified directly, that breaks the inheritance from the parent controller, decoupling the ngIncluded scope from it. After that, changing parent controller $scope var has no effect within the include.

I understand that this is completely expected, but I'm wondering how people deal with that. Possible options I can see are:
- Always attach the controller you want in effect to a containing element inside each ngInclude. Downside is that it's impossible for the include contentsto participate directly in the parent controller; they're in their own.
- Never have modifiable elements inside an ngInclude

My main actual use case is a section of the page that's only loaded on demand, and wanting to set variables for it via routes.

Am I making sense here?

Dave

Dave Merrill

unread,
Jan 23, 2013, 10:32:16 AM1/23/13
to ang...@googlegroups.com

Dave Merrill

unread,
Jan 23, 2013, 10:55:58 AM1/23/13
to ang...@googlegroups.com
Also, related, when ngInclude has an onload property, code to run after the included template is loaded. However, that code runs in the scope of the parent controller, not the scope of the include itself, or that of an ng-controller attribute on the ngInclude element.

Putting these together:
- The controller for view code inside an ng-include MUST be within the ng-included content to be in the same scope as the content
- The onLoad method for that ng-include CANNOT be inside the ng-included content

Net effect is that you have to split the controller code for the include into two parts, undesireable.

Does anyone else consider this not great?

Dave

Dave Merrill

unread,
Jan 23, 2013, 11:01:43 AM1/23/13
to ang...@googlegroups.com
Also, can someone explain to me why the value of varA in include 2 shows as 'foo', not 'bar', which s what its controller set it to?

Dave

Peter Bacon Darwin

unread,
Jan 23, 2013, 11:53:11 AM1/23/13
to ang...@googlegroups.com

Hi Dave
Whenever there are child scopes and you are inheriting a field then the safest and easiest thing to do is simply always reference properties on an object that is on scope rather than a property directly on scope.

Pete
...from my mobile.

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
 
 

Dave Merrill

unread,
Jan 23, 2013, 12:15:46 PM1/23/13
to ang...@googlegroups.com
Thank you Peter, as always, that was it.

Can you point me to where in the docs the reason for that behavior is explained?

Dave

Peter Bacon Darwin

unread,
Jan 23, 2013, 12:37:28 PM1/23/13
to ang...@googlegroups.com
It is fundamental to javascript prototypical inheritance.  Have a look at this page for a thorough explanation.
Pete

Thiago FeLix

unread,
Jan 23, 2013, 12:48:47 PM1/23/13
to ang...@googlegroups.com
As Miško says in his best pratices video, we should not "treating scope as model".

Always you are using ngModel try to use dot, like "something.property"

=)

Dave Merrill

unread,
Jan 23, 2013, 1:17:26 PM1/23/13
to ang...@googlegroups.com
@Peter and @Thiago: Right. I know this, lost track of the implication in this context, careless me. My real apps have one or more data objects in $scope in most cases, and always where it matters. This came up mostly because I was trying a simplified case, too simplified in this case.

The real thing I'm trying to do is set up generic passing of route vars into the scope of the current tab's controller. I'm using ng-include (not ng-view), so multiple tabs can be loaded at once, so as far as I can tell, that doesn't happen automagically. 

Instead I set up $on("$routeChangeSuccess" in the top level controller, which extracted the params from the route, and broadcast a 'tabChange' event. Individual tab controllers had a $on('tabChange'..) set up to handle that. I was thinking there would be generic code to copy those params into the scope, but it's a bit weird to be  locked into the name of the controller scope object to populate, and I didn't want the incoming route vars to have dots in them either. Copying directly into primitives in the scope "works", but has the inheritance limitations you both pointed out.

Has anyone tried to wire up anything like this, to generically pass whatever route parameters are defined into a particular child scope? Am I (hopefully) missing some way this can happen without me building infrastructure to cause it?

Thanks again to all, as always.

Dave

Sekib Omazic

unread,
Jan 30, 2013, 3:25:40 AM1/30/13
to ang...@googlegroups.com
Maybe this can help:


There is also a Git-Project trying to solve this problem:



Cheers,

Sekib

mar...@theotherfirm.com

unread,
Jun 27, 2013, 6:09:03 AM6/27/13
to ang...@googlegroups.com
You can create a custom include directive that does not create a new scope. It grabs the html and does $compile(html)(scope) in the current scope as opposed to a scope.$new(). Intuitively, the included html behaves as if it were inline. I heard in passing that there might be memory leak concerns with this approach but I'm not sure why.
Reply all
Reply to author
Forward
0 new messages