Angular custom directive scope not updating as expected
I have several directives that are used on a page in my TypeScript application, and each one has its own controllers to control its own scope. Everything works pretty smoothly so far this is a really strange error.
I have a directive keypad
used in a directive payment
that is being called by my controller order
. I just want my code examples to be minimal for simplicity.
My directive payment
has a controller that has a constructor that has:
$scope.vm = this;
I use this pattern a lot. My directive payment
also has a function keypadOnChange()
that is called from the directive keypad
.
// 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);
}
It's worth noting here that it console
displays whatever I expect at the right time.
My template for the directive payment
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, it's worth noting that all features and behavior work as expected - including the vm.keypadIsVisible
one that changes similarly vm.manualTenderInputValue
.
The problem is that it vm.manualTenderInputValue
doesn't update. It displays the corresponding value on page load, and I can console.log()
value it when it changes, which is correct, but I cannot update {{ }}
.
Any thoughts on what I'm missing here?
Update
My directive keypad
handles the change event so it can tell that someone is listening for the change and they can do as they please with the data. Looks like this (and spoiler alert: here's the problem ...)
My keyboard 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 mine payment
, which had a template which had a line:
<div class="white"
keypad
onchange="vm.keypadOnChange"></div>
And the directive payment
has a function keypadOnChange
included in the original message. I entered console.log(this)
and found myself this
referencing a directive controller instance in this context keypad
. And that's the problem!
But ... how can I fix this? (no pun intended)
How do I make it so that it has the correct context (and therefore can update the scope) when run keypadOnChange
in a controller ?payment
this
Finally, I am using this directive keypad
elsewhere and have not encountered this issue.
source to share
What I decided to solve was that I could maintain the context this
for the directive controller payment
.
My controller constructor payment
ended up including:
this.keypadChange = this.onKeypadChange.bind(this);
So far 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 directive keypad
now looks like this:
<div class="white" keypad onchange="vm.keypadChange"></div>
Based on the comments and suggestions, I will most likely change some of my attribute names to avoid confusion, but this solution answers my original question.
source to share