0

I have old code that looks something like this:

<as-split unit="pixel" #mainViewSplit class="custom-gutter" direction="horizontal" 
   gutterSize="2">
  <as-split-area #propertiesContentPanel [size]="(propertiesWidth | async)" 
    [minSize]="350" maxSize="{{propertiesMinimized? minPanelWidth : '*'}}" 
    *ngIf="(propertiesSplitVisible | async)" [order]="splitOrder.properties">
    <app-properties-content-panel></app-properties-content-panel>
  </as-split-area>
  <as-split-area #someContentPanel [size]="(someWidth | async)" [minSize]="350"
    maxSize="{{someMinimized? minPanelWidth : '*'}}" *ngIf="(someSplitVisible | async)"
    [order]="splitOrder.some">
    <app-some-content-panel></app-some-content-some>
  </as-split-area>
</as-split>

In the above html there's as-split-component that contains 2 as-split-area directives (https://angular-split.github.io/documentation). Also in the html above there's 2 template reference variables used to reference the 2 as-split-area directives. They are

#propertiesContentPanel

and

#someContentPanel

In the class (.ts) files they are referenced like this:

@ViewChild('propertiesContentPanel') propertiesContentPanelSplit: SplitAreaDirective;
@ViewChild('someContentPanel') someContentPanel: SplitAreaDirective;

In reality there's a lot more of these as-split-areas but for simplicity only 2 are shown. I want to add all the as-split-area directives to the as-split component with ngFor. So the code would look like this:

  <as-split unit="pixel" #mainViewSplit class="custom-gutter" direction="horizontal" gutterSize="2">
    <ng-container *ngFor="let splitItem of splitData">
      <as-split-area id="splitItem.id" *ngIf="(splitItem.isVisible | async) 
        [size]="(splitItem.width | async)" [minSize]="splitItem.minSize" 
        maxSize="{{splitItem.isMinimized? minPanelWidth : '*'}}" [order]="splitItem.order">
         <ng-container *ngTemplateOutlet="splitItem.template"></ng-container>
      </as-split-area>
    </ng-container>
  </as-split>

Above all the templates and related .ts code used in

<ng-container *ngTemplateOutlet="splitItem.template"></ng-container>

are omitted for simplicity.

Everything else works but I cannot now reference the as-split-area directives in the code anymore because template reference variables are missing. How can I bind to as-split-area directives in the refactored ngFor-version so that I can still reference them in the class file with the 2 ViewChild I have (propertiesContentPanel and someContentPanel)?

I would like to do something like this:

<as-split-area #="splitItem.referenceVariable"

But this doesn't work. I have also omitted type of splitItem also from the question to avoid confusion.

5
  • That doesn't look like valid syntax... the # creates a variable which you can then access via ViewChild(). You could use a directive (or input) to pass the template to the component instead. Commented Oct 25, 2022 at 12:32
  • yes. it is not valid syntax. hence the question. Commented Oct 25, 2022 at 13:08
  • all i want to know is how to make the new code like the old code. Commented Oct 25, 2022 at 13:18
  • 1
    Do you need to know which reference is which (propertiesContentPanel vs someContentPanel)? OR as long as you can get reference to them, you are satisficed? Commented Oct 25, 2022 at 13:50
  • I need to know which is which Commented Oct 25, 2022 at 13:52

1 Answer 1

1

You can't dynamically define template reference variable. The feature was requested, but it was closed:

https://github.com/angular/angular/issues/33233


But you can work around this by querying all of the SplitArea directives, access its order property and add your own logic. Please note that you need to map each order to each panel. The idea is to use order as the id since we can't make any change to SplitArea directive. This way, you can give each SplitArea a separate treatment according to the order.

If you, instead, want to apply the treatment for each type (SomeContent vs. PropertiesContent vs. etcContent), please check out the Bonus section below.

example.component.ts

@Component({
 ...
})
export class ExampleComponent implements AfterViewInit {
  
  @ViewChildren(SplitAreaDirective)
  splitAreas!: QueryList<SplitAreaDirective>;

  public ngAfterViewInit() {
    
    const propertiesContentPanel = this.splitAreas.find(s => s.order === 0);

    if (propertiesContentPanel) {
       // do your logic here.
    }
  }
}

example.component.html

<as-split>
  <ng-container *ngFor="let splitItem of splitData">
    <as-split-area id="splitItem.id" 
         *ngIf="(splitItem.isVisible | async)"
         [order]="splitItem.order">
      <ng-container *ngTemplateOutlet="splitItem.template"></ng-container>
    </as-split-area>
  </ng-container>
</as-split>

Bonus:

You can also create a custom directive that accepts a string literal type, append it to the SplitArea directive, query it with @ViewChildren, then do your logic according to the string literal type.

SplitData type also need to include a new property called templateType and is of SplitAreaType type.

myTemplateRef.directive.ts

export type SplitAreaType = 'SomeContent' | 'PropertiesContent'; 

@Directive({
  selector: '[appMyTemplateRef]'
})
export class MyTemplateRefDirective {

  public get SplitArea() {
    return this._splitAreaRef;
  }

  constructor(private _splitAreaRef:SplitAreaDirective) {}
  
  @Input()
  public templateType: SplitAreaType = 'SomeContent';
}

example1.component.html

<as-split>
  <ng-container *ngFor="let splitItem of splitData">
    <as-split-area appMyTemplateRef [templateType]="splitItem.templateType">
      <ng-container *ngTemplateOutlet="splitItem.template"></ng-container>
    </as-split-area>
  </ng-container>
</as-split>

example1.component.ts

@Component({
 ...
})
export class Example1Component implements AfterViewInit {
  
  @ViewChildren(MyTemplateRefDirective)
  myTemplateRefs!: QueryList<MyTemplateRefDirective>;

  public ngAfterViewInit() {
    
    this.myTemplateRefs.forEach(t => {

      if(t.templateType === 'SomeContent') {
         // do something with the SplitArea here.
         t.splitArea.gutterSize = 200;
      } else {
     
      }

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

3 Comments

Not sure what this has to do with my question. I'm not trying to pass template into component
I cannot edit as-split-area (angular-split.github.io)
also it's a directive, not a component

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.