Access validation error message custom directive - angularjs

<form-input label="Product Name" required name="name" model="ProdEdit.product.title"></form-input>
App.directive('formInput', function($timeout) {
var template = '<div class="form-group">'+
'<label for="{{id}}">{{label}}</label>'+
'<input type="text" required name="{{name}}" class="form-control" ng-model="model" id="{{id}}" placeholder="Enter {{label}}">'+
'<div ng-messages="myForm.name.$error" class="text-danger"></div>'+
'<span ng-message="required" >This is mandatory</span>'+
'</div>';
return {
restrict: 'E',
require: "^ngMessages",
template: template,
scope: {
label: "#",
model: "=",
name: "#",
required : "&"
},
replace: true
};
})
I created a form input directive like above. Now I want to show error message in span. Kindly help me out.

Related

How to make an input field into a reusable field?

I have this input with lots of directives on it:
<input class="form-control"
mobile-number
limit-characters
number-only
dir="ltr"
ng-class="{'error-form-control': vm.form.step2.phoneNumber.$invalid && (vm.form.step2.phoneNumber.$dirty || vm.form.step2.phoneNumber.$touched)}"
required
ng-model="vm.formData.phoneNumber"
name="phoneNumber"
type="text">
How can I make it into a reusable directive like so:
<phone-number ng-model="vm.formData.phoneNumber"></phone-number>
and how can I use angular form validation with this directive?
I guees it will look like this
app.directive('phoneNumber', function(){
return {
scope: {
ngModel: '='
classValidation: '=',
inputName: '#'
},
template: ' <input class="form-control" mobile-number limit-characters number-only dir="ltr" ng-class="classValidation" required ng-model="ngModel" name="{{inputName}}" type="text">',
link: function(scope, elem, attr, ctrl) {
}
}
})
HTML
<phone-number ng-model="vm.formData.phoneNumber" input-name="phoneNumber" class-validation="{'error-form-control': vm.form.step2.phoneNumber.$invalid && (vm.form.step2.phoneNumber.$dirty || vm.form.step2.phoneNumber.$touched)}"></phone-number>

disable submit button in directive

I simply want to add the class disable when form.$valid is false. The first submit button (not directive) obiouvsly works, but I don't know how to make visible the form state inside the directive. I cannot hardcode the form name in directive, it should be reusable in several forms..
<form id="tA" name="form" ng-controller="ctrl" ng-submit="form.$valid && save()" novalidate>
<input type="text" class="form-control" placeholder="title" name="name" ng-model="model.name" required ng-required="true">
<button class="btn btn-default" ng-class="{'disabled' : !form.$valid}" class="btn btn-default">Submit</button>
<button-raised disabled="!form.$valid">directive Submit</button-raised>
app.directive('buttonRaised', function() {
return {
restrict: 'E',
template: '<button class="mdl-button" ng-class="ngClass" ng-transclude></button>',
scope: {
ngModel: '='
},
transclude: true,
link: function($scope, el, $attrs,formCtrl) {
console.log(formCtrl)
$scope.ngClass = {
// 'disabled': $scope.$parent.formCtrl.$valid,
};
}
};
});
one way to do this is to pass your boolean as a parameter of your directive :
app.directive('buttonRaised', function() {
return {
restrict: 'E',
template: '<button class="mdl-button" ng-disabled="disabled" ng-class="ngClass" ng-transclude></button>',
scope: {
ngModel: '=',
disabled: '='
},
transclude: true,
link: function($scope, el, $attrs,formCtrl) {
console.log(formCtrl)
$scope.ngClass = {
// 'disabled': $scope.$parent.formCtrl.$valid,
};
}
};
});
You can change the directive and html as per this working this
The directive
app.directive('buttonRaised', function() {
return {
restrict: 'E',
template: '<button class="mdl-button" ng-class="{\'disabled\': disableButton}" ng-transclude></button>',
scope: {
disableButton: '='
},
transclude: true,
link: function($scope, el, $attrs,formCtrl) {
console.log(formCtrl)
}
};
});
The html
<form id="tA" name="form" ng-controller="ctrl" ng-submit="form.$valid && save()" novalidate>
<input type="text" class="form-control" placeholder="title" name="name" ng-model="model.name" required ng-required="true">
<button class="btn btn-default" ng-class="{'disabled' : !form.$valid}" class="btn btn-default">Submit</button>
// directive taking parameter disable-button
<button-raised disable-button="!form.$valid">directive Submit</button-raised>

ng-messages not showing in directive

I'm trying to re-use code as much as I can so I'm wrapping ng-messages in a directive. However, the messages are not shown..
<form name="elementForm" novalidate>
<md-input-container>
<label>Category</label>
<input ng-required="true" ng-model="item.category" name="category" type="text">
<administration-input-validation control="category" formname="elementForm"></administration-input-validation>
</md-input-container>
</form>
Directive:
angular.module('app.analytics')
.directive('administrationInputValidation', function () {
return {
template:
'<div ng-messages>' +
'<div ng-message="required">This is required</div>' +
'</div>',
restrict: 'E',
replace: true,
require: '^form',
scope: {
control: '=',
formname: '='
},
link: function(scope, element, attrs) {
var formStr = attrs.formname + "." + attrs.control;
element.attr("ng-messages", formStr + "." + "$error");
}
};
});
I also tried hardcoding but it's still not showing
<div ng-messages="elementForm.category.$error">
UPDATE
Binding works now, but it's not showing the messages

