Have some directive to uncheck previously checked radio in group:
(function (angular, $) {
'use strict';
var radioGroupDirective = function () {
return {
restrict: 'EA',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModelController) {
var $radios = $element.find('input[type="radio"]');
$radios.click(function($event) {
var $radio = $($event.target);
if ($radio.data('waschecked') == true) {
$radio.prop('checked', false);
$radio.data('waschecked', false);
ngModelController.$setViewValue(null);
} else {
$radio.data('waschecked', true);
}
$radio.siblings('input[type="radio"]').data('waschecked', false);
});
},
};
};
radioGroupDirective.$inject = [];
angular.module('radio.group', []).directive('radioGroup', radioGroupDirective);
})(angular, $);
Usage:
<div radio-group ng-model="fruit">
<input type="radio" ng-model="fruit" value="Apple"/>
<input type="radio" ng-model="fruit" value="Banana"/>
<input type="radio" ng-model="fruit" value="Mango"/>
</div>
It works fine, but I want to remove duplicate code of ngModels in child inputs. Like this:
<div radio-group ng-model="fruit">
<input type="radio" value="Apple"/>
<input type="radio" value="Banana"/>
<input type="radio" value="Mango"/>
</div>
So I try to add ngModel to all child inputs dynamically at compile function
(function (angular, $) {
'use strict';
var radioGroupDirective = function ($compile) {
return {
restrict: 'EA',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModelController) {
var $radios = $element.find('input[type="radio"]');
$radios.click(function($event) {
var $radio = $($event.target);
if ($radio.data('waschecked') == true) {
$radio.prop('checked', false);
$radio.data('waschecked', false);
ngModelController.$setViewValue(null);
} else {
$radio.data('waschecked', true);
}
$radio.siblings('input[type="radio"]').data('waschecked', false);
});
},
compile: function (tElement, tAttrs) {
var $radios = tElement.find('input[type="radio"]');
angular.forEach($radios, function(radio) {
$(radio).attr('ng-model', tAttrs.ngModel);
});
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
},
post: function postLink(scope, iElement, iAttrs, controller) {
$compile(iElement)(scope);
},
};
},
};
};
radioGroupDirective.$inject = ['$compile'];
angular.module('radio.group', []).directive('radioGroup', radioGroupDirective);
})(angular, $);
but it causes an infinite compilation loop and a dead of the browser
You try to compile the entire the directive (radioGroup) again from the link function so it causes an infinite loop.
Instead compile only the inputs:
angular.forEach($radios, function(radio) {
$compile(radio)(scope);
});
See this plunker.
Full worked plunker for this directive (for someone who could find it usefull)
var radioGroupDirective = function ($compile) {
return {
restrict: 'EA',
require: 'ngModel',
compile: function (tElement, tAttrs) {
var $radios = tElement.find('input');
angular.forEach($radios, function(radio) {
$(radio).attr('ng-model', tAttrs.ngModel);
});
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
},
post: function postLink(scope, iElement, iAttrs, controller) {
angular.forEach($radios, function(radio) {
$compile(radio)(scope);
});
$($radios).click(function($event) {
var $radio = $($event.target);
if ($radio.data('waschecked') == true) {
$radio.prop('checked', false);
$radio.data('waschecked', false);
controller.$setViewValue(null);
} else {
$radio.data('waschecked', true);
}
$radio.siblings('input[type="radio"]').data('waschecked', false);
});
},
};
},
};
};
radioGroupDirective.$inject = ['$compile'];
angular.module('radio.group', []).directive('radioGroup', radioGroupDirective);
Related
In this plunk I have directive dir1 calling a method in directive dir2 as described here.
The problem is that the control object (scope.dir2Ctl) is empty in dir1 and I get TypeError: scope.dir2Ctl.call2 is not a function. Any ideas how to fix this?
HTML
<body ng-app="myModule" ng-controller="ctl">
<dir1 x1="1"></dir1>
</body>
Javascript
angular.module("myModule", [])
.controller('ctl', function($scope) {})
.directive('dir1', function ($timeout) {
return {
restrict: 'EA',
scope: {
x1: '='
},
template: '<p>x2 should be 2 = {{x2}} </p>' +
'<dir2 control="dir2Ctl"></dir2>',
link: function (scope, element, attrs) {
scope.dir2Ctl = {};
$timeout(function(){
console.log(scope.dir2Ctl)
scope.x2 = scope.dir2Ctl.call2();
},1000);
}
}
})
.directive('dir2', function () {
return {
restrict: 'EA',
scope: {
control: '='
},
template: '<p>some text in dir2</p>',
link: function (scope, element, attrs) {
scope.control = scope.control || {};
scope.control.call2 = function(){
return 2;
};
}
}
});
How do I use $broadcast to update custom validation in other directives which already have isolated scope?
I want to be able create separate validation rules used on a single input field.So in the future I can change the validation of a field by simply changing the directive reference.
Check the plunkr
edit: I am using angular 1.2.8
The element the directive is on has isolated scope.
Validation Directive 1
(function () {
'use strict';
angular
.module('app')
.directive('dateOneValidation', dateOneValidation);
function dateOneValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$on('updateDateOneValidation', function(e, date){
ctrl.$parsers.unshift(function (viewValue) {
var form = scope.form;
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var today = moment();
var dateOneBeforeOrOnToday = dateOne.isSame(today, 'day') || dateOne.isBefore(today, 'day');
dateOneBeforeOrOnToday ? form.dateOne.$setValidity('dateOneBeforeOrOnToday', true):
form.dateOne.$setValidity('dateOneBeforeOrOnToday', false);
return viewValue
});
});
}
}
})();
Validation Directive 2
(function () {
'use strict';
angular
.module('app')
.directive('dateTwoValidation', dateTwoValidation);
function dateTwoValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$on('updateDateTwoValidation', function(e, date){
ctrl.$parsers.unshift(function (viewValue) {
var form = scope.form;
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var dateTwo = moment(viewValue, "DD/MM/YYYY", true);
var dateTwoAfterDateOne = dateTwo.isSame(dateOne, 'day') || dateTwo.isAfter(dateOne, 'day');
dateTwoAfterDateOne ? form.dateTwo.$setValidity('dateTwoAfterDateOne', true):
form.dateTwo.$setValidity('dateTwoAfterDateOne', false);
return viewValue
});
});
}
}
})();
(function () {
'use strict';
angular
.module('app')
.directive('stepOne', stepOne);
function stepOne() {
parentController.$inject = ['$scope'];
function parentController($scope) {
var vm = this;
vm.dateOne = '01/01/2000'
vm.dateTwo = '01/01/1900'
vm.validateStepOne = validateStepOne;
function validateStepOne() {
$scope.$broadcast('updateDateOneValidation');
$scope.$broadcast('updateDateTwoValidation');
}
}
var directive = {
restrict: 'EA',
require: '^form',
templateUrl: 'src/app/form/step1.html',
scope: {
},
controller: parentController,
controllerAs: 'vm'
};
return directive;
}
})();
(function () {
'use strict';
angular
.module('app')
.directive('dateOneValidation', dateOneValidation);
function dateOneValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
var form = scope.form;
var today = moment();
scope.$watch(attrs.ngModel, function () {
validator()
});
scope.$on('updateDateOneValidation', function () {
validator();
});
function validator() {
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var dateOneBeforeOrOnToday = dateOne.isSame(today, 'day') || dateOne.isBefore(today, 'day');
dateOneBeforeOrOnToday ? form.dateOne.$setValidity('dateOneBeforeOrOnToday', true) :
form.dateOne.$setValidity('dateOneBeforeOrOnToday', false);
}
}
}
})();
(function () {
'use strict';
angular
.module('app')
.directive('dateTwoValidation', dateTwoValidation);
function dateTwoValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
var form = scope.form;
scope.$watch(attrs.ngModel, function () {
validator();
});
scope.$on('updateDateTwoValidation', function (e, date) {
validator();
});
function validator() {
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var dateTwo = moment(form.dateTwo.$viewValue, "DD/MM/YYYY", true);
var dateTwoAfterDateOne = dateTwo.isSame(dateOne, 'day') || dateTwo.isAfter(dateOne, 'day');
dateTwoAfterDateOne ? form.dateTwo.$setValidity('dateTwoAfterDateOne', true) :
form.dateTwo.$setValidity('dateTwoAfterDateOne', false);
};
};
}
})()
Alternatively You can use a higher shared scope with a form object and pass it to your directives. Something like the following:
topLevelScope - ngForm
directive1(topLevelScope.ngForm)
topLevelScope.ngForm.$setValidity('input1', true)
directive2(topLevelScope.ngForm)
topLevelScope.ngForm.$setValidity('input2', true)
directive3(topLevelScope.ngForm)
topLevelScope.ngForm.$setValidity('input3', true)
My 2 cents.
The following directive does not generate any exceptions & it does get called, but link never executes. Can you point me in the right direction?
(function() {
var noduplicateModule,
__hasProp = {}.hasOwnProperty;
noduplicateModule = angular.module('noduplicate', []);
noduplicateModule.directive('noduplicate', function() {
return {
restrict: 'A',
scope: {
ngModel: '=',
bindAttr: '='
},
require: 'ngModel',
link: function (scope, elem, attr, ctrl) {
var options;
console.log("test");
//options = getOptions(scope);
console.log("test");
//ngModelCtrl.$validators.noduplicate = function (viewVal) {
//
// console.log("test");
// return true;
//};
elem.on('blur', function () {
console.log("test");
});
elem.on('focus', function () {
console.log("test");
});
}
};
});
}).call(this);
UPDATE - HTML
<select name="test" id="test" data-role="none" class="form-control" ng-model="testfield" required noduplicate="NODUPE"/>
I wrote a directive for input focus & blur
angular
.module('app')
.directive('input', ['$filter', function($filter) {
return function(scope, element, attrs) {
if (element && element[0] && element[0].placeholder) {
scope.placeholder = element[0].placeholder;
element.bind("focus", function() {
console.log(scope.placeholder);
element[0].placeholder = "";
});
element.bind("blur", function() {
element[0].placeholder = $filter('translate')(scope.placeholder);
});
}
};
}]);
I want same functionality for text area also. But don't wanted to write an other directive. How I can do this?
var myDirective = ['$filter', function($filter) {
return {
restrict: 'E',
scope: true,
link: function(scope, element, attrs) {
if (element && element[0] && element[0].placeholder) {
scope.placeholder = element[0].placeholder;
element.bind("focus", function() {
console.log(scope.placeholder);
element[0].placeholder = "";
});
element.bind("blur", function() {
element[0].placeholder = $filter('translate')(scope.placeholder);
});
}
}
};
}]
angular
.module('app')
.directive('input', myDirective);
.directive('textarea', myDirective);
and in your html:
<input />
<textarea></textarea>
I have a directive and I'm trying to pass Date/moment object via attribute. I'm passing it like this: (I know, that I can create isolated-scope and bind it, it is not the case)
<form name="form">
<input name="field" ng-model="fieldModel" form-field-directive field-date="{{fieldDateModel}}" />
</form>
Without curly brackets the result is obvious, but with I'm getting such quoted string "2015-07-03T10:35:13.691Z".
Is there anyway to work with it?
UPDATE:
angular.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.fieldDateModel = moment(); // new Date()
});
angular.module('app')
.directive('formFieldDirective', function() {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
ngModelCtrl.$validators.fieldDate = function() {
if (angular.isUndefined(iAttrs.fieldDate)) {
return true;
}
console.log(iAttrs.fieldDate);
};
}
};
});
You can actually pull the value from the parent scope using $parse which is more reliable.
angular.module('app')
.directive('formFieldDirective', function($parse) {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
ngModelCtrl.$validators.fieldDate = function() {
if (angular.isUndefined(iAttrs.fieldDate)) {
return true;
}
console.log(($parse(iAttrs.fieldDate)(scope)).format());
};
}
};
});
http://jsbin.com/qoheraloge/1/edit?js,console,output