Reputation: 13194
I created a custom element in Aurelia
and I also have the valueChanged
, however I need to do a certain action only when the value
is changed outside of the custom element. Since the signature is valueChanged(newValue, oldValue)
, how would I know when the value gets changed from the ViewModel
and not from the custom element itself? Is that doable somehow with an observer
or observable
?
I actually got kind of a working sample, I saw that there's also an __array_observer__
property when the value
is changed from the ViewModel
, and it works but it's probably not ideal. So I got this piece of code which kinda works
valueChanged(newValue, oldValue) {
if (newValue !== oldValue && newValue.__array_observer__) {
// value got changed outside of this custom element
}
}
This is probably not ideal though, or is it? Any other suggestion in knowing where the value
got changed outside of the custom element?
EDIT
As much as possible, I'm looking for a solution that will still have access to the custom element. Even if I want to get triggered by an external value change call, I still need to call an internal function of the same custom element.
EDIT #2
To give a little more description of my issue, I need to know when the value
got changed from the outside because this will trigger an action that will re-affect the value
. Without knowing if the change was from the outside of the custom element, I fall in a recursive call with no way to stop it. What I'm looking for is similar to what used to be the caller
and the callee
but this was removed with ES5 and Strict Mode, however this would have been very useful.
Still looking for an answer :(
Upvotes: 2
Views: 1239
Reputation: 1574
As discussed in gitter, you can use a suppress flag
value: number;
suppressValueChanged: boolean;
valueChanged(){
if(this.suppressValueChanged){
this.suppressValueChanged = false;
this.logger.debug("the value has been changed from inside the element");
return;
}
this.logger.debug("the value has been changed from outside the element");
// here comes the code to run when the value is changed outside
}
internalSetValue(value: number){
this.suppressValueChanged = true;
this.value = value;
}
The reason I reset the flag in the changed
method is that depending on the circumstances valueChanged
can be called by Aurelia asynchronously so you cannot just do the following
this.suppressValueChanged = true;
this.value = 123;
this.suppressValueChanged = false;
Sometimes, using a task will work
this.taskQueue.queueTask(() => {
this.suppressValueChanged = true;
this.value = 123;
this.suppressValueChanged = false;
});
It really depends where exactly in Aurelia code you are changing the value. I've found that the first option gives the most consistent result.
Upvotes: 1
Reputation: 11990
You could use a CustomBindingBehavior to intercept the updateTarget
event. For instance:
export class InterceptBindingBehavior {
bind(binding, scope, interceptor) {
binding['originalUpdateTarget'] = binding['updateTarget'];
binding.updateTarget = val => {
alert('property was changed outside of the element');
//do something here
binding['originalUpdateTarget'](val);
}
}
unbind(binding, scope) {
binding.updateTarget = binding['originalUpdateTarget'];
binding['originalUpdateTarget'] = null;
}
}
Usage:
<template>
<require from="./intercept-binding-behavior"></require>
<some-element value.bind="message & intercept"></some-element>
</template>
Runnable example: https://gist.run/?id=bcd7d39ed94856caf586f224f89fd1ff
I haven't tested this in many cases and I'm not sure if it's best way.
If you want to do the opposite (intercept when the property is changed from the element instead of the VM) just replace updateTarget
for updateSource
.
More info about CustomBindingBehaviors http://aurelia.io/hub.html#/doc/article/aurelia/binding/latest/binding-binding-behaviors/8
Hope this helps!
Upvotes: 2