Reputation: 3459
I want to build custom directives having the same ng-change syntax as a normal input field. Let's say I have a directive like this:
;(function() {
'use strict';
angular.module('myMod', []);
angular.module('myMod').directive('myDir', myDirDirective);
function myDirDirective() {
return {
restrict: 'E',
template: '
<input ng-change="checkInput1()" type=...>
<input ng-change="checkInput2()" type=...>
',
controllerAs: 'myDirDirective',
controller: myDirController,
require: 'ngModel',
scope: {},
bindToController: {
model: '='
}
};
}
// Controller goes here...
})(); // EOF
Now I want to define the input check methods like
function checkInput1() {
...
if( <changes in input 1 are legit> ) {
fireOuterNgChange();
}
}
function checkInput2() {
...
if( <changes in input 2 are legit> ) {
fireOuterNgChange();
}
}
And finally I want to be able to use my custom directive like:
<myDir ng-change="doSomethingAfterSomethingChanged()">
...
</myDir>
A simple use case for this would be a time picker with several input fields for hours : minutes : seconds : milliseconds. Just to give an example. I tried different approaches without success; How can I do this?
Upvotes: 0
Views: 2395
Reputation: 3459
@Neozaru answer works perfect. But to be complete I'm posting a complete code example for easier understanding. Following the John Papa's Style Guide and using the controllerAs
Syntax instead of $scope
(example use case: having a re-usable userform):
Implement you custom directive with your custom ng-change events
First, the template
// my-dir-template.html
Username: <input type="text" name="username" ng-change="passwordForm.changeHandler()" ng-model="passwordForm.model">
Password: <input type="text" name="password" ng-change="passwordForm.changeHandler()" ng-model="passwordForm.model">
The directive and the controller
;(function() {
'use strict';
angular.module('myMod', []);
angular.module('myMod').directive('passwordForm', passwordFormDirective);
function passwordFormDirective() {
return {
restrict: 'E',
templateUrl: 'password-form.html',
controllerAs: 'passwordForm',
controller: passwordFormController,
require: 'ngModel',
scope: {},
bindToController: {
model: '=',
ngChange: '&' // << bind ng-change to controller (not scope)
}
};
}
function passwordFormController() { // no scope injected
// Pseudo this
var vm = this;
// implement controller
vm.changeHandler = changeHandler ;
// // // Method implementations
...
function changeHandler() {
// we could do validation here, altough I'm not sure if this would be a good idea here.
// for now, we only do the change listener notification
if(vm.ngChange === 'function') {
vm.ngChange();
}
}
}
})(); // EOF
Now we can use our directive with the normal ng-change listener. Maybe for registration of new users:
<password-form ng-model="the-model" ng-change="checkIfUsernameExists()">
Upvotes: 2
Reputation: 1130
So here you need to perform two things :
<input>
elements.<my-dir>
.For (1), you'll simply do as your said : You register callbacks in your directive's scope (scope.checkInput1 = function() { ... }
).
Then, to forward the event to the parent (finally imitating the <input ng-change>
behavior), you will need to declare an expression binding in the Directive's isolated scope like this :
scope: {
onDateChange: '&'
}
On the parent Controller, assuming that you declared some $scope.onDirectiveDateChange = function() { ... }
in the scope, you just pass the callback into your custom Directive like this :
<my-dir on-date-change="onDirectiveDateChange()"></my-dir>
Then you call it from your directive's checkInput2
:
scope.onDateChange(); // This will call parent's "onDirectiveDateChange()" if defined
Upvotes: 2