Skip to content

Support for manual content reprojection #1989

Closed

Description

@mhevery

GOAL

  • provide <content>-like way of re-projecting content from one location of the tree to another.
  • Preserve the injection and context variables of the source

Implementation

Here is a proposed implementation skeleton.

  • make TemplateRef queryable (it already is injectable)

ng-outlet

@Directive({
  selector: '[ng-outlet]',
  properties: {
    'ngOutlet': 'ngOutlet',
    'ngOutletLocals': 'ngOutletLocals'
  },
  lifecycle: [onChange]
})
class NgOutlet {
  ngOutletLocals:any;
  ngOutlet:TemplateRef; // Maybe this should take an array of templates???

  constructor(public viewContainer: ViewContainerRef) { }

  onChange() {
    // todo: Don't destroy the view if ngTemplateRef did not change
    this.viewContainer.clear();
    var viewRef:ViewRef = this.viewContainer.createEmbeddedView(this.ngOutlet);
    // use structural changes to cal setLocal only if hash `ngOutletLocals` changed.
    for(var prop in this.ngOutletLocals) {
      viewRef.setLocal(prop, this.ngOutletLocals[prop]);
    }
  }
}

Example of Usage

@Component({
  selector: 'my-component'
})
@View({
  template: `
  <button template="var i = index" (click)="onClick()">
    {{i}}: {{text}}
  </button>

  <!-- here for simplicity, but it could be anywhere in the tree -->
  <template *ng-outlet="templates.first; locals={'index': 1}"></template>
`
})
class MyComponent {
  text: string;
  templates: QuerList<TemplateRef>;

  constructor(@ViewQuery(TemplateRef) templates: QueryList<TemplateRef>) {
    this.templates = templates;
  }

  onClick() {
    // do something
  }
}

Activity

  1. added this to the milestone on May 19, 2015
  2. mhevery commented on May 19, 2015

    @mhevery
    ContributorAuthor
  3. matanlurey commented on May 22, 2015

    @matanlurey
    Contributor

    I like. I have a prototype of something similar we can look at when you're back.

  4. modified the milestone: on May 29, 2015
  5. 53 remaining items

  6. removed this from the alpha-39 milestone on Oct 5, 2015
  7. mhevery commented on Oct 25, 2015

    @mhevery
    ContributorAuthor

    This is done.

  8. user414 commented on Mar 11, 2016

    @user414

    This seems to be exactly what I'm looking for except that the documentation for it is lacking. Looking at the code it seems NgOutlet never made it in but ngForTemplate is the one to use, seems possible to use this with one example I saw in some other issue which I will link here for reference

    #4769

    but would be nice to add this in the doc of the ngFor

    https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngFor

    if I come up with a simple plunker to show this will post it here.

  9. zoechi commented on Mar 11, 2016

    @zoechi
    Contributor
  10. user414 commented on Mar 11, 2016

    @user414

    @zoechi Thank you very much

  11. user414 commented on Mar 11, 2016

    @user414

    I didn't realize until now that the doc is in another project, I will always make sure in the future I look up the angular.io issues/merge request for info, thanks again @zoechi

  12. user414 commented on Mar 14, 2016

    @user414

    Since @zoechi pointer saved me time thought I would use some of that time to post back some comments. Overall the implementation was as expected and described in the new docs except that I would have expected the index to work in the called template like this

    <template #hero #i="index">
    <hero-detail [hero]="hero"><span>This is my index {{i}}</span></hero-detail>
    </template>
    

    Is it stands now if you need the index in the template pointed to in the ngForTemplate it seems you are out of luck, or at least couldn't make it work.

    I would also have expected, and maybe I missed how to do this, to be able to easily define a template somewhere outside for reuse. In the hero example I would have expected to be able to define the

    <template #hero #i="index">
    

    completely outside of

    <hero-dashboard [heroes]="heroes">
    

    so that in app.component.ts I could obtain a templateRef somehow and bind it to the child component instead like this

    <hero-dashboard [heroes]="heroes" [heroDetailTmpl]="templateRef">
    

    so that I can reuse it in multiple child component if need be without copy pasting. Thanks.

  13. user414 commented on Mar 14, 2016

    @user414

    Will modify my last comment, the index actually works. In my example, I was using it with just one element hence why I didn't see it changing. Which brings me to another comments. It might be good to modify the example in the new documentation to add one with the index to show that it can indeed work.

  14. user414 commented on Mar 18, 2016

    @user414

    A few more comments. It would also be useful to document that it does not seem possible to pass variable/parameter other then built in index to ngForTemplate target like this

    <template ngFor  [ngForOf]="[jsonObject]" [ngForTemplate]="customRenderer" #itemNumber="itemNumber"></template>
    
    <template #customRender #itemNumber #parentObject>
       <span>{{whichScopeAmI(itemNumber)}}</span>
      <span>{{parentObject.whichScopeAmI(itemNumber)}}</span>
    </template>
    

    I found that it is not possible but even though I think it might be a good feature to add, it would also be good to document what works and doesn't work. I would expect this ngForTemplate to work similarly to a method call where I wouldn't need to use ngFor and could just call another template defined somewhere else with extra parameter. However, it doesn't work like that and I think should be documented. It would also be good to document the scope of this target template, through experimentation I came to the conclusion that the scope is where the template is declared but I'm not sure it would have been my vote, it would be nice to have a reference to the object where the template is being run so at least we can access method there, otherwise I find it looses some flexibility since you have no access to where you will run. All of this could be done in equivalent javascript/typescript function and inheritance but kind of defeats the purpose.

  15. user414 commented on Mar 18, 2016

    @user414

    Wanted to add a workaround for the issue describe above, for now I simply encapsulate my ngFor object inside another object that I include the parameter I require inside, it's not very elegant but works in case it helps someone else.

  16. angular-automatic-lock-bot commented on Sep 8, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. locked and limited conversation to collaborators on Sep 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

effort1: hoursfeatureLabel used to distinguish feature request from other issues

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions