Dynamic input type angularjs - angularjs

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-input-directive-production</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js"></script>
</head>
<body ng-app="inputExample">
<div ng-controller="ExampleController">
<form name="myForm">
<label>
Is Bulk:
<input type="checkbox" ng-model="isBulk" ng-change="onChange()"/>
</label
<label>
Quantity:
<input input-type="isBulk ? 'text' : 'number'" name="lastName"
ng-model="quantity"
ng-minlength="3" ng-maxlength="10"
ng-disabled="isBulk"
>
</label>
</form>
<hr/>
<div>isBulk:{{isBulk}}</div>
<div>quantity: {{quantity}}</div>
</div>
</body>
</html>
angular.module('inputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.quantity = 0;
$scope.isBulk = false;
$scope.onChange = function(){
if($scope.isBulk){
$scope.quantity = "NOT APPLICABLE";
}else{
$scope.quantity = 0;
}
}
}])
.directive('inputType', function() {
return {
restrict: "A",
scope: {
quantity: "="
},
link: function(scope, element, attr) {
var inputType = scope.$eval(attr.inputType);
console.log("inputType", inputType);
element.attr("type", inputType);
}
};
});
How do I dynamically change input type based on a value.
Here is the plunker link
https://next.plnkr.co/edit/kmkNKPWcM5jq159k

Use a different template with ng-if
<input ng-if="isBulk" input-type="text" name="lastName" ng-model="quantity"
ng-minlength="3" ng-maxlength="10">
<input ng-if="!isBulk" input-type="number" name="lastName" ng-model="quantity"
ng-minlength="3" ng-maxlength="10">
Update
You could add a watcher in your directive:
scope.$watch("inputType", function (newValue, oldValue, scope) {
if (newValue && newValue !== oldValue) {
element.attr("type", newValue);
}
});
Plunker : https://next.plnkr.co/edit/EsTwRTChBHjDqD2e

Change the directive to watch the attribute expression:
app.directive('inputType', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
̶s̶c̶o̶p̶e̶:̶ ̶{̶
̶i̶n̶p̶u̶t̶T̶y̶p̶e̶:̶ ̶=̶
̶}̶,̶
link: function(scope, elem, attrs) {
̶v̶a̶r̶ ̶i̶n̶p̶u̶t̶T̶y̶p̶e̶ ̶=̶ ̶s̶c̶o̶p̶e̶.̶$̶e̶v̶a̶l̶(̶a̶t̶t̶r̶.̶i̶n̶p̶u̶t̶T̶y̶p̶e̶)̶;̶
scope.$watch(attrs.inputType, function(newValue) {
var inputType = newValue;
console.log("inputType", inputType);
elem.attr("type", inputType);
});
}
};
});
The directive will then update whenever the value of the expression changes.
Note: By having the watcher evaluate the attribute directly, the directive avoids using an isolate scope to evaluate the attribute.

Related

scope.$eval() is undefined if both input fields have the same directive

