Angular directive for form elements - angularjs

I want to create directive which will be used for form elements like input,textarea,select...
My code:
app.directive('input', function() {
return {
restrict: 'E',
priority: -1000,
require: '^?required',
link: function (scope, element, attrs, ctrl) {
element.on('focus', function (e) {
element.addClass('validate');
});
}
};
});
When I try to use common directive it doesn't work but don't have idea why...
<input common-directive type="text" name="name" placeholder="Firstname" ng-model="profile.name" ng-minlength="2" required />

Related

How to set input field validation in reusable custom directive?

I'm trying to make a reusable custom directive that will validate date in input field. Code provided below is working, however is not reusable at all which is my biggest concern.
What I was trying to do, was to set a new scope in directive however I got an error:
Multiple directives requesting isolated scope.
So I guess isolated scope is not going to help me.
Any other solutions?
That's my first template:
<form ng-submit="add()" name="addTask" class="form-horizontal">
<input name="dateInput" is-date-valid type="text" class="form-control" ng-model="task.DueDate" datepicker-options="datepicker.options" ng-model-options="{ timezone: 'UTC' }" uib-datepicker-popup="mediumDate" is-open="isOpened" required>
</form>
That's my second template:
<form ng-submit="edit()" name="editTask" class="form-horizontal">
<input name="dateInput" is-date-valid type="text" class="form-control" ng-model="task.DueDate" datepicker-options="datepicker.options" ng-model-options="{ timezone: 'UTC' }" uib-datepicker-popup="mediumDate" is-open="isOpened" required>
</form>
And that's my custom directive:
function isDateValid($log) {
'ngInject';
var directive = {
restrict: 'A',
require: 'ngModel',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$watch(attrs.ngModel, function () {
var validation = can_i_get_this_from_controller ?
if (validation) {
ctrl.$setValidity('validation', true);
} else {
ctrl.$setValidity('validation', false);
}
});
}
}
module.exports = isDateValid;
The way you implemented the custom validator is not good, you should be doing something like this -
.directive('dateValidate', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ngModel) {
ngModel.$validators.dateValidate = function(modelValue) {
//Your logic here, return true if success else false
}
}
};
});
It can be used on both form paths, so no need of that logic here.
To know more about these this is one good resource

Angular ng-dirty not toggling with datepicker directive

I have a custom directive for applying jQuery UI Datepicker to some inputs. I can pick a date and it updates the input. However, when i post back the results. The input(control) that was edited isn't marked dirty so the changes never get saved. See below..
<td>
<input type="text" jqdatepicker name="Delegation.StartDate" ng-model="delegation.StartDate" />
</td>
<td>
<input type="text" jqdatepicker name="Delegation.EndDate" ng-model="delegation.EndDate" />
</td>
App.directive('jqdatepicker', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
element.datepicker({
dateFormat: 'm/dd/yy',
onSelect: function (date) {
scope.date = date;
scope.$apply();
ngModelCtrl.$setDirty(); <--doesn't work
}
});
}
};});
I have tried using scope, element, ngModel and can't get the state of the control to change from pristine to dirty. On save, i scrap the rows(tr) for those that have the class ng-dirty and process them. Any thoughts on how to do this? I use the same method on about 8 other pages without issue but those do not use the directive/datepickers.
After lots of trial and error and reading. I finally got it to work! Below is the directive.
App.directive('jqdatepicker', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
element.datepicker({
dateFormat: 'm/dd/yy',
onSelect: function (date) {
console.log(ngModelCtrl);
ngModelCtrl.$setViewValue(date);
}
});
}
};
});

How to update value of ng-model with the expression in html part

