Aurelia技术问询:dynamicExpression绑定行为后如何应用值转换器?
Great question! I’ve run into this exact scenario with Aurelia’s dynamicExpression binding behavior before—value converters don’t play nicely when tacked on directly like you tried, and here’s why and how to fix it:
Why Your Original Syntax Fails
Aurelia processes binding behaviors before value converters in the binding pipeline. When you write value.bind="model & dynamicExpression:field.expression | formatNumber:'$###,###.00'", the dynamicExpression behavior takes over resolving the binding, and the subsequent | formatNumber pipe never gets applied to the result of that dynamic resolution.
Fixes to Try
Option 1: Embed the Value Converter in the Dynamic Expression
If you control the field.expression value, the simplest fix is to include the value converter directly in the expression string that dynamicExpression will evaluate. For example:
// Update your field's expression to include the converter logic field.expression = "model | formatNumber:'$###,###.00'";
Then simplify your binding to:
<input type="text" value.bind="& dynamicExpression:field.expression" />
This works because dynamicExpression parses and executes the entire expression, including the value converter pipeline.
Option 2: Wrap the Result in a Computed Property
If you can’t modify the original field.expression, create a computed property that first resolves the dynamic expression result, then applies the value converter. Here’s how:
import { computedFrom, inject } from 'aurelia-framework'; import { ExpressionParser } from 'aurelia-binding'; import { FormatNumberValueConverter } from './path-to-your-converter'; @inject(ExpressionParser, FormatNumberValueConverter) export class YourViewModel { constructor(expressionParser, formatNumberConverter) { this.expressionParser = expressionParser; this.formatNumberConverter = formatNumberConverter; } @computedFrom('model', 'field.expression') get formattedDynamicValue() { // Parse and evaluate the dynamic expression const ast = this.expressionParser.parse(this.field.expression); const result = ast.evaluate({ model: this.model }); // Apply the value converter to the result return this.formatNumberConverter.toView(result, '$###,###.00'); } }
Then bind to the computed property in your view:
<input type="text" value.bind="formattedDynamicValue" />
Option 3: Build a Reusable Custom Binding Behavior
For a cleaner, more reusable solution, create a custom binding behavior that combines dynamic expression resolution with value conversion. Here’s a basic implementation:
import { inject } from 'aurelia-framework'; import { ExpressionParser } from 'aurelia-binding'; @inject() export class DynamicWithConverterBindingBehavior { bind(binding, source, expressionStr, converterName, ...converterArgs) { // Evaluate the dynamic expression const parser = source.container.get(ExpressionParser); const ast = parser.parse(expressionStr); const dynamicResult = ast.evaluate(source); // Get the value converter and apply it const converter = source.container.get(`${converterName}ValueConverter`); const convertedValue = converter.toView(dynamicResult, ...converterArgs); // Update the binding target with the converted value binding.updateTarget(convertedValue); } }
Then use it in your view like this:
<input type="text" value.bind="model & dynamicWithConverter:field.expression:'formatNumber':'$###,###.00'" />
This keeps your view markup concise and lets you reuse the logic across multiple bindings.
内容的提问来源于stack exchange,提问作者John Parker