I'm trying to validate two password input fields. Simply confirm that they are equal. (Suggest another approach if mine is way wrong)
I have implemented a directive with a simple validation that checks if the "confirm" password is the same as the original. But the directive also checks for other things, so I need to have both input fields to have it.
The problem is that when I have my directive on both input fields, I cannot read their model values through the attribute (to check if they match).
Here is a working demo without the directive on the first password:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive('myDir', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.mismatch = function(modelValue, viewValue) {
// MAIN CODE:
return viewValue === scope.$eval(attrs.confirm);
};
ctrl.$validators.short = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
return true;
}
if (modelValue.length >= 3) {
return true;
}
return false;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form1">
<input type="password" name="password1" ng-model="pass1"><br>
<input type="password" my-dir confirm="pass1" name="password2" ng-model="pass2"><br>
<pre>{{form1.password2.$error | json}}</pre>
<p ng-show="form1.password2.$error.mismatch" style="color:red">Passwords are different</p>
</form>
</div>
If I change the first filed to:
<input type="password" my-dir confirm="pass2" name="password1" ng-model="pass1">
to validate in both directions, then scope.$eval(attrs.confirm) becomes undefined for both fields.
Here is a demo of my issue:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive('myDir', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.mismatch = function(modelValue, viewValue) {
// `scope.$eval(attrs.confirm)` always undefined
return viewValue === scope.$eval(attrs.confirm);
};
ctrl.$validators.short = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
return true;
}
if (modelValue.length >= 3) {
return true;
}
return false;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form1">
<input type="password" my-dir confirm="pass2" name="password1" ng-model="pass1"><br>
<input type="password" my-dir confirm="pass1" name="password2" ng-model="pass2"><br>
<pre>{{form1.password2.$error | json}}</pre>
<p ng-show="form1.password2.$error.mismatch || form1.password.$error.mismatch" style="color:red">
Passwords are different
</p>
</form>
</div>
You need to do 2 things:
1. Add ng-model-options="{allowInvalid: true}" so invalid value will still update scope value.
2. Now you have problem that e.g. changing 2nd input wont trigger 1st re-validation. This is done using observe:
<body ng-controller="MainCtrl" ng-init="x = 0; y = 0">
<form name="form1">
<input type="password" my-dir="{{y}}" confirm="pass2" name="password1" ng-model="pass1" ng-model-options="{allowInvalid: true}"
ng-change="x = x + 1"><br>
<input type="password" my-dir="{{x}}" confirm="pass1" name="password2" ng-model="pass2" ng-model-options="{allowInvalid: true}"
ng-change="y = y + 1"><br>
and
attrs.$observe('myDir', function() {
ctrl.$validate();
});
http://plnkr.co/edit/ws4tVWGXfFNR2yqLRJN7?p=preview
P.S. for usual fields I would write my-dir="{{pass1}}" and then no need in $eval and ng-change, but for passwords... not sure

AngularJS - input type="number" not clearable for non-number (NaN)