Why value of the ng-model is not updated with the expression. Before ng-model is defined value get updated
Value will be updated as soon as phase2 or phase3 changes
<input type="text" name="phase1" value="{{phase2 - phase3}}" ></input>
Value will not be updated
<input type="text" name="phase1" value="{{phase2 - phase3}}" ng-model="phase1"></input>
So I think of writing a directive which will evaluate the expression inside the directive and updated the output to model,
Here is html it will look like
<input type="text" name="phase1" ng-model="phase1" my-value="{{phase2 - phase3}}" my-model-value></input>
Directive:
myApp.directive('myModelValue', function(){
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel',
value: '#myValue'
},
link: function (scope, element, attr, controller) {
scope.model = scope.value;
}
};
});
This directive evaluate only at load time, but I want to continuously update/watch as the dependent fields (phase2 & phase3) changes.
I can update value from controller but I want to do it from html. Please help me, it it possible or against the working of angular
Thanks guys I figure out what I wanted to do. Here is the my final simple but useful directive :)
app.directive('myModelValue', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel'
},
link: function (scope, element, attr, controller) {
attr.$observe('myModelValue', function (finalValue) {
scope.model = finalValue;
});
}
};
});
Usage:
<input type="text" ng-model="phase1" my-model-value="{{phase2 - phase3}}"></input>
<input type="text" ng-model="phase1.name" my-model-value="{{valid angular expression}}"></input>
In order to continously watch the phase2/3 changes you can make use of $scope.$watch function.
Something like this will work for you:
link: function (scope, element, attr, controller) {
scope.$watchCollection('[phase1,phase2]', function() {
//whatever you want to do over here }
and in the scope pass phase1 and phase2 values as well
This will watch the value expression and update the same when value will change
myApp.directive('myModelValue', function(){
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel',
value: '#myValue'
},
link: function (scope, element, attr, controller) {
scope.$watch('value',function(newValue){
console.log(newValue);
});
}
};
});
here value is a local scope so it will watch the expression

Two way data binding failing with ng-model

My two-way data binding using ng-model is not working.
AngularJS Docs
Relevant Question
Parent directive template:
<div class="form-group">
<label>Company Phone</label>
<input ng-model="formData.company_phone" type="phonenumber" class="form-control" placeholder="Company Phone">
</div>
And the child directive:
.directive('input', [function(){
return: {
restrict: 'E',
require: '?ngModel',//right now this is binding to this directive scope, not a parent one
link: function($scope, element, attr, ngModel){
if (attr.type !== 'phonenumber') {
return;
}
//some code to validate a phone number
$scope.$apply(function () {
//bind updated number, but I need this to reflect in the parent scope
$scope[attr.ngModel] = formattedNumber;
}
I used $parse to solve this issue:
.directive('input', ['$parse', function($parse){
return {
restrict: 'E',
require: '?ngModel',
link: function(scope, element, attr, ngModel){
var getter = $parse(attr.ngModel);
var setter = getter.assign;
if (attr.type !== 'phonenumber') {
return;
}
//code that validated a phone number
scope.$apply(function () {
setter(scope, formattedNumber);
});
}
}
}]);

Attribute directive to work on an element inside another directive

I have hit a wall with what I need from angular, hopefully there's an easy way to achieve what I'm after.
I have a directive that looks something like that:
m.directive("string", function() {
return {
replace: true,
restrict: 'E'
scope: {'value':'='}
template: '<div>yada yada yada <input type="text" ng-model="value"/></div>'
};
});
I have another directive which must go on top of text input elements only:
m.directive("maskedString", function() {
restrict: 'A',
link: function(scope, element, attrs) {
// ... do stuff on the element
}
});
So... I can do that with no problem:
<input type="text" masked-string />
However, what I really need is:
<string masked-string />
This should end up setting the masked-string attribute on the input field before the template is compiled.
What is the best way to achieve that? 10x
I suggest you use compile method of the directive for this. Here is a working fiddle - http://jsfiddle.net/R4a62/1/
myApp.directive("string", function () {
return {
replace: true,
restrict: 'E',
scope: {
'value': '='
},
compile:function(element, attrs){
var newElement = angular.element('<div>yada yada yada <input type="text" masked-string ng-model="value"/></div>');
element.replaceWith(newElement);
}
};
});
You can do this with $compile. You only need to change the top-level directive. Here's a fiddle with an example. http://jsfiddle.net/D94t7/6/
m.directive("string", function ($compile) {
return {
replace: true,
restrict: 'E',
scope: {
'value': '=',
'drtv': '='
},
link: function(scope, element, attrs) {
var template = '<div>yada yada yada <input type="text" ng-model="value" '+ attrs.drtv +'/></div>';
// Add the HTML
var el = angular.element(template);
element.append(el);
// Compile and bind to scope
var compiled = $compile(el);
compiled(scope);
}
};
});

Resources