Reputation: 12838
I'm trying to bind an async value to one of my Aurelia templates, and obviously all I get is [object Promise]
in return.
I found this article http://www.sobell.net/aurelia-async-bindings/ which excellently explains how to solve this problem using a binding behavior which looks like this:
// http://www.sobell.net/aurelia-async-bindings/
export class asyncBindingBehavior {
bind (binding, source) {
binding.originalUpdateTarget = binding.updateTarget;
binding.updateTarget = a => {
if (typeof a.then === 'function') {
binding.originalUpdateTarget('...');
a.then(d => {
binding.originalUpdateTarget(d);
});
}
else {
binding.originalUpdateTarget(a);
}
};
}
unbind (binding) {
binding.updateTarget = binding.originalUpdateTarget;
binding.originalUpdateTarget = null;
}
}
This works perfectly when the promise resolves with a string or other non-object-like variable.
But what if my promise resolves with an object? How would I go about accessing the property I need inside that object?
Because if I do: ${object.property & async}
inside my template then it will fail as object.property
isn't a promise - only object
is.
I added a bit of a hack that allows me to specify a property as an argument to async
, like this: ${object & async:'property'}
and updated my binding behavior as such:
// http://www.sobell.net/aurelia-async-bindings/
export class asyncBindingBehavior {
bind (binding, source, property) {
binding.originalUpdateTarget = binding.updateTarget;
binding.updateTarget = a => {
if (typeof a.then === 'function') {
binding.originalUpdateTarget('...');
a.then(d => {
if (property) {
binding.originalUpdateTarget(d[property]);
}
else {
binding.originalUpdateTarget(d);
}
});
}
else {
binding.originalUpdateTarget(a);
}
};
}
unbind (binding) {
binding.updateTarget = binding.originalUpdateTarget;
binding.originalUpdateTarget = null;
}
}
But this feels very much like a hack to me, and it also won't allow me to access any deeper properties like object.parent.child
.
I also found this (rather old) issue on GitHub: https://github.com/aurelia/templating/issues/81 where they use a getValue
method. I've never heard of this method and trying to use it fails so I'm not sure how that works at all...
Any ideas?
Upvotes: 3
Views: 1703
Reputation: 19288
You could sidestep your conundrum by specifying a function as the third parameter, giving the flexibility to do much more than simple property extraction.
You could write something like this :
export class asyncBindingBehavior {
bind (binding, source, transformer="default") {
binding.originalUpdateTarget = binding.updateTarget;
binding.updateTarget = a => {
if (typeof a.then === 'function') {
binding.originalUpdateTarget('...');
a.then(d => binding.originalUpdateTarget(transformFunctions[transformer](d)));
} else {
binding.originalUpdateTarget(a);
}
};
}
unbind (binding) {
binding.updateTarget = binding.originalUpdateTarget;
binding.originalUpdateTarget = null;
}
}
The transformFunctions
lookup would be necessary(?) due to the way Aurelia bindings are specified as HTML-ebbedded or template directives (ie all params must be String). Unless Aurelia offers a better way better way to "pass a function" (Value Converters?), you would write something like this :
export var transformFunctions = {
default: (d) => d,
transform1: (d) => d.someProperty,
transform2: (d) => d.someProperty.someOtherProperty,
transform3: someFunction,
transform4: someOtherFunction.bind(null, someData);
}
Of course, you would give the functions better names.
Upvotes: 4