-
Notifications
You must be signed in to change notification settings - Fork 27.3k
feat(ngInclude): childScope.$eval(onincludeExp) #1227
Conversation
Expressions are now evaluated against the included [child] scope by passing them as the `onInclude` attribute. This is similar to onload, but evaluates against the included's scope vs. the directive's scope.
+1 |
+1 as well, this would be almost like having Tiles :-) |
+1 |
Thanks for your contribution! In order for us to be able to accept it, we ask you to sign our CLA (contributor's license agreement). CLA is important for us to be able to avoid legal troubles down the road. For individuals (a simple click-through form): For corporations (print, sign and scan+email, fax or mail): |
Hey Misko! In truth, this patch spurred from a discussion on the mailing list; https://groups.google.com/forum/?fromgroups=#!topic/angular/5clM0kjHXq8 I believe that it gives developers flexibility to do things in a way that may come more naturally to them (while also providing a shortcut to inject values into the included partial's scope without having to write [accessor] logic into the parent controller). Could you suggest a curt method for accomplishing the example @ http://jsfiddle.net/briceburg/NMmyY/1/ that is perhaps a "more angular" way? (ps) - CLA signed. |
I think you are trying to subvert ng-include into a component system. I think a component is a much better fit for what you are looking for: http://plnkr.co/edit/qnzNs0?p=preview I just don't feel comfortable that something which is declared in one scope can reach into another scope and modify its content. I am going to close this PR. If you feel that my solution with a component is not sufficient/better, feel free to reopen it and provide more context as to why it should be included. |
@mhevery, your solution require creating separate directive each time when simple template inclusion needed. I suppose directives are for more complex things than just template inclusion. In your case we will end up with bunch of trivial code (btw some one may store directive in separate files ), so why not to avoid this if possible? |
@mhevery I also think this is a much needed feature. Directives are great but they are an overkill for something like this. It would be nice to just inject some parameters to a template through ng-include. |
Yeah, I'd much rather being able to use an inner scop-specific variable fro my ng-included partail than using this component system. +1 |
@mhevery's solution is more inline with the Angular way of doing things. You end up with clean understandable HTML markup. |
You could always put an ng-controller around the ng-include element, which sets up the scope for the included template. |
Check another way to accomplish what you want here http://stackoverflow.com/a/20639139/220086. Example: http://jsfiddle.net/Cndc6/4/ |
This is a good solution, but rather a static data model, than an ng-controller |
Coming from Knockout.js I could very explicitly do something like this which makes a lot of sense:
I don't think making a one off directive for each instance of wanting to do this makes code as comprehensible as just doing it in HTML with a universal directive that can initialize the template's scope one time without having side effects. I would compare this to saying "yeah you have to make a directive just to use a template" (which would be silly). That's not the case that's why ngInclude exists. We just can't tell it what data to have on it's new scope. I really like the @briceburg's solution as being least hacky and most straightforward. Also ng-init on a controller evaluates in the controller's (or any directive) scope as expected which is sort of inconsistent behavior. This doesn't work with ngInclude because of the directives priority and terminal flag I believe. This leads to some definite API confusion unless you know Angular really well. Furthermore the documentation for "onload" on ngInclude makes it seem like the expression might be evaluated on the child scope that ngInclude creates but instead its evaluated on the parent scope which can lead to errors. Perhaps I'll update the docs... Here is a directive which solves the issue by creating a new scope on the element at the correct priority. This can be used with ng-init:
Ex:
Demoed here: |
+1 for this feature |
Another +1 I came here looking for exactly this. I don't want to have to create a directive just so that I can include a form in 2 places. |
Here is a simple component-oriented directive that may provide you what you want. http://plnkr.co/edit/cK4SxK7NyOdWojMn4buB?p=preview angular.module('app', [])
.directive('myComponent', function() {
return {
scope: {},
templateUrl: function(element, attrs) {
return attrs.myComponent;
},
link: function(scope, element, attrs) {
var props = scope.$eval(attrs.myComponentScope);
angular.forEach(props, function(value, key) {
scope[key] = value;
});
}
};
}); It is generic enough to be used in many places in place of ng-include: <div my-component="partial.html" my-component-scope="{ name: 'Peter' }"></div> |
Given that I learned pretty much everything I know about Angular by reading Peter's book, I'm going to take that answer as gospel. The fact that I actually understand how it works is a bonus too :) Thanks Peter. |
I've followed a trail of internet to get here, and it's been a couple of months since Peter's last answer. Should this last answer be the "idiomatic" way to pass static variables into child templates? Is there a move to standardize the directive Peter wrote as part of the ng-include directive? As John pointed out above, this is also something that comes out-of-the-box with Ember.js that I feel is a common enough of use-case to be included in the core directives (assuming there is no problem with Peter's directive). |
Given other frameworks I have used in the past, I also expected AngularJS to provide this out of the box. The myComponent suggested by petebacondarwin is exactly what I am looking for. Unfortunately it didn't quite work for me with AngularJS v1.2.21. I had to change The newScope directive suggested by johnculviner did however work fine in my case. |
Allow expressions to be evaluated against the included scope by passing them as the
onInclude
attribute.This is similar to onload, but evaluates against the included's [child] scope vs. the directive's [parent] scope.
See: http://jsfiddle.net/briceburg/NMmyY/1/ as a demonstration.