9

I need to create unique Anchor Names/Components in a ngFor loop to use it with ComponentResolver.resolveComponent.

<div>
  <table>
    <tr *ng-for="#vIndex of vArr">
      <td *ng-for="#hIndex of hArr">
        <div #uniqueanchorname{{vIndex}}_{{hIndex}}></div>
      </td>
    </tr>
  </table>
</div>

the resulting html should look something like that:

<div>
  <table>
    <tr>
      <td>
        <div #uniqueanchorname0_0></div>
      </td>
      <td>
        <div #uniqueanchorname0_1></div>
      </td>
    </tr>
    <tr>
      <td>
        <div #uniqueanchorname1_0></div>
      </td>
      <td>
        <div #uniqueanchorname1_1></div>
      </td>
      <td>
        <div #uniqueanchorname1_2></div>
      </td>
    </tr>
  </table>
</div>

With that i can use the DynamicComponentLoader like:

loader.loadIntoLocation(responseDependentComponent, elementRef, 'uniqueAnchorName1_2');

the resulting HTML does not get replaced and will look something like:

<div>
  <table>
    <tr>
      <td>
        <div #uniqueanchorname{{vIndex}}_{{hIndex}}></div>
      </td>
      <td>
        <div #uniqueanchorname{{vIndex}}_{{hIndex}}></div>
      </td>
    </tr>
    <tr>
      <td>
        <div #uniqueanchorname{{vIndex}}_{{hIndex}}></div>
      </td>
      <td>
        <div #uniqueanchorname{{vIndex}}_{{hIndex}}></div>
      </td>
      <td>
        <div #uniqueanchorname{{vIndex}}_{{hIndex}}></div>
      </td>
    </tr>
  </table>
</div>

If the creation of unique anchor names is not possible. Is there an other way to load components into a specific location?

4
  • could you try something like #{{'uniqueAnchorName' + vIndex + '_' + hIndex}} Commented Oct 6, 2015 at 18:50
  • I don't really understood your problem. Did that work? It didn't? I haven't tried it, but the only thing I can see is the fact of using uppercase in your variable names. If you write uniqueAnchorName the browser will lowercase it to uniqueanchorname before ng2 compiles. Commented Oct 6, 2015 at 19:16
  • @PankajParkar mustache ({{xxx}})does not gets replaced in attributes, the resulting html still looks like #uniqueAnchorName{{vIndex}}_{{hIndex}} Commented Oct 6, 2015 at 19:23
  • 2
    @EricMartinez thx for the hint. But the mustache does not get replaced in attributes. Commented Oct 6, 2015 at 19:25

2 Answers 2

5

Sorry, there's been a misunderstanding.

import {
  Directive, 
  Component, 
  View, 
  CORE_DIRECTIVES, 
  ElementRef, 
  DynamicComponentLoader,
  Input,
  QueryList,
  ViewChildren
} from 'angular2/angular2'

@Component({
  selector: 'my-cmp'
})
@View({
  template: 'my component'
})
class MyCmp {}

@Directive({
  selector: '[location]'
})
class Location {
  @Input() h: number;
  @Input() v: number;
  constructor(public elementRef: ElementRef) {
  }
}

@Component({
  selector: 'my-table'
})
@View({
  template: `
  <table border>
    <tr *ng-for="#v of vArr">
      <td *ng-for="#h of hArr">
        <div location v="{{v}}" h="{{h}}">{{v}}-{{h}}</div>
      </td>
    </tr>
  </table>
  h:<input #hi value="1"><br>
  v:<input #vi value="2"><br>
  <button (click)="load(hi.value, vi.value)">load</button>
  `,
  directives: [CORE_DIRECTIVES, Location]
})
class MyTable {
  vArr = [1, 2, 3];
  hArr = [1, 2, 3];
  @ViewChildren(Location) locations: QueryList;
  constructor(
    private loader: DynamicComponentLoader,
    ) {
  }

  load(h, v) {
    let elementRef = null;
    for(let i = 0; i < this.locations._results.length; i++) {
       if(this.locations._results[i].h == h && this.locations._results[i].v ==v) {
         elementRef = this.locations._results[i].elementRef;
       }
    }

    if(elementRef) {
      this.loader.loadNextToLocation(MyCmp, elementRef);
    }
  }
}

@Component({
  selector: 'my-app'
})
@View({
  template: `<my-table></my-table>`,
  directives: [MyTable]
})
export class App {}

http://plnkr.co/edit/dqfPCW3MBa9hM23EW3cS?p=preview Is that what you need?

Sign up to request clarification or add additional context in comments.

3 Comments

Your solution is doing what I need. It's a bit uncomely to create a lot of Directives just to have a reference. In my oppinion, it would be better if we could create string-anchors as references. But however, your solution is working, thx.
I think #xxx as a local variable name is not bindable. The only way to do that is by ElementRef, that is why using directive.
this.locations._results returns no results in angular 8 :(
0

Solution for Angular2 rc.0

HTML:

<div style="display: block">
  <table>
    <tr *ngFor="let v of arr; let i = index">
      <td *ngFor="let h of arr[i]; let j = index">
        <div location v="i" h="j"></div>
      </td>
    </tr>
  </table>
</div>

Location directive:

@Directive({
  selector: '[location]'
})
class Location {
  @Input() h: number;
  @Input() v: number;

  constructor(public viewContainerRef: ViewContainerRef) {
  }
}

Component

@Component({
  selector: 'example-cmp',
  directives: [CORE_DIRECTIVES, Location]
})
export class ExampleComponent implements AfterViewInit {
  public arr: Array<Array<number>> = [];
  public componentRef: ComponentRef<any>;

  @ViewChildren(Location) private locations: QueryList<Location>;

  constructor(private resolver: ComponentResolver) {
  }

  ngAfterViewInit() {
    this.loadTag(0,0,SomeViewComponent);
  }

  loadTag(x:number, y:number, component) {
    let viewContainerRef: ViewContainerRef = null;
    let locs = this.locations.toArray();
    for (let i = 0; i < locs.length; i++) {
      if (+locs[i].h === x && +locs[i].v === y) {
        viewContainerRef = locs[i].viewContainerRef;
      }
    }
    if (viewContainerRef != null) {
      var injector = ReflectiveInjector.fromResolvedProviders(ReflectiveInjector.resolve([
        provide(NeededAttribute, { useValue: 42 })]),
        this.componentRef.injector);

      this.resolver.resolveComponent(component).then((factory: ComponentFactory<any>) => {
        var compRef: ComponentRef<any> = viewContainerRef.createComponent(factory, -1, injector);
      });
    }
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.