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:
favorite
as an argument to update
( on-change="parent.update(favorite)"
) dir.onChange()
before calling parent.update()
Avoid using two-way, '='
, binding in components to propagate values. Instead use one-way, '<'
, binding for inputs and expression, '&'
, binding for outputs:
<my-fave-picker favorite="parent.favorite"
on-change="parent.favorite=$value; parent.update($value)">
</my-fave-picker>
app.directive('MyFavePicker', function() {
return {
restrict: 'E',
templateUrl: 'fave-picker-template.html',
scope: {
̶f̶a̶v̶o̶r̶i̶t̶e̶:̶ ̶'̶=̶'̶,̶
favorite: '<',
onChange: '&'
},
controllerAs: 'vm',
bindToController: true,
controller: 'FavePickerController'
};
})
In the component template:
<input
type="text"
ng-model="vm.favorite"
ng-change="vm.onChange({$value: vm.favorite})"
typeahead-on-select="vm.onChange({$value: vm.favorite})"
ng-init="vm.loadTypeaheadValues()"
placeholder="Pick your favorite Swift"
uib-typeahead="name for name in ::vm.TypeaheadValues | filter:$viewValue"
class="form-control"
/>
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
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.