使用 ngFor 处理自定义指令 - Angular2

handle custom directive with ngFor - Angular2

昨天我试图解决其中一个 SO 问题,但在我的解决方案中遇到了问题。

在组件的模板中,我正在使用 ngFor 指令,其中我正在使用我的自定义 popover 指令。 仅通过指令,我想显示每个 ngFor 对象的隐藏内容。

一旦你检查 http://plnkr.co/edit/X4U8ofJ5rgmE1YQ7fTAG?p=preview 你就会意识到我的问题。

在指令中使用的 mouseenter 事件我想显示适当的 ngFor 对象的内容。

directive.ts

import {Input,Component,Output,EventEmitter,Input,Directive,Hostbinding} from 'angular2/core';
import {Component, Input, OnInit, OnChanges, ChangeDetectionStrategy, ElementRef} from 'angular2/core';
@Directive({
    selector: '.tower-details',
    host:{
      '(mouseenter)':'show($event)',
      '(mouseout)':'hide()'
    }
})
export class popover{
   @Input() value: string;
   @Output() valueChange=new EventEmitter();


   ngOnChanges(...args:any[]){
     //console.log(args[0].value);
   }
   show(val)
   {
     console.log(val.target);
     this.valueChange.emit(true);
   }
   hide()
   {
     console.log('hide');
     this.valueChange.emit(false);
   }

}

app.ts

 template: `
    <div  *ngFor="#p of popovers;#index=index">
            <div class="tower-details"  [(value)]="show" style="display: block;border:1px solid green;background-color:orange" >
             Hover Me ! {{index}}
                <div *ngIf="show">
                <div class="popover top" style="display: block;border:1px solid green">
                    <h3 class="popover-title">{{p.title}}</h3>
                    <div class="popover-content">pop up content</div>
                </div>
                </div>
            </div>
            <br>
            <br>
     </div>
  `

我猜你想要类似的东西

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div  *ngFor="let p of popovers;let index=index">
            <div class="tower-details"  [(value)]="show[p.title]" style="display: block;border:1px solid green;background-color:orange" >
             Hover Me ! {{index}}
                <div *ngIf="show[p.title]">
                <div class="popover top" style="display: block;border:1px solid green">
                    <h3 class="popover-title">{{p.title}}</h3>
                    <div class="popover-content">pop up content</div>
                </div>
                </div>
            </div>
            <br>
            <br>
     </div>
  `,
    directives: [popover]


})
export class App {

  popovers=[{"title":"popover1"},{"title":"popover2"},{"name":"title"}]
  show={'popover1': false, 'popover2': false, 'title': false};
}

每个项目的状态需要单独存储。如果您对每个使用相同的值,则它们 show/hide 同步。

因为您在 [(value)]="show" 上使用双向绑定,每个项目的值将传播到 App 并返回到每个 tower-details.

Plunker example

更新

您可以导出如下指令:

@Directive({
    selector: '.tower-details',
    host:{
      '(mouseenter)':'show($event)',
      '(mouseout)':'hide()'
    },
    exportAs: 'tower'
})
export class popover{

然后你可以创建一个模板变量来引用指令中的值

        <div class="tower-details" #tower="tower" style="display: block;border:1px solid green;background-color:orange" >
         Hover Me ! {{index}} - {{tower.value}}
            <div *ngIf="tower.value">

您还需要在指令中设置 value 而不是仅仅发出一个事件。事实上,不再需要发出事件,除非您想通过其他方式进行绑定。

   show(val)
   {
     console.log(val.target);
     this.value = true;
     this.valueChange.emit(true);
   }
   hide()
   {
     console.log('hide');
     this.value = false;
     this.valueChange.emit(false);
   }

Plunker example

其实你使用的show变量是全局的。你应该使用类似的东西:

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div *ngFor="#p of popovers;#index=index">
        <div class="tower-details" (valueChange)="show[index]=$event" style="display: block;border:1px solid green;background-color:orange" >
         Hover Me ! {{index}}
            <div *ngIf="show[index]">
            <div class="popover top" style="display: block;border:1px solid green">
                <h3 class="popover-title">{{p.title}}</h3>
                <div class="popover-content">pop up content</div>
            </div>
            </div>
        </div>
        <br>
        <br>
  </div>
  {{show | json }}
`,
directives: [popover]
})
export class App {
  popovers=[{"title":"popover1"},{"title":"popover2"}, {"name":"title"}]
  show=[false,false,false];
}

看到这个 plunkr:http://plnkr.co/edit/pIgH4OdMIf7rj2NOw9b6?p=preview

编辑

再想一想,你可以直接利用applied指令的状态来避免使用show数组。

@Directive({
  selector: '.tower-details',
  host:{
    '(mouseenter)':'show($event)',
    '(mouseout)':'hide()'
  },
  exportAs: 'popover'
})
export class popover{
  shoudShow: false;

  show(val) {
    this.shoudShow = true;
  }

  hide() {
    this.shoudShow = false;
  }
}

在组件中是这样的:

@Component({
  selector: 'my-app',
  template: `
    <div  *ngFor="#p of popovers;#index=index">
        <div class="tower-details" #dir="popover" style="display: block;border:1px solid green;background-color:orange" >
         Hover Me ! {{index}}
            <div *ngIf="dir.shoudShow">
            <div class="popover top" style="display: block;border:1px solid green">
                <h3 class="popover-title">{{p.title}}</h3>
                <div class="popover-content">pop up content</div>
            </div>
            </div>
        </div>
        <br>
        <br>
   </div>
  `,
  directives: [popover]
})
export class App {
  popovers=[{"title":"popover1"},{"title":"popover2"}, {"name":"title"}]
}

看到这个新的 plunkr:http://plnkr.co/edit/4Ewx15fYgm8AgejWZmXl?p=preview