1

I have a working PLNKR written with angular version2.
It's a simple timer where the component has a reference to the directive which contains the logic :

@Component({
  selector: 'my-app',
   template: `
    <div>
     <div class="timer" *simpleTimer="#timer=timerApi">       <-- see here
     <div class="time">{{ timer.getTime() }}</div>
      ...
    </div>
  `

and in the directive itself - it sets the value for timerApi via :

  view.setLocal('timerApi', api);

The directive doesn't use exportAs :

@Directive({
  selector: '[simpleTimer]'
})

I want to convert it to Angular 4. but some features doesn't work.

For example , the following code : *simpleTimer="#timer=timerApi" yields :

Parser Error: Unexpected token # at column 1 in [#timer=timerApi]

Also this method view.setLocal doesn't exist anymore.

Question:

How can I reference the directive from the component ? ( so i'll have all its methods)

I've added the exportAs to the directive and it still doesn't work.

The problematic Plunker converted to ver 4.2.3

Royi Namir
  • 144,742
  • 138
  • 468
  • 792

1 Answers1

3

There is second parameter for vcRef.createEmbeddedView which expects the context:

let api = {
  toggle: () => this.toggle(),
  reset: () => this.reset(),
  getTime: () => this.getTime()
};
let view = this.viewContainer.createEmbeddedView(this.templateRef, { timerApi: api });

Usage:

*simpleTimer="let timer = timerApi"

Fixed Plunker v4.2.3

Another option

let view = this.viewContainer.createEmbeddedView(this.templateRef, { $implicit: api });

and template

*simpleTimer="let timer"

Plunker

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • What if simpletimer had also an @input? How woild that fit in with the assignment above? – Royi Namir Jun 18 '17 at 16:35
  • 1
    `*simpleTimer="inputValue, yurzui: inputValue2, let timer=timerApi;"` means that your directive has `@Input` `simpleTimer` and we pass `inputValue` to it, also has `@Input simpleTimerYurzui` and we pass `inputValue2` to it – yurzui Jun 18 '17 at 16:41
  • 1
    You can notice each subsequent @Input gets its name from the following pattern `simplerTimer + (Y)First character in uppercase + rest characters(urzui)` – yurzui Jun 18 '17 at 16:44
  • Yuruzi I must ask you , where did you learn about the @input postfix regarding directive's base name ? I don't see it in the docs – Royi Namir Jun 18 '17 at 19:15
  • https://stackoverflow.com/questions/38752744/angular2-how-is-ngfor-expanded But it has changed a bit – yurzui Jun 18 '17 at 19:19
  • 1
    So my answer is deep debugging – yurzui Jun 18 '17 at 19:20
  • @yuruzi - I've just noticed : the original OP of the plunker used _structural directive_ so he can create the referenced view and add a context to it. He set the context ( which is used via `exportAs`) via `createEmbeddedView` , but if I make it a non(!) structural directive - then I don't have this overload : `this.viewContainer.createEmbeddedView(this.templateRef, { timerApi: api })`. so how can I access the object's methods inside a non-structural directive ? https://plnkr.co/edit/TVOeZYYsfG1BQ4dKi8Ug?p=preview – Royi Namir Jun 19 '17 at 09:53
  • This `*simpleTimer=` vs `[simpleTimer]=` vs `simpleTimer=` is really confusing – Royi Namir Jun 19 '17 at 10:03
  • `*simpleTimer=` is microsyntax, `[simpleTimer]` is property binding with expression, `simpleTimer="{{1+3}}"` is property binding with interpolation (@Input is always string), `simpleTimer="text"` is one-time binding – yurzui Jun 19 '17 at 10:06
  • wouldn't I be able to reference `api` inside the template `
    {{ api.getTime() }}
    ` without using the context?
    – Max Koretskyi Jun 20 '17 at 04:26