My AngularJS typeahead FaveDirective needs to bind a single value to the parent scope, and call an update function when that value changes:
Parent html:
<div class="parent-controller-scope ng-scope">
<my-fave-picker favorite="parent.favorite" on-change="parent.update()">
</div>
Fave picker directive template:
<input
type="text"
ng-model="vm.favorite"
typeahead-on-select="vm.onChange()"
ng-init="vm.loadTypeaheadValues()"
placeholder="Pick your favorite Swift"
uib-typeahead="name for name in ::vm.TypeaheadValues | filter:$viewValue"
class="form-control">
Fave picker directive code:
(function (angular, _) {
'use strict';
angular
.module('favorite')
.directive('MyFavePicker', function() {
return {
restrict: 'E',
templateUrl: 'fave-picker-template.html',
scope: {
favorite: '=',
onChange: '&'
},
controllerAs: 'vm',
bindToController: true,
controller: 'FavePickerController'
};
})
.controller('FavePickerController', function() {
// etc.
});
}(angular, _));
This works almost correctly; when the typeahead input is committed, it calls update() on the parent scope as intended. The problem is that this happens before the latest value of favorite is propagated to the parent scope. In other words, if the typeahead has possible values ["Taylor Swift", "Jonathan Swift"] and I type "Tay" and then hit enter to select the value from the dropdown, then at the time the typeahead-on-select callback is executed, I have the following values:
vm.favorite = "Taylor Swift"
parent.favorite = "Tay"
The parent.update() function therefore operates with the wrong value of parent.favorite ("Tay" instead of "Taylor Swift").
I can think of some bad ways, but what's the right way to do this so that the change to vm.favorite gets propagated back to the parent scope before calling parent.favorite()?
Note that the following things are not possible in my circumstances:
- inheriting parent scope instead of using isolate scope
- passing
favoriteas an argument toupdate(on-change="parent.update(favorite)") - setting a timeout in
dir.onChange()before callingparent.update()
Avoid using two-way,
'=', binding in components to propagate values. Instead use one-way,'<', binding for inputs and expression,'&', binding for outputs:In the component template:
By applying the value in the expression,
'&', binding, the value is propagated immediately. With two-way,'=', binding, the value is propagated after a digest cycle.For more information, see