Clear number input type does not work for 'e' number
When I clear the input field with input eee in number type, it does not get cleared. Any other input numbers get cleared. Check the JSFiddle. Any hints would be appreciated.
http://jsfiddle.net/2ankx9up/
<div ng-app="app">
<div ng-controller="MainCtrl">
<input type="number" class="form-control" data-ng-model="searchAll">
</input>
<a class="clear" href="" data-ng-click="clearSearch()">X</a>
</div>
</div>
var app = angular.module("app", []);
app.controller("MainCtrl", function ($scope) {
$scope.searchAll = "";
$scope.clearSearch = function () {
$scope.searchAll = "";
};
});
The ng-model directive is unable to clear the content of an <input type="number"> element when that content parses to NaN (not a number). This can happen when a user pastes invalid content or simply types "eee".
One fix is to add a custom directive:
app.directive('clearNan', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
ngModel.$formatters.push(function(value) {
if (!value) elem.val(null);
return value;
});
}
};
})
Usage:
<input type="number" clear-nan ng-model="x" />
The DEMO
angular.module('numfmt-error-module', [])
.directive('clearNan', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
ngModel.$formatters.push(function(value) {
if (!value) elem.val(null);
return value;
});
}
};
})
.run(function($rootScope) {
$rootScope.typeOf = function(value) {
return typeof value;
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="numfmt-error-module">
<input clear-nan type="number" ng-model="x" />
<br>
{{ x }} : {{ typeOf(x) }}
<br>
<button ng-click="x=''">Clear input</button>
</body>

AngularJS datetimepicker directive not work when change value

I have a problem with datetimepicker in AngularJS. When the page loaded, datetimepicker directive run, and I got the right value I want. But when I chose another date, directive does not work, although I have to change the event inside.
A few days ago, It worked, but not now. I tested many times. I don't know why, because I didn't change anything.
The code:
.directive("datetimeselect", [
"Config", function (Config) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, el, attr, ngModel) {
$(el).datetimepicker({
format: Config.defaultConfig.dateTimeFormat
});
el.on('dp.change', function (event) {
scope.$apply(function () {
var date = moment(event.date);
ngModel.$setViewValue(date.format(Config.defaultConfig.dateTimeFormat));
});
});
//format text from the user (view to model)
ngModel.$parsers.push(function (data) {
return moment(data).format(Config.defaultConfig.dateTimeFormat);
});
//format text going to user (model to view)
ngModel.$formatters.push(function (data) {
return moment(data).format(Config.defaultConfig.dateTimeFormat);
});
}
};
}
])
And this is HTML
<div class="form-group col-md-6">
<label for="ToTime" class="control-label">To Time</label>
<input type="text" class="form-control" name="ToTime" id="ToTime"
ng-model="record.ToTime" datetimeselect />
</div>
The $parser is unnecessary and the $formatter needs to set the date:
function postLink(scope, element, attr, ngModel) {
var ignoreChangeEvent = false;
element.datetimepicker();
element.on('dp.change', function(event) {
if (ignoreChangeEvent) {
ignoreChangeEvent = false;
return;
}
scope.$apply(function() {
ngModel.$setViewValue(event.date);
});
});
ngModel.$formatters.push(function (date) {
ignoreChangeEvent = true;
element.data("DateTimePicker").setDate(date);
});
}
The DEMO
angular.module('bootstrap-timepicker', [])
.directive('datetimepicker', [
function() {
return {
restrict: 'A',
link: postLink,
require: 'ngModel'
};
function postLink(scope, element, attr, ngModel) {
var ignoreChangeEvent = false;
element.datetimepicker();
element.on('dp.change', function(event) {
if (ignoreChangeEvent) {
ignoreChangeEvent = false;
return;
}
scope.$apply(function() {
ngModel.$setViewValue(event.date);
});
});
ngModel.$formatters.push(function (date) {
ignoreChangeEvent = true;
element.data("DateTimePicker").setDate(date);
});
}
}
])
.controller('IndexController', function($scope) {
$scope.date = new Date();
});
<link rel="stylesheet" href="//unpkg.com/bootstrap#3/dist/css/bootstrap.css">
<link rel="stylesheet" href="//unpkg.com/bootstrap#3/dist/css/bootstrap-theme.css">
<link rel="stylesheet" href="//unpkg.com/bootstrap-datetime-picker#2.3/css/bootstrap-datetimepicker.css">
<script src="//unpkg.com/jquery#2"></script>
<script src="//unpkg.com/bootstrap#3/dist/js/bootstrap.js"></script>
<script src="//unpkg.com/moment"></script>
<script src="//unpkg.com/eonasdan-bootstrap-datetimepicker#3/src/js/bootstrap-datetimepicker.js"></script>
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="bootstrap-timepicker">
<div class="container" ng-controller="IndexController">
<h4>Datetimepicker</h4>
<div class="form-group">
<div class='input-group date' datetimepicker ng-model="date">
<input type='text' class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<p>
ng-model value: {{date}}
</p>
<div class='input-group date' datetimepicker ng-model="date">
<input type='text' class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
</body>

How to run customed directive and normal ng-directive also

