I have a few directives being used on a page in my TypeScript application, and each have their own controllers to manage their own scope. Everything has been working quite smoothly until this really strange bug.
I have a keypad
directive being used in a payment
directive which is called by my order
controller. I'm going to keep my code samples minimal for simplicity.
My payment
directive has a controller which has a constructor that has:
$scope.vm = this;
I use this pattern very frequently. My payment
directive also has a function keypadOnChange()
that is invoked from the keypad
directive.
// In the payment directive:
public keypadOnChange(keypadDirective: IKeypadDirectiveController): void {
console.log("keypad is changed");
console.log(keypadDirective.selection);
this.manualTenderInputValue = Number(keypadDirective.selectionToString());
console.log(this.manualTenderInputValue);
}
The thing worth noting here is that the console
displays everything I expect it to at exactly the right time.
My template for the payment
directive contains:
<div ng-show="vm.keypadIsVisible" class="square_keypad">
<div class="white"
keypad
onchange="vm.keypadOnChange"></div>
</div>
<div class="item manual-tender-input-field item-white item-small-padding"
ng-click="vm.toggleKeypadVisibility()">
{{ vm.manualTenderInputValue }}
</div>
Again, the thing worth noting is that all functions and behavior are working as expected -- including vm.keypadIsVisible
which is changed in a similar way to vm.manualTenderInputValue
.
The problem is that vm.manualTenderInputValue
is not getting updated. It displays the appropriate value on page load, and I can console.log()
its value when it's changed, and it is correct, but I can't get the {{ }}
to update.
Any thoughts on what I'm missing here?
My keypad
directive handles a change event, so it can tell anyone listening about the change and they can do as they please with the data. It looks like this (and spoiler: here in lies the problem...)
My keypad directive has a controller that has these noteworthy lines:
// a public variable:
public onChange: any = null;
// in the constructor:
$scope.$watch("onchange", (v) => { this.onChange = v; });
// in a function invoked by ng-click:
public selectNumber(digit: string, domId?: string): void {
// ... some other stuff not relevant ...
this.triggerOnChange();
}
// the triggerOnChange in the keypad directive controller:
public triggerOnChange(): void {
if (this.onChange) {
this.onChange(this);
}
}
Now, back to my payment
which had a template that had a line looked like:
<div class="white"
keypad
onchange="vm.keypadOnChange"></div>
And the payment
directive controller has the keypadOnChange
function included in the original post. I threw in a console.log(this)
and discovered that in that context, this
was referring to the instance of the keypad
directive controller. And that is the problem!
But... how do I fix this ? (no pun intended)
How do I make it so that when keypadOnChange
is invoked on the payment
controller it still has the right this
context (and can therefore update the scope)?
One final note, I'm using this keypad
directive elsewhere and didn't run into this issue.
What solved my problem was ensuring that I could maintain the this
context for the payment
directive controller.
My payment
controller constructor ended up including:
this.keypadChange = this.onKeypadChange.bind(this);
While onKeypadChange()
remained the same:
public keypadOnChange(keypadDirective: IKeypadDirectiveController): void {
// is now referring to the instance of the controller, NOT the keypad directive:
console.log(this);
this.manualTenderInputValue = Number(keypadDirective.selectionToString());
}
Finally, the template that calls the keypad
directive now looks like:
<div class="white" keypad onchange="vm.keypadChange"></div>
Based on comments and suggestions, I'll likely be changing some of my attribute names to avoid confusion, but this solution answers my original question.
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.