Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Conversation

briceburg
Copy link
Contributor

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.

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.
@zzal
Copy link

zzal commented Aug 9, 2012

+1

@pkozlowski-opensource
Copy link
Member

+1 as well, this would be almost like having Tiles :-)

@brettlaforge
Copy link

+1

@mhevery
Copy link
Contributor

mhevery commented Aug 31, 2012

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):
http://code.google.com/legal/individual-cla-v1.0.html

For corporations (print, sign and scan+email, fax or mail):
http://code.google.com/legal/corporate-cla-v1.0.html

@briceburg
Copy link
Contributor Author

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.

@mhevery
Copy link
Contributor

mhevery commented Sep 5, 2012

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 mhevery closed this Sep 5, 2012
@SET001
Copy link

SET001 commented Jun 26, 2013

@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?

@ecolak
Copy link

ecolak commented Jun 28, 2013

@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.

@BeOleg
Copy link

BeOleg commented Sep 25, 2013

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

@petebacondarwin
Copy link
Contributor

@mhevery's solution is more inline with the Angular way of doing things. You end up with clean understandable HTML markup.

@petebacondarwin
Copy link
Contributor

You could always put an ng-controller around the ng-include element, which sets up the scope for the included template.

@ifeltsweet
Copy link

Check another way to accomplish what you want here http://stackoverflow.com/a/20639139/220086.

Example: http://jsfiddle.net/Cndc6/4/

@BeOleg
Copy link

BeOleg commented Dec 17, 2013

This is a good solution, but rather a static data model, than an ng-controller

@johnculviner
Copy link

Coming from Knockout.js I could very explicitly do something like this which makes a lot of sense:

<div data-bind="template: { name: 'myTemplate', data: dataForTheTemplate }"></div>
<div data-bind="template: { name: 'myTemplate', data: otherDataForTheTemplate}"></div>

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:

directive('newScope', function() {
      return {
        scope: true,
        priority: 450,
      };
    });

Ex:

  <div new-scope="" ng-init="myVar = 'one instance'" ng-include="'template.html'"></div>
  <div new-scope="" ng-init="myVar = 'another instance'" ng-include="'template.html'"></div>

Demoed here:
http://plnkr.co/edit/El8bIm8ta97MNRglfl3n?p=preview

@gevgeny
Copy link

gevgeny commented Feb 13, 2014

+1 for this feature

@JonCognioDigital
Copy link

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.

@petebacondarwin
Copy link
Contributor

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>

@JonCognioDigital
Copy link

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.

@c-johnson
Copy link

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).

@7c6f1568-555e-42a8-aff6-9045799c8b86

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
var props = scope.$eval(attrs.myComponentScope);
to
var props = scope.$parent.$eval(attrs.myComponentScope);
otherwise properties from the parent scope were evaluating to undefined. Even then, I have got strange bugs where the template just didn't work correctly, for example when using the new scope values inside a filter.

The newScope directive suggested by johnculviner did however work fine in my case.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.