I have created an Angular directive element with some inputs, and depending on the attributes of the element, the inputs should be set with default values. Here is the directive:
.directive('zoneType', ['$compile', function(){
restrict: "E",
require: "^?ngModel",
templateUrl: "zone.html",
link: function(scope, element, attrs, ngModel){
if(!ngModel) return;
var temp = 0;
var press = 0;
if(attrs.region=="top"){
temp = 60;
press = 2;
}else if(attrs.region=="bottom"){
temp = 20;
press = 0.4;
}
element.find("#gas1").val(temp);
element.find("#gas2").val(press);
ngModel.$setViewValue(element.html());
ngModel.$render();
}]);
and the template looks like this
<form role="form" class="form-inline">
<div class="form-group">
<input placeholder="Gas1" id="gas1" class="form-control" type="number" ng-model="$root.zone[$index].gas1"/>
</div>
<div class="form-group">
<input placeholder="Gas2" id="gas2" class="form-control" type="number" ng-model="$root.zone[$index].gas2"/>
</div>
</form>
The $index is necessary because the form is inside an angular Tabset.
I'm declaring the element like this
<zone-type region='top' ng-model='zone'></zone-type>
The template is loading correctly, but the values are not being set, is this the right way to do it?
Try this:
.directive('zoneType', ['$compile', function() {
restrict: "E",
require: "^?ngModel", // <<<<< don't know if you need this.
templateUrl: "zone.html",
link: function(scope, element, attrs, ngModel) {
scope.temp = 0;
scope.press = 0;
if (attrs.region == "top") {
scope.temp = 60;
scope.press = 2;
} else if (attrs.region == "bottom") {
scope.temp = 20;
scope.press = 0.4;
}
}]);
And your html should be:
<form role="form" class="form-inline">
<div class="form-group">
<input placeholder="Gas1" id="gas1" class="form-control" type="number" ng-model="temp"/>
</div>
<div class="form-group">
<input placeholder="Gas2" id="gas2" class="form-control" type="number" ng-model="press"/>
</div>
</form>
You really don't need id="gas1" and id="gas2" unless you have a need to use them in your code. Angular will do the two way binding because you have ng-model.
When using ng-model, Angular will bind temp to any scope.temp.
So later in your code, if you change temp like scope.temp = 'some value', that value is shown in the browser automatically, although you might have to call scope.$apply() or scope.$digest().
Related
I have a form input. When the page is loaded the input has "ng-readonly=true" property and it only shows the data.
When I double click (ng-dblclick) the property "ng-readonly" changes to false and I can edit the input.
For all this, it is working currectly. But when the data
(ng-model="school.fax") a row data is empty it does do a focus, and I need to click on the input to focus and start writing.
It does not happen when the data is not empty (ng-model="school.fax" have value, get value from server API) and in this case, it's working correctly
The question:
How can I focus on the empty input and start writing without need to click the input row?
The code:
HTML
<label>
<input class="inputs"
type="text"
ng-readonly="!edit_school_fax"
ng-dblclick="editSchoolFax(true)"
ng-model="school.fax"/>
</label>
JS
$scope.editSchoolFax = function(edit) {
$scope.edit_school_fax = edit;
};
FYI
I try, and it does not work for me:
Add "autofocus" inside the input
<input autofocus
Use directive like this solution: LINK
add custom directive
link(scope, element, attrs) {
scope.$watch(attrs.someAttrs, (newVal, oldVal) => {
if (newVal === true && newVal !== oldVal) {
$timeout(() => {
element
.focus()
.select();
});
}
});
},
Use a custom directive that adds a focus method to the ngModelController:
app.directive("inputFormFocus", function() {
return {
require: "ngModel",
link: postLink
};
function postLink (scope, elem, attrs, ngModel) {
console.log("postLink");
console.log(ngModel);
ngModel.focus = function() {
elem[0].focus();
}
}
})
Usage
<form name="form1">
<input input-form-focus
name="fax"
class="inputs"
type="text"
ng-readonly="!edit_school_fax"
ng-dblclick="editSchoolFax(true)"
ng-model="school.fax"/>
</form>
$scope.form1.fax.focus();
The DEMO
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.editSchoolFax = function(edit) {
$scope.edit_school_fax = edit;
};
$scope.school = { fax: "555-100-1234" };
$scope.faxFocus = function() {
$scope.edit_school_fax = true;
$scope.form1.fax.focus();
};
})
.directive("inputFormFocus", function() {
return {
require: "ngModel",
link: postLink
};
function postLink (scope, elem, attrs, ngModel) {
ngModel.focus = function() {
console.log(attrs.name + " focus");
elem[0].focus();
}
}
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-controller="ctrl">
<form name="form1">
<input input-form-focus
name="fax"
class="inputs"
type="text"
ng-readonly="!edit_school_fax"
ng-dblclick="editSchoolFax(true)"
ng-model="school.fax"/>
</form>
<button ng-click="faxFocus()">Focus and Edit</button>
</body>
I have this angular component where I like to add a custom input validator (see plunker).
I'm trying to access the ngModelController in the $onInit function. But it seams that the form is not populated at this time. Later on in the sendEmail() function it's no problem to access the the input model controller. How can I access the ngModelController and add a custom validator?
emailInput.js
(function(angular) {
'use strict';
function EmailInputController($log) {
var ctrl = this;
ctrl.$onInit = function() {
// ctrl.myForm.myEmailInput is not populated
//$log.debug("Email view value is: "+(ctrl.myForm.myEmailInput.$viewValue));
};
ctrl.sendEmail = function() {
$log.debug("EmailInputController.sendEmail");
$log.debug("Email view value is: " + (ctrl.myForm.myEmailInput.$viewValue));
};
}
angular.module('emailInputApp').component('emailInput', {
templateUrl: 'emailInput.html',
controller: EmailInputController,
});
})(window.angular);
emailInput.html
<form name="$ctrl.myForm">
<label>Email:</label>
<input name="myEmailInput" type="email" ng-model="$ctrl.email" required maxlength="15">
<button type="button" ng-click="$ctrl.sendEmail()">Send Email</button>
<p>Your Email addres is {{$ctrl.email}}</p>
<div ng-messages="$ctrl.myForm.myEmailInput.$error" role="alert">
<div ng-message="required">Please enter an email address.</div>
<div ng-message="email">This field must be a valid email address.</div>
<div ng-message="maxlength">This field can be at most 15 characters long.</div>
</div>
<code>
{{$ctrl.myForm.myEmailInput | json}}
</code>
</form>
http://plnkr.co/edit/YQfGAsix1DON4ff3EWxz?p=preview
You can add watcher and remove it when not needed anymore.
var removeWatch = $scope.$watch('$ctrl.myForm', function () {
$log.debug("Email view value is: " + (ctrl.myForm.myEmailInput.$modelValue));
removeWatch();
});
app.directive('validateEmail', function() {
var EMAIL_REGEXP = /^[_a-z0-9]+(\.[_a-z0-9]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/;
return {
require: 'ngModel',
restrict: '',
link: function(scope, elm, attrs, ctrl) {
// only apply the validator if ngModel is present and Angular has added the email validator
if (ctrl && ctrl.$validators.email) {
// this will overwrite the default Angular email validator
ctrl.$validators.email = function(modelValue) {
return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
};
}
}
};
});
And simply add
<input type='email' validate-email name='email' id='email' ng-model='email' required>
I am creating a project using AngularJS and I want to integrate validation in AngularJS. My requirement is that the number should be between the 1-4096 in AngularJS.
Here is my code:
<div class="col-lg-6 col-md-6">
<input type="text" class="form-control" placeholder="VLAN ID" ng-model="exchange.vlanId" valid-number/>
</div>
You should create very simple directive that would allow to validate input in reusable, configurable and declarative way.
You already have valid-number attribute, so the implementation can look like:
angular.module('demo', []).directive('validNumber', [function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
if (!ctrl) return;
var range = attrs.validNumber.split(',').map(Number);
ctrl.$validators.validNumber = function(value) {
return value >= range[0] && value <= range[1];
};
}
};
}]);
.error {color: brown;}
<script src="https://code.angularjs.org/1.4.8/angular.min.js"></script>
<div ng-app="demo">
<form name="form">
<input type="text" class="form-control" placeholder="VLAN ID" name="vlanId"
ng-model="exchange.vlanId" valid-number="1,4096" />
</form>
<div class="error" ng-show="form.$dirty && form.vlanId.$error.validNumber">VLAN ID should be in range 1-4096.</div>
</div>
You can bind an event on the input and call a function with passing the model in it:
<input type="text" class="form-control" placeholder="VLAN ID"
ng-model="exchange.vlanId"
ng-keydown="obj.validate(exchange.vlanId)" valid-number/>
Now in the controller you can define a method:
yourApp.controller('theController', ['$scope', function($scope){
$scope.obj = {
validate:function(val){
if(val < 1 || val > 4096){
alert(val+' is out of range');
}
}
};
}]);
And the directive valid-number can also be used:
yourApp.directive('validNumber', function($scope){
return {
restrict:'E',
link:function(scope, el, attrs){
el.on('keydown', function(){
el.css('border', function(){
return scope.exchange.vlanId < 1 || scope.exchange.vlanId > 4096
? "red" : "green";
});
});
}
};
});
What code changes need to be made to get the custom countparens directive below to provide the extra custom string validation shown below during form validation? The code below DOES successfully alert the user when the input field is empty, but it IS NOT alerting the user when the number of open parens ( and close parens ) is not equal.
I am using AngularJS. I used the documentation at this link (scroll to bottom) to design the code below.
Here is the html for the form:
<table>
<tr>
<td width=200>
<form name="userForm" ng-submit="rectangularForm(userForm.$valid)" novalidate>
<input type="text" name="fieldname" ng-model="nameofjsontype.fieldname" required />
<p ng-show="userForm.fieldname.$invalid && !userForm.fieldname.$pristine" class="help-block">Function is a required field.</p>
<span ng-show="userForm.nameofjsontype.fieldname.$error.countparens">The #( != #) !</span>
<br>
<button type="submit" ng-disabled="userForm.$invalid" >Click to submit</button>
</form>
</td>
</tr>
</table>
The javascript file containing the directive includes:
// create angular app
var myApp = angular.module('myApp', []);
// create angular controller
myApp.controller('myController', ['$scope', '$http', function($scope, $http) {
$scope.nameofjsontype = {type:"nameofjsontype", fieldname: 'some (value) here.'};
$scope.rectangularForm = function(isValid) {
// check to make sure the form is completely valid
if (isValid) {
var funcJSON = {type:"nameofjsontype", fieldname: $scope.nameofjsontype.fieldname};
$http.post('/server/side/controller', funcJSON).then(function(response) {
$scope.nameofjsontype = response.data;
});
}
};
}]);
myApp.directive('countparens', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$validators.countparens = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
// consider empty models to be valid
return true;
}
if (
($scope.nameofjsontype.fieldname.match(/\)/g).length) == ($scope.nameofjsontype.fieldname.match(/\(/g).length)
) {
// it is valid
return true;
}
// it is invalid
return false;
};
}
};
});
Your markup should be using userForm.fieldname.$error.countparens to show the error. The field bound to the userForm is NOT the same as your ngModel value. See plunker for what I mean
<span ng-show="userForm.fieldname.$error.countparens" class="help-block">The #( != #) !</span>
You are also not using your directive on your input element:
<input type="text" name="fieldname" ng-model="nameofjsontype.fieldname" required data-countparens=""/>
In your directive
you should be using modelValue and not the scope value when doing your matching AND
you need to cater for when there are no matches to ( or )
.
myApp.directive('countparens', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$validators.countparens = function(modelValue, viewValue) {
return ctrl.$isEmpty(modelValue) ||
((modelValue.match(/\)/g) || []).length == (modelValue.match(/\(/g) || []).length);
};
}
};
});
I am trying to write custom directive for USA telephone number using angularjs and need to preserve the data type of the field as integer.Here is the jsfiddle directive and need help to complete the directive.
If user enters a valid telephone no (exactly 10 numbers ie.1234567890) then input should split into 3 chunks as 123-456-7890 when the user moves to next control.otherewise I should show error message "not a valid number".
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
<input type="text" ng-model="telephone" phoneformat name="input1" />
<span class="error" ng-show="myForm.input1.$error.telephone">Numbers only!</span>
<span class="error" ng-show="myForm.input1.$error.telephone">Exact 10 Numbers only!</span>
</form>
</div>
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.telephone = "1234567890";
}]);
myApp.directive("phoneformat", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attr, ngModelCtrl) {
var phoneformat = function () {
}
}
};
});
It looks like you want to leverage the $error property of the form to drive validation. To do this, you will need to call $setValidity in the ngModelCtrl that you have required into your directive:
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.telephone = "1234567890";
}]);
myApp.directive("phoneformat", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attr, ngModelCtrl) {
//Parsing is performed from angular from view to model (e.g. update input box)
//Sounds like you just want the number without the hyphens, so take them out with replace
var phoneParse = function (value) {
var numbers = value && value.replace(/-/g, "");
if (/^\d{10}$/.test(numbers)) {
return numbers;
}
return undefined;
}
//Formatting is done from view to model (e.g. when you set $scope.telephone)
//Function to insert hyphens if 10 digits were entered.
var phoneFormat = function (value) {
var numbers = value && value.replace(/-/g,"");
var matches = numbers && numbers.match(/^(\d{3})(\d{3})(\d{4})$/);
if (matches) {
return matches[1] + "-" + matches[2] + "-" + matches[3];
}
return undefined;
}
//Add these functions to the formatter and parser pipelines
ngModelCtrl.$parsers.push(phoneParse);
ngModelCtrl.$formatters.push(phoneFormat);
//Since you want to update the error message on blur, call $setValidity on blur
element.bind("blur", function () {
var value = phoneFormat(element.val());
var isValid = !!value;
if (isValid) {
ngModelCtrl.$setViewValue(value);
ngModelCtrl.$render();
}
ngModelCtrl.$setValidity("telephone", isValid);
//call scope.$apply() since blur event happens "outside of angular"
scope.$apply();
});
}
};
});
Working fiddle. This was just a quick way of demonstrating the parser and formatter pipelines that are used in ngModel, along with $setValidity -- which is used to populate the $error field(s).
Update: To use this same phone validation across multiple phones, use form with $error. Notice that each input gets a unique name that is used with myForm (name of form). Both use $error.telephone:
<form name="myForm">
Mobile Phone:
<input type="text" ng-model="mobilephone" phoneformat name="mobilephone" />
<span class="error" ng-show="myForm.mobilephone.$error.telephone">
Exact 10 Numbers only!
</span>
<br />
Home Phone:
<input type="text" ng-model="homephone" phoneformat name="homephone" />
<span class="error" ng-show="myForm.homephone.$error.telephone">
Exact 10 Numbers only!
</span>
</form>
Updated fiddle.
You might want to use http://angular-ui.github.io/ui-utils/ Mask directive.
Working Fiddle: http://jsfiddle.net/HB7LU/6581/
myApp.directive("phoneFormat", function () {
return {
restrict: "A",
link: function (scope, element, attr) {
element.bind('change', function() {
if ( this.value.length === 10 ) {
var number = this.value;
this.value = number.substring(0,3) + '-' + number.substring(3,6) + '-' + number.substring(6,10)
}
else {
document.querySelector('.helpblock').innerHTML = 'error in formatting';
}
});
}
};
});
Iv'e extended your original fiddle. here's the result:
http://jsfiddle.net/10k58awt/
You can find splittedNumber array (contains 3 parts of number) on form submission
js:
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl", ["$scope", function ($scope) {
$scope.telephone = "1234567890";
$scope.submit = function () {
var splittedNumber = [$scope.telephone.substring(0, 3), $scope.telephone.substring(3, 6), $scope.telephone.substring(6, 10)];
// Do something with splitted number
console.log(splittedNumber);
};
}]);
myApp.directive("phoneformat", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (phoneInput) {
phoneInput = phoneInput.trim();
if (phoneInput && phoneInput.length == 10 && !isNaN(phoneInput)) {
ctrl.$setValidity('phoneformat', true);
return phoneInput;
} else {
ctrl.$setValidity('phoneformat', false);
return undefined;
}
});
}
};
});
html:
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm" novalidate ng-submit="myForm.$valid && submit()">
<input type="text" ng-model="telephone" phoneformat name="input1" /> <span class="error" ng-show="myForm.input1.$error.phoneformat">Invalid US Phone number!</span>
<div>
<button class="btn btn-primary" type="submit" ng-class="{'disabled': !myForm.$valid}">submit</button>
</div>
</form>
</div>