【问题标题】:Controlling the evaluation of the value of an attribute控制属性值的评估
【发布时间】:2017-12-14 03:27:32
【问题描述】:

以下代码有效(以任何拼写错误为模——实际代码要复杂得多)。当您单击包含该指令的 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>

但是,如果有任何类似的变化,无论何时单击按钮,都会显示相同的时间,即呈现页面的时间。我一生都无法弄清楚如何在我喜欢的时间而不是在呈现页面时评估表达式。有什么建议吗?

【问题讨论】:

  • 那么,你想传递任意值,不限于 Angular 表达式支持什么?这似乎是个坏主意。现代 JavaScript 使用从模块中导入的类/变量,而不是全局变量,因此您将无法使用非全局定义的类传递任何内容。你想达到什么目的?
  • 如果您只是想传递一个角度表达式,只需将输入的类型更改为any,将其重命名为message,然后使用alert(this.message);plnkr.co/edit/3DTNuJAx4fUAH6Umy4nF?p=preview跨度>
  • @JBNizet -- 哈哈哈,我看到了你的困惑。由于我的示例显示了一个没有副作用的函数,因此您认为只要在警报之前立即调用它就可以随时调用它。你的 now() 函数被一遍又一遍地调用。见这里:plnkr.co/edit/UFQyg9lkhW5ry3eFnXe4 -- 我需要控制它何时执行,因为它有副作用。
  • 所以,基本上,你想要
  • 请编辑您的问题并详细说明。说明你真正想要达到的目标。

标签: angular


【解决方案1】:

有两种可能的方式来创建 args:

  • &lt;button [alertOnClick]="method(new Date())"&gt;Time&lt;/button&gt; 在渲染/更改检测期间仅创建一次 Date 对象。

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

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

另一种方法是编写纯自定义args 管道:&lt;button [alertOnClick]="method|args:[Date,new Date()]"&gt;Time&lt;/button&gt;。此管道创建包装函数,该函数可以在函数调用时创建参数。您可以控制哪些值应创建一次,哪些值应仅在函数调用期间创建。示例:

@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);
    };
  }
}

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

【讨论】:

    【解决方案2】:

    表达式评估

    我想更自然地调用它,像这样:
    &lt;button [alertOnClick]="String(new Date())"&gt;Time&lt;/button&gt;

    这在我看来像是后期表达式评估,可以用

    来实现
    <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 库纳入范围。


    方法评价

    “Angular 方式”是传递方法名称以供将来评估。
    这在很多地方都有显示,所以我很惊讶你在你的示例 plunker 中没有得到它。 (参考: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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 1970-01-01
      • 2012-02-25
      • 2019-07-19
      • 2016-08-29
      • 1970-01-01
      相关资源
      最近更新 更多