I have an input to confirm the email twice,
However, When I used the check-email directive and the required validation is not working any more.
Any suggestion? I don't want user keeps this field blank
html
<input type="text"
id="confirm_email_booking"
name="confirm_email_booking"
class="form-control"
check-email
ng-model="payment_contact.confirm_email_booking"
/>
JS
app.directive('checkEmail', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue, $scope) {
var notMatch = (viewValue != scope.form.email_booking.$viewValue)
ctrl.$setValidity('notMatch', !notMatch)
return notMatch;
})
}
}
})
You can just check if the value is present in your directive, as below:
var notMatch = viewValue && viewValue != scope.form.email_booking.$viewValue;
Then you could have something like this:
(function() {
"use strict";
angular
.module('app', [])
.controller('MainCtrl', MainCtrl)
.directive('checkEmail', checkEmail);
MainCtrl.$inject = ['$scope'];
function MainCtrl($scope) {
}
function checkEmail() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue, $scope) {
var notMatch = viewValue && viewValue != scope.form.email_booking.$viewValue;
ctrl.$setValidity('notMatch', !notMatch);
return notMatch;
})
}
}
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body ng-controller="MainCtrl">
<div class="col-md-12">
<form name="form">
<input type="text" id="email_booking" name="email_booking" class="form-control" ng-model="payment_contact.email_booking" />
<hr>
<input type="text" id="confirm_email_booking" name="confirm_email_booking" class="form-control" check-email ng-model="payment_contact.confirm_email_booking" required />
<span class="text-danger" ng-if="form.confirm_email_booking.$error.required">
Required!
</span>
<span class="text-danger" ng-if="form.confirm_email_booking.$error.notMatch">
NotMatch!
</span>
<pre ng-bind="form.confirm_email_booking | json"></pre>
</form>
</div>
</body>
</html>

AngularJS - write custom directive to validate passed values

I have an html form that looks like this :
<div class="row col-lg-offset-3">
<div class="form-group col-lg-6" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}" show-errors >
<label class="control-label">Age</label>
<input type="text" class="form-control" name="Age" ng-model="user.Age" ng-required='!user.phonenumber' placeholder="Age"/>
</div>
</div>
Directive:
(function(){
angular.module('myApp', [])
.controller('studentDataController', function($scope) {})
.directive('showErrors', function() {
return {
restrict: 'A',
require: '^form',
link: function (scope, el, attrs, formCtrl) {
var inputEl = el[0].querySelector("[Age]");
var inputNgEl = angular.element(inputEl);
var inputValue = inputNgEl.attr('Age');
var isValid = (inputValue >= 3 && inputValue < 100);
inputNgEl.bind('blur', function() {
el.toggleClass('has-error', isValid);
})
}
}
});
})();
I am trying to validate input for Age field when it blurs out.Age value should be between 3 to 99.i.i.e check if the value is valid or invalid when user is done typing and leaves the text field.Then if the value is invalid, apply the has- class
The directive though is not working. Did I miss anything ?
If really have to do that via custom directive please see below:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app
.directive('ngAge', NgLength);
function NgLength() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModel) {
$scope.$watch($attrs.ngModel, function(value) {
var isValid = (value > 3 && value < 100);
ngModel.$setValidity($attrs.ngModel, isValid);
});
}
}
}
/* Put your css in here */
.has-error {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<form name="userForm" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}">
<label class="control-label">Age</label>
<input type="text" class="form-control" name="Age" ng-model="user.Age" ng-age placeholder="Age" />
</form>
</body>
AngularJS 1.3.x introduces $validators pipeline - it is much simpler to write custom validation rules with them.
A collection of validators that are applied whenever the model value changes. The key value within the object refers to the name of the validator while the function refers to the validation operation. The validation operation is provided with the model value as an argument and must return a true or false value depending on the response of that validation.
var app = angular.module('app', []);
app
.controller('MainCtrl', function($scope) {
$scope.name = 'World';
}).directive('ngAge', function NgLength() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModel) {
ngModel.$validators.validAge = function(modelValue, viewValue) {
var age = modelValue || viewValue;
return age > 3 && age < 100
};
}
}
});
.has-error {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<body ng-app="app">
<form name="userForm" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}">
<label class="control-label">Age</label>
<input type="text" class="form-control" name="Age" ng-model="user.Age" ng-age placeholder="Age" />
</form>
</body>
You can use max, min directive. Please sample below
var app = angular.module('plunker', []);
.has-error {
background-color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link data-require="bootstrap-css#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<html ng-app="plunker">
<body>
<div class="row col-lg-offset-3">
<form name="userForm" class="form-group col-lg-6" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}" show-errors>
<label class="control-label">Age</label>
<input type="number" class="form-control" name="Age" ng-model="user.Age" ng-required='!user.phonenumber' placeholder="Age" max="100" min="3" />
</form>
</div>

Resources