【问题标题】:Aurelia Dynamically Bound Value ConverterAurelia 动态绑定值转换器
【发布时间】:2016-12-18 07:34:12
【问题描述】:

我遇到了 Aurelia 的问题,并假设我缺少某些东西。

我正在尝试创建一个“通用”网格。我删除了很多 html 以保持示例简短,但基本思想是这样的:

<template>
<require from="../value-converters"></require>
  <table show.bind="rows.length">
    <thead>
      <tr>
        <th repeat.for="columnDefinition of columnDefinitions">
          ${columnDefinition.displayName}
        </th>
      </tr>
    </thead>
    <tbody>
      <tr repeat.for="row of rows">
        <td repeat.for="columnDefinition of columnDefinitions">
          <span if.bind="columnDefinition.isCurrency">${row[columnDefinition.propertyName] | numeralFormatter}</span>
          <span if.bind="columnDefinition.isDate">${row[columnDefinition.propertyName] | dateFormatter}</span>
          <span if.bind="!columnDefinition.isCurrency && !columnDefinition.isDate &&">${row[columnDefinition.propertyName]}</span>
        </td>
      </tr>
    </tbody>
  </table>
</template>

我希望能够使用 ValueConverters 来帮助正确显示某些类型的列数据。以上目前正在工作,但我希望为其他列提供更多价值转换器,并且条件会变得笨拙。到目前为止,我对 Aurelia 的体验是它提供了相当优雅的解决方案,但我至今无法弄清楚这一点。

我尝试向 columnDefinition 类添加另一个属性,例如 formatter:string = undefined,然后尝试创建如下跨度:

<span if.bind="columnDefinition.formatter">${row[columnDefinition.propertyName] | columnDefinition.formatter}</span>
<span if.bind="!columnDefinition.formatter">${row[columnDefinition.propertyName]}</span>

但是解析器在 '.' 上抛出了一个错误。

有什么方法可以实现吗?处理此类问题的“aurelia 方式”是什么。

提前感谢您提供的任何帮助。

【问题讨论】:

    标签: aurelia


    【解决方案1】:

    我最终采用了与@Slyvain 建议的方法类似的方法,但略有不同:

    import {DateValueConverter} from './date';
    import {NumberValueConverter} from './number';
    import {autoinject} from 'aurelia-framework';
    
    @autoinject()
    export class MetaValueConverter {
        constructor(private date: DateValueConverter,
                    private number: NumberValueConverter) {
        }
    
        public toView(value, valueConverter, format) {
            /* JUSTIFICATION: https://stackoverflow.com/questions/38898440/aurelia-dynamically-bound-value-converter#comment-65199423 */
            /* tslint:disable:no-string-literal */
            if (this[valueConverter] && this[valueConverter].toView) {
                return this[valueConverter].toView(value, format);
            } else {
                return value;
            }
        }
    
        public fromView(val, valueConverter, format) {
            if (this[valueConverter] && this[valueConverter].fromView) {
                return this[valueConverter].fromView(value, format);
            } else {
                return value;
            }
        }
    }
    

    原码可以在here找到。

    希望这会有所帮助。

    【讨论】:

    • 这看起来棒极了!非常感谢分享!
    【解决方案2】:

    我跟着@peinearydevelopment又更进一步,创建了一个全动态的值转换器。

    用法如下${myValue | dynamic:converterKey:converterArgs} 或简单${myValue | dynamic:converterKey} 如果不需要额外的参数。 converterKey 用于请求应在容器中注册的值转换器。 converterArgs 是您将传递给 toViewfromView 函数的参数数组。

    import { autoinject, Container } from 'aurelia-dependency-injection';
    
    export type ValueConverterKey = new (...args: any[]) => object;
    
    type ValueConverterFunc = (...args: any[]) => any;
    
    interface ValueConverter {
      toView?: ValueConverterFunc;
      fromView?: ValueConverterFunc;
    }
    
    @autoinject()
    export class DynamicValueConverter {
        constructor(
          private container: Container,
        ) { }
    
        public toView(value: any, converterKey?: ValueConverterKey, ...converterArgs: any[]) {
          if (!converterKey) {
            return value;
          }
    
          return this.convertValueIfPossible(value, converterKey, converterArgs, 'toView');
        }
    
        public fromView(value: any, converterKey?: ValueConverterKey, ...converterArgs: any[]) {
          if (!converterKey) {
            return value;
          }
    
          return this.convertValueIfPossible(value, converterKey, converterArgs, 'fromView');
        }
    
        private convertValueIfPossible(value: any, converterKey: ValueConverterKey, converterArgs: any[], func: keyof ValueConverter) {
          let converter = this.container.get(converterKey);
    
          if (converter) {
            let converterFunc = converter[func];
    
            if (converterFunc) {
              return converterFunc.call(converter, value, ...converterArgs);
            }
          }
    
          return value;
        }
    }
    

    【讨论】:

    • FWIW 我们有一个用例,我们创建了一个包,其中包含一个显示值的自定义元素,但是我们希望为包的用户提供根据需要转换显示值的能力。跨度>
    【解决方案3】:

    您是否考虑过将单个 &lt;span&gt; 与单个通用转换器一起使用,该转换器将列定义作为参数并委托给正确的转换器?我认为这会使组件标记更简单。

    <span>${row[columnDefinition.propertyName] | formatCell:columnDefinition}</span>
    

    在格式化程序内部:

    export class FormatCell {
      toView(value, columnDefinition){
        if(columnDefinition.isCurrency)
            return new CurrencyConverter().toView(value);
    
        if(columnDefinition.isDate)
            return new DateConverter().toView(value);
    
        return value;
      }
    }
    

    【讨论】:

    • 我绝对可以这样做,但是如果我想出另一个类型转换器,比如我有一个枚举并且我想将它转换为文本,我不能只创建转换器和 columnDefinition 和让它正常工作,我必须在这里添加另一个 if 语句。它似乎不适合可扩展性。
    • 1 - 每次新的 if 语句或每次标记中的新行都非常接近。 2 - 你真的不需要每次都使用新的 if 语句。这只是为了表明您可以外部化转换器选择。您可以有一个约定type + "Converter" 并动态创建转换器。或者,您可以在应用程序启动时向 DI 容器注册命名转换器,并在此转换器中向容器询问该名称的转换器。如果找到了就使用它,否则返回value
    • @peinearydevelopment 您是否找到了不同的解决方案,或者这是最好的方法?我现在正在尝试做同样的事情,从我目前的角度来看,Sylvain 的解决方案似乎是最好的方法,但我对 Aurelia 的经验不如其他开发人员。
    • @LStarky。我在下面发布了我的方法,它类似于 Sylvain 建议的方法,但我认为更具可扩展性。我仍然很想听听其他人的不同方法。
    猜你喜欢
    • 2018-07-15
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多