控制属性值的评估

时间:2017-12-14 03:27:33

标签: angular

以下代码有效(以任何拼写错误为模 - 真正的代码要复杂得多)。单击包含此指令的DOM元素时,表达式的值将显示在警报中。

@Directive({selector: '[alertOnClick]'})
export class AlertOnClick implements OnDestroy {
  @Input('alertOnClick') clickFunction: (() => string);

  @HostListener('click')
  onClick() {
    alert(this.clickFunction());
  }
}

问题是,必须像这样调用:

<button [alertOnClick]="() => String(new Date())">Time</button>

编辑:似乎Angular解析器不支持匿名函数。必须通过在控制器上命名函数来调用它。

我想更自然地调用它,就像这样:

<button [alertOnClick]="String(new Date())">Time</button>

但是如果有任何类似的变化,只要点击按钮,就会显示相同的时间,即呈现页面的时间。我不能为我的生活弄清楚如何在我喜欢的时候评估表达式,而不是在渲染页面时。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

创建args有两种可能的方法:

  • <button [alertOnClick]="method(new Date())">Time</button>仅在渲染/更改检测期间创建Date个对象。

  • <button [alertOnClick]="method(createDate())">Time</button> - 在每次更改检测+实际函数调用时多次创建Date个对象。

可以使用工厂函数/类型构造函数以受控方式创建args:<button [alertOnClick]="method(createDate/Date)">Time</button>method内部将调用createDate()new date()。可用的解决方案,但不方便。

另一种方法是编写纯自定义args管道:<button [alertOnClick]="method|args:[Date,new Date()]">Time</button>。这个管道创建了包装函数,可以在函数调用上创建参数。您可以控制应该创建一次哪些值以及应该仅在函数调用期间创建哪些值。例如:

@Pipe({name: 'args', pure: true})
export class ArgsPipe implements PipeTransform {
  transform(method: Function, parameters: any[]): Function {
    return ()=> {
       const args = parameters.forEach(arg => {
            if(typeof arg === 'function') {
                return arg();
            }
            return arg;
       });
       //todo: figure out how to get correct this
       method.apply(this, args);
    };
  }
}

可能你还需要一个管道来禁用对函数参数的评估,它会将它们转换为() => functionArgument<button [alertOnClick]="method|args:[someCallback|func,new Date()]">Time</button> - 在这种情况下someCallback函数将被传递给{{1没有调用。

答案 1 :(得分:1)

表达评估

  

我想更自然地调用它,如下所示:
  <button [alertOnClick]="String(new Date())">Time</button>

这对我来说就像晚期表达评估,可以用

实现
<p alertOnClick="String(new Date())">Current time</p>

@Directive({selector: '[alertOnClick]'})
export class AlertOnClick {
  @Input('alertOnClick') message: String;

  @HostListener('click')
  onClick() {
    alert(eval(this.message));
  }
}

在编译时发生的事情是alertOnClick属性被赋予表达式的字符串版本,然后在运行时Javascript eval(ref MDN web docs)正在评估字符串。

当然,这可能会因您的副作用而失败。代码因为绑定。即eval只能 ,因为StringDate内置于该语言中。
了解你的副作用是多么有趣。

您还可以调用自己定义的全局函数

const evalMe = () => { return String(new Date()) }

<p alertOnClick="evalMe()">Current time</p>

@Directive({selector: '[alertOnClick]'})
export class AlertOnClick {
  @Input('alertOnClick') message: String;

  @HostListener('click')
  onClick() {
    alert(eval(this.message));
  }
}

这会带来可能导入的普通javascript库。


方法评估

&#39; Angular方式&#39;是为了将来的评估传递一个方法名称 这在很多地方展示过,所以我很惊讶你没有在你的示例选手中找到它。 (参考:Angular2 passing a function to a directive via attribute

<p [alertOnClick]="evalMethod">Current time</p>

export class App {
  ...    
  evalMethod() {
    console.log("I am being called!")
    return new Date();
  }


@Directive({selector: '[alertOnClick]'})
export class AlertOnClick {
  @Input('alertOnClick') messageFn: Function;

  @HostListener('click')
  onClick() {
    alert(this.messageFn());
  }
}

它的工作原理取决于表达式的来源,以及是否可以在组件方法中完成任何所需的绑定 至少,您有更多的绑定空间,因为您已经有效地从模板中删除了表达式。

这是工作Plunker