Directly access form element from form.FormController?

I'm working on several components (directives) to aid in form validation. I'd like the components to be aware of the related input element's state (such as required). For example...
Markup:
<form name="editUser">
<control-label input="editUser.name">Name</control-label>
<input type="text" name="name" ng-model="user.name" required/>
</form>
Directive:
app.directive("controlLabel", function() {
return {
restrict: "E",
replace: true,
transclude: true,
scope: {
input: "=input"
},
template:
'<label class="control-label">'+
'<span ng-transclude>{{label}}</span>'+
'<span ng-if="input.required"> (required!)</span>'+ // doesn't work?
'</label>'
};
});
Output:
<form name="editUser">
<label>
<span>Name</span>
<span>(required!)</span>
</label>
<input type="text" name="name" ng-model="user.name" required/>
</form>
The source for form.FormController leaves me to believe this isn't possible. Is there any way to at least get access to the attrs on the element? I thought about using a decorator, but so far I haven't been able to figure out how that would be done.
You should use input.$validators.required instead of input.required as:
myApp.directive("controlLabel", function() {
return {
restrict: "E",
replace: true,
transclude: true,
scope: {
input: "=input"
},
template:
'<label class="control-label">'+
'<span ng-transclude>{{label}}</span>'+
'<span ng-if="input.$validators.required"> (required!)</span>'+
'</label>'
};
});
Working Demo
First, there's an error in your code. If you're using transclude, you will have to declare it in your directive, or you will get an error.
As for your problem, within a directive, you can access DOM element. And for this particular use case, you can even get by without creating isolated scope or extra attribute at all:
app.directive("controlLabel", function() {
return {
restrict: "E",
replace: true,
scope: true, // if needed, can also use empty isolated scope { }
transclude: true, // must declare this
template:
'<label class="control-label">' +
'<span ng-transclude>{{label}}</span>' +
'<span ng-if="show"> (required!)</span>' +
'</label>',
link: function(scope, jqElem, attrs) {
// check if next sibling of this directive is required
scope.show = (jqElem.next().attr("required") === 'required');
}
};
});
Now your control label is really minimal and DRY, and the logic is well encapsulated within a directive. The only requirement is that your directive target must be the next sibling of the label:
<control-label>Name</control-label>
<input type="text" name="name" ng-model="user.name" required/>
Of course, if needed, you can use your jquery-fu to change the link function to suit your other requirements.

Angular directive: How to make assign value to parent scope?

I have a controller AppCtrl as
scope.transaction = {}
The index looks like
<div class="control-group">
<label class="control-label">Date</label>
<div class="controls">
<div class="control-group input-append date form_datetime">
<date-time-picker data-ng-model="transaction.date"></date-time-picker>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">Amount</label>
<div class="controls">
<div class="input-append">
<input type="text" name="transactionAmount" ng-model="transaction.amount" required>
</div>
and my custom directive looks like
angular.module('customDirectives', []).directive('dateTimePicker', function() {
return {
restrict: 'E',
replace: true,
scope: {
transaction['date']: '=' # COMPILATION ERROR HERE
},
template: '<div class="control-group input-append date form_datetime">'+
'<input type="text" readonly data-date-format="yyyy-mm-dd hh:ii" name="transactionDate" ng-model="transaction.date" data-date-time required>'+
'<span class="add-on"><em class="icon-remove"></em></span>'+
'<span class="add-on"><em class="icon-th"></em></span>'+
'</div>',
link: function(scope, element, attrs, ngModel) {
var input = element.find('input');
element.datetimepicker({
format: "yyyy-mm-ddThh:ii:ssZ",
showMeridian: true,
autoclose: true,
todayBtn: true,
pickerPosition: 'bottom-left'
});
element.bind('blur keyup change', function(){
console.log('binding element');
scope.$apply(date);
});
function date() {
console.log('setting date',input.val());
scope.ngModel = input.val();
}
date(); // initialize
}
}
});
I want to assign the date value from my directive to $scope.transaction.date but it is failing as compilation error, how can I achieve this?
scope: {
transaction['date']: '=' # COMPILATION ERROR HERE
},
Should be
scope: {
transactionDate: '='
},
And
<date-time-picker data-ng-model="transaction.date"></date-time-picker>
Should be
<date-time-picker transaction-date="transaction.date"></date-time-picker>
Then within your directive you can call scope.transactionDate = myValue;
within scope.$apply();
EDIT: If you want to use ng-model within your directive then you can use
....
restrict: 'E',
require: '?ngModel',
....
And
controller.$setViewValue(value); //this will in directive code where you want set the value of the ng-model bound variable.
In Html
<date-time-picker data-ng-model="transaction.date"></date-time-picker>

Resources