1

I have learning AngularDart. Everything went well so for. But I am stuck with structural directives : I cannot figure out how to use the template input variables to implement my own structural directive.

I read many times this document: Structural Directives.

And, although the material below refers to AngularJS, I read this questions/documents:

It is said that from the micosyntax declaration "let v=value", Angular creates the template variable "let-v". However, I cannot use the name "let-v" in a template since "let-v" is not a valid name for a variable.

By the way, if you look at the explanation that is given here for the directive ngFor :

<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackByHeroId"
     [class.odd]="odd">
  ({{i}}) {{hero.name}}
</div>

<template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd"
          [ngForTrackBy]="trackByHeroId">
  <div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</template>

You see that, inside the template, the template input variable i is called i (not let-i):

<div [class.odd]="odd">({{i}}) {{hero.name}}</div>

I tried a LOT of things within the Dart code of my structural directive. But nothing works.

I read the source code for the directive NgFor. Something potentially interesting here :

  viewRef.setLocal('first', identical(i, 0));
  viewRef.setLocal('last', identical(i, len - 1));
  viewRef.setLocal('index', i);
  viewRef.setLocal('count', len);

However, I tried that with no success.

Here is the simple code I wrote:

File: lib/src/directive_my_dummy.dart

import 'package:angular/angular.dart';

@Directive(
    selector: '[myDummy]'
)

class MyDummyDirective implements OnInit {
  TemplateRef _templateRef;
  ViewContainerRef _viewContainer;

  MyDummyDirective(TemplateRef templateRef, ViewContainerRef viewContainer) {
    _templateRef = templateRef;
    _viewContainer = viewContainer;
  }

  @Input('let-d')
  List<int> d;

  void ngOnInit() {
    print("One instance of MyDummyDirective is instantiated.");
    EmbeddedViewRef vr = _viewContainer.createEmbeddedView(_templateRef);
    vr.setLocal('d', [1,2,3]);
    print(d.toString());
  }
}

File: lib/app_component.html

<div *myDummy="let d=data">
    This is a dummy test. {{d.toString()}}
</div>

<div *myDummy="let d=[1,2,3]">
    This is a dummy test. {{d.toString()}}
</div>

<div *myDummy="let d=getData()">
</div>

<div *myDummy="let d=[1,2,3]; let name='Toto'"></div>

The full code can be found here.

Can you show me a basic example that illustrates the use of the template input variables ?

Denis Beurive
  • 305
  • 2
  • 10

1 Answers1

0

First, there are two entities that we call "template":

  • The component template.
  • The (structural) directive template.

The term "input template variable" makes reference to the (structural) directive template.

I think that it would be better to use the appellation "input directive template variable".

I'll use the appellation "input directive template variable" instead of "input template variable".

The role of an input directive template variable is to configure a (structural) directive template.

Where does the value of an input directive template variable come from ?

The answer is: the value of an input directive template variable gets assigned within the directive instance. You cannot define the value of an input directive template variable directly within the component template. For example, the code <div *myDummy="let d=10"> below will NOT assign the value 10 to the variable d.

The value of the input directive template variable is assigned from within the directive instance. For example:

TemplateRef _templateRef;
ViewContainerRef _viewContainer;
// ...
_viewContainer.createEmbeddedView(_templateRef);
_viewContainer.get(0).setLocal('data', 'MyDummyDirective.data');

And you write, within the component template:

<div *myDummy="let d=data">

I give a simple example:

lib/src/directive_my_dummy.dart

@Directive(
    selector: '[myDummy]'
)
class MyDummyDirective implements OnInit {
  TemplateRef _templateRef;
  ViewContainerRef _viewContainer;

  @Input('myDummyVariable')
  String variable;

  MyDummyDirective(this._templateRef, this._viewContainer);

  void ngOnInit() {
    // WARNING: the property "variable" has no value assigned within the constructor.
    _viewContainer.createEmbeddedView(_templateRef);
    _viewContainer.get(0).setLocal('data', 'MyDummyDirective.data');
    print('MyDummyDirective.variable = ${variable}');
    _viewContainer.get(0).setLocal('var', 'This is ' + variable);
  }
}

lib/app_component.html

<div *myDummy="let d=data; variable:'value from the lib/app_component.html'; let v=var">
        <p>This is a dummy directive.</p>
        <ul>
            <li><b>d</b>=<code>{{d.toString()}}</code></li>
            <li><b>data</b>=<code>{{data}}</code> (makes reference to the instance of AppComponent)</li>
            <li><b>v</b>=<code>{{v}}</code></li>
        </ul>
</div>

lib/app_component.dart

import 'package:angular/angular.dart';
import 'package:myapp/src/directive_my_dummy.dart';

@Component(
    selector: 'app-component',
    templateUrl: 'app_component.html',
    directives: [MyDummyDirective],
)
class AppComponent {
    List<int> getData() => [100, 200, 300];
    String data = 'AppComponent.data';
}

The result:

This is a dummy directive.

<ul>
    <li>d=MyDummyDirective.data</li>
    <li>data=AppComponent.data (makes reference to the instance of AppComponent)</li>
    <li>v=This is value from the lib/app_component.html</li>
</ul>

EDIT:

As a picture often speaks better than words...

Denis Beurive
  • 305
  • 2
  • 10