I'm running into an issue with Aurelia and am assuming that there is something I am missing.
I'm trying to create a 'generic' grid. I have removed a lot of the html to keep the example short, but the basic idea is this:
<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>
I want to be able to use the ValueConverters to help properly display certain types of column data. The above is currently working, but I want to have more value converters for other columns and the conditions will get unwieldy. My experience with Aurelia so far is that it offers fairly elegant solutions, but I have been unable to figure this one out as of yet.
I tried adding another property to the columnDefinition class like this formatter:string = undefined
and then tried to create the spans like the following:
<span if.bind="columnDefinition.formatter">${row[columnDefinition.propertyName] | columnDefinition.formatter}</span>
<span if.bind="!columnDefinition.formatter">${row[columnDefinition.propertyName]}</span>
but the parser threw an error on the '.'.
Is there any way to achieve this? What is the 'aurelia-way' of dealing with this type of a problem.
Thanks in advance for any help that could be offered.
I ended up taking a similar approach to the one suggested by @Slyvain with a bit of a different twist:
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;
}
}
}
Original code can be found here .
Hope this helps.
I followed @peinearydevelopment and went one step further again to create a fully dynamic value converter.
Usage is as follows ${myValue | dynamic:converterKey:converterArgs}
${myValue | dynamic:converterKey:converterArgs}
or simply ${myValue | dynamic:converterKey}
${myValue | dynamic:converterKey}
if no additional arguments are required. The converterKey
is used to request a value converter that should be registered with the container. converterArgs
is the array of arguments that you'd pass to the toView
& fromView
functions.
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;
}
}
Have you considered using a single <span>
with a single general purpose converter that takes the column definition as a parameter and that delegates to the right converter? I think that would make the component markup simpler.
<span>${row[columnDefinition.propertyName] | formatCell:columnDefinition}</span>
And inside the formatter:
export class FormatCell {
toView(value, columnDefinition){
if(columnDefinition.isCurrency)
return new CurrencyConverter().toView(value);
if(columnDefinition.isDate)
return new DateConverter().toView(value);
return value;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.