AngularJs - show-hide password on click event using directive - angularjs

I have one input field for password and one button with that input field
now, if type of input field is passwordi.e type="password", then on click of that button it should become text i.e type="text"
if again I click on the same button it should change type="password"
Means it should toggle the value of type of input element
I have done this using controller, It's working fine with controller. below is the working code using controller
But instead of controller if i want to use directive then how to handle this toggle condition using directive
purpose - I want to use this functionality on multiple input elements
HTML
<div class="input-group">
<label>Password</label>
<input type="{{inputType}}" class="form-control" ng-model="password" />
<span ng-click="show()">show</span>
</div>
Controller
$scope.inputType = 'password';
$scope.show = function() {
if ($scope.inputType === 'password') {
$scope.inputType = !$scope.inputType;
$scope.inputType = 'text';
} else {
$scope.inputType = !$scope.inputType;
$scope.inputType = 'password';
}
}
I tried using Directive - Below is my trial code
I am not getting how to change the type of <input /> element using directive
Directive
.directive('myDir', function() {
require: 'ngModel',
link: function (scope, element, attrs) {
console.log(attrs.type);
attrs.type = 'password'
// how to call this below code on click event or on click of <span>
which I am using for password
if (attrs.type === 'password') {
attrs.type = !attrs.type;
attrs.type = 'text';
} else {
attrs.type = !attrs.type.inputType;
attrs.type = 'password';
}
}
})
HTML Using Directive
<div class="input-group">
<label>Password</label>
<input my-dir type="" class="form-control" ng-model="password" />
<span ng-click="show()">show</span>
</div>

You can use ng-attr-type directive for dynamically change the input type. For example:
<input ng-attr-type="{{ isPassword ? 'password' : 'text' }}">
you can change the value of isPassword to the click event and make it toggle.
Using directive
.directive('isPassword', function() {
return {
restrict : 'A',
scope: {
isPassword: '=isPassword'
},
link: function (scope, element, attrs) {
scope.$watch('isPassword', function(a, b){
element.attr('type', a ? 'password' : 'text')
})
}
}
});
<input is-password="checkPassword" placeholder="Put your password" />
<input type="checkbox" ng-model="checkPassword" />
update on button click
<button ng-click="checkPassword=!checkPassword">click</button>

This is what the following directive does when added to the input element.
It appends a span element "Show me" with ng-click=show() event attached to it.
scope: true enables an isolated scope for the directive. This makes sure the function show() is unique for each directive.
When clicked on "Show me", the directive changes the input type of that element.
Hope this helps.
JSfiddle link

Related

How to include input fields from custom directives in angular forms?

I need to create a simple form with validations like this - https://jsfiddle.net/rohansh20/k7omkz7p/2/
<div ng-app="module1" ng-controller="ctrl1 as vm">
<form novalidate name="vm.form1" class="css-form">
<label>Name:
<input type="text" name="Name" ng-model="vm.user.name" required />
</label>
<br />
<label>E-mail:
<input type="email" name="Email" ng-model="vm.user.email" required />
</label>
<br />
<input type="submit" ng-click="vm.save(vm.form1, vm.user)" value="Save" />
</form>
<div>
{{vm.result}}
</div>
<pre>form = {{vm.form1 | json}}</pre>
</div>
angular.module('module1', []);
angular.module('module1').controller('ctrl1', function() {
this.save = function(form, user) {
if(form.$invalid) {
this.result = 'Please correct the data entered';
return;
}
this.result = 'User ' + user.name + ' with email ' + user.email + ' saved successfully';
};
});
But I need to dynamically generate the input fields. So I have made a directive that transforms into any type of input field - https://jsfiddle.net/rohansh20/hdxj0np6/3/
<div ng-app="module1" ng-controller="ctrl1 as vm">
<form novalidate name="vm.form1" class="css-form">
<custom-input name="Name" type="text" model="vm.user.name" required="true">
</custom-input>
<br />
<custom-input name="Email" type="email" model="vm.user.email" required="true">
</custom-input>
<br />
<input type="submit" ng-click="vm.save(vm.form1, vm.user)" value="Save" />
</form>
<div>
{{vm.result}}
</div>
<pre>form = {{vm.form1 | json}}</pre>
</div>
var app = angular.module('module1', []);
app.controller('ctrl1', function() {
this.save = function(form, user) {
if(form.$invalid) {
this.result = 'Please correct the data entered';
return;
}
this.result = 'User ' + user.name + ' with email ' + user.email + ' saved successfully';
};
});
app.directive('customInput', function($compile) {
return {
restrict: 'E',
link: function(scope, element, attributes) {
var labelElement = angular.element('<label/>'),
name = attributes.name,
type = attributes.type,
ngModelString = attributes.model,
required = attributes.required,
inputElement = angular.element('<input/>');
inputElement.attr('ng-model', ngModelString);
inputElement.attr('name', name);
inputElement.attr('type', type);
if (required) {
inputElement.attr('required', 'required');
}
labelElement.append(name + ': ');
labelElement.append(inputElement);
$compile(labelElement)(scope);
element.replaceWith(labelElement);
}
}
});
The fiddles are simplified versions of what I'm trying to make.
The problem is that these fields, even though compiled and rendered perfectly(which can be seen by inspecting the HTML), are not getting included as part of the parent form control. This can be seen in the displayed form control object in both the fiddles. Because of this, the form validity cannot be determined and both forms behave differently on submitting invalid input.
I need the form control in the second fiddle to have correct values for its properties and to have the child controls and their properties like in the first fiddle. Is this even possible using a custom directive? What do I need to change to make this work?
Note - The directive would involve complex operations to dynamically create HTML, so it has to be done in the link function of a directive. A directive template with multiple ngIfs would just not work.
In order not to lose bindings from your parent form, include it in your custom form directive
In your directive
(function () {
'use strict';
angular
.module('myApp')
.directive('customInput', customInput)
customInput.$inject = ['$compile'];
/* #ngInject */
function customInput ($compile) {
var directive = {
templateUrl: 'app/custom-input.html',
restrict: 'E',
transclude: true,
require: "?^form",
compile: compile,
controller:CustomInputController,
controllerAs:'vm',
scope:{
inputType:'=',
inputValue:'='
}
};
return directive;
function CustomInputController($scope){
var vm = this;
}
function compile(element, attributes){
return {
pre: preLink,
post: postLink
}
}
function preLink (scope,element,attrs, form, transclude){
}
function postLink (scope,element,attrs, form, transclude){
scope.currentForm = form;
$compile(element.contents())(scope);
}
}
})();
In your directive html template
<input type="inputType" ng-model="inputValue">
When you call your directive
<br-input type="text"
input-value="vm.user.email"
inputname="name"
input-required ="true">
</br-input>

ng-type / show-password directive on `<input>` element in angularjs

We can use data-binding on input elements like this:
<input type="{{ showPassword ? 'text' : 'password' }}" name="password">
But this has similar problems as using data-binding on a href attribute (see ngHref). This way there is an input element in the dom with the type {{ showPassword ? 'text' : 'password' }} until angular loads. It looks convenient to have an ngType directive much like ngHref, what could be used this way:
<input type="password" ng-type="{{ showPassword ? 'text' : 'password' }}" name="password">
Is there any other way to do it? Do I have to implement this ngType thing?
Custom directive that changes the <input> type:
To show or hide the password use a custom directive:
app.directive("showPassword", function() {
return function linkFn(scope, elem, attrs) {
scope.$watch(attrs.showPassword, function(newValue) {
if (newValue) {
elem.attr("type", "text");
} else {
elem.attr("type", "password");
};
});
};
});
Usage
<input type=password show-password="showPassword"
ng-model="thePassword">
The show-password directive watches the defined scope variable and changes the input to type=text when truthy and back to type=password when falsey.
The DEMO
angular.module("myApp",[])
.directive("showPassword", function() {
return function linkFn(scope, elem, attrs) {
scope.$watch(attrs.showPassword, function(newValue) {
if (newValue) {
elem.attr("type", "text");
} else {
elem.attr("type", "password");
};
});
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app='myApp'>
<button ng-click="showPassword = true">Show Password</button><br>
<button ng-click="showPassword = false">Hide Password</button><br>
<input type=password show-password="showPassword"
ng-model="thePassword">
<hr>
PASSWORD == {{thePassword}}
</div>

how to hide value of input element if its $pristine

I have ng-model attached to , but i want to display a default placeholder value if it's not been touched ($pristine). Is there any good way to do it? I cannot simply set my ng-model value to null during initial.
Here's my plunker:
http://plnkr.co/edit/0kzKrwKTbJzsMGG8D1gQ?p=preview
<body ng-controller="inputController">
<input type="number" id="pricefield" min="0" name="price" placeholder="Price" ng-model="test.value" required/>
</body>
angular.module('plunker', []);
function inputController($scope) {
$scope.test = {value: 0};
}
You could use ng-attr directive to set placeholder value dynamically, to check the form element is pristine or not you need to place this field inside a form & then you could easily check the $pristine property of that form element like myForm.price.$pristine.
Markup
<form name="myForm">
<input type="number" id="pricefield" min="0" name="price" ng-model="test.value"
ng-attr-placeholder="{{myForm.price.$pristine ? 'Some Value': 'Default Value'}}" required/>
</form>
Demo Plunkr
Update
I'd suggest to have one directive that will change hide the $viewValue on initial load & will show placeholder. Directive will have controller over the display value using $formatters on ngModelControlller
Markup
<input type="number" custom-dir id="pricefield" min="0" name="price"
ng-attr-placeholder="{{myForm.price.$pristine ? 'Initial Placeholder': 'After change Placeholder'}}"
ng-model="test.value" required/>
Directive
app.directive('hideInitialLoad', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
var initalHide = true;
//format text going to user (model to view)
ngModel.$formatters.push(function(value) {
console.log(attr.min > value)
if (initalHide){
initalHide = false;
return undefined;
}
return value;
});
}
};
});
Updated Demo

How to create a directive for disable all elements into div element

how to create a directive for disable all elements into div element ?
something like this :
<div div-disabled div-disabled-condition="state=='Stack'||state=='Over'||state=='Flow'">
<input type="text"/>
<input type="url"/>
<div>
<input type="text"/>
<input type="url"/>
</div>
<div>
Is it possible? I have no idea .
angular
.module('uiRouterApp.ctrl.add', ['uiRouterApp.ctrl.customDirective'])
.controller('addCtrl', [
'$scope',
'$location',
'$stateParams',
'$state',
function ($scope, $location, $stateParams, $state) {
$scope.state = {};
}
]).directive('divDisabled', function () {
return {
scope: {
divDisabledCondition: '#'
},
link: function (scope, element, attrs) {
}
};
});
Update :
please see this :
<div class="col-sm-12 ng-isolate-scope" selected-object="SelectedAutoComplete" local-data="requirements.Item1" search-fields="NameFa,NameEn" title-field="NameFa" minlength="2" field-required="true" image-field="ImageUrl" disable-auto-compelete="response.State=='Success'||response.State=='Error'||response.State=='Warning'">
<div class="angucomplete-holder">
<input id="_value" ng-model="searchStr" type="text" placeholder="select" class="form-control ng-dirty" ng-focus="resetHideResults()" ng-blur="hideResults()" autocapitalize="off" autocorrect="off" autocomplete="off" ng-change="inputChangeHandler(searchStr)" ng-disabled="response.State=='Success'||response.State=='Error'||response.State=='Warning'" style="">
<!-- ngIf: showDropdown -->
</div>
</div>
directive :
.directive('contentsDisabled', function() {
return {
compile: function(tElem, tAttrs) {
var inputs = tElem.find('input');
for (var i = 0; i < inputs.length; i++) {
inputs.attr('ng-disabled', tAttrs['disableAutoCompelete']);
}
}
}
})
why When the state is 'Success' or 'Error' or 'Warning' Input not disabled ?
You can create a directive that alters its content during compile time by adding the condition. Something along these lines (untested):
module.directive('contentsDisabled', function() {
return {
compile: function(tElem, tAttrs) {
var inputs = tElem.find('input');
inputs.attr('ng-disabled', tAttrs['contentsDisabled']);
}
};
});
See a JSFiddle here: http://jsfiddle.net/HB7LU/6380/
This has the drawback that you just copy the expression from contents-disabled into ng-disabled attributes of any inputs - if somebody uses a directive that in turn creates <input> elements, you won't pick them up.
It'd be less fragile to get hold of the FormController instance and iterate through all its controls, but sadly AngularJS doesn't expose the controls in a form. Maybe file a feature request?
You also can use a tag fieldset :
<form>
<fieldset ng-disable="foo">
<input name="the_one"/>
<input name="the_second"/>
</fieldset>
<input name="the_thrid"/>
</form>
With this way, when the variable foo is TRUE, inputs "the_one" and "the_second" will be disabled.
Why don't you use ng-disabled on your required expression on each input?
https://docs.angularjs.org/api/ng/directive/ngDisabled
If you truly do want a grouping directive, use the compile function of the directive to insert the ng-disabled attribute on each child. Or use a paren't child directive to signify which children to apply the ng-disabled to.
There is a new option to control enable/disable input field for angucomplete-alt.
http://ghiden.github.io/angucomplete-alt/#example13

Submit form on pressing Enter with AngularJS

In this particular case, what options do I have to make these inputs call a function when I press Enter?
Html:
<form>
<input type="text" ng-model="name" <!-- Press ENTER and call myFunc --> />
<br />
<input type="text" ng-model="email" <!-- Press ENTER and call myFunc --> />
</form>
// Controller //
.controller('mycontroller', ['$scope',function($scope) {
$scope.name = '';
$scope.email = '';
// Function to be called when pressing ENTER
$scope.myFunc = function() {
alert('Submitted');
};
}])
Angular supports this out of the box. Have you tried ngSubmit on your form element?
<form ng-submit="myFunc()" ng-controller="mycontroller">
<input type="text" ng-model="name" />
<br />
<input type="text" ng-model="email" />
</form>
EDIT: Per the comment regarding the submit button, see Submitting a form by pressing enter without a submit button which gives the solution of:
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;"/>
If you don't like the hidden submit button solution, you'll need to bind a controller function to the Enter keypress or keyup event. This normally requires a custom directive, but the AngularUI library has a nice keypress solution set up already. See http://angular-ui.github.com/
After adding the angularUI lib, your code would be something like:
<form ui-keypress="{13:'myFunc($event)'}">
... input fields ...
</form>
or you can bind the enter keypress to each individual field.
Also, see this SO questions for creating a simple keypres directive:
How can I detect onKeyUp in AngularJS?
EDIT (2014-08-28): At the time this answer was written, ng-keypress/ng-keyup/ng-keydown did not exist as native directives in AngularJS. In the comments below #darlan-alves has a pretty good solution with:
<input ng-keyup="$event.keyCode == 13 && myFunc()"... />
If you want to call function without form you can use my ngEnter directive:
Javascript:
angular.module('yourModuleName').directive('ngEnter', function() {
return function(scope, element, attrs) {
element.bind("keydown keypress", function(event) {
if(event.which === 13) {
scope.$apply(function(){
scope.$eval(attrs.ngEnter, {'event': event});
});
event.preventDefault();
}
});
};
});
HTML:
<div ng-app="" ng-controller="MainCtrl">
<input type="text" ng-enter="doSomething()">
</div>
I submit others awesome directives on my twitter and my gist account.
If you only have one input you can use the form tag.
<form ng-submit="myFunc()" ...>
If you have more than one input, or don't want to use the form tag, or want to attach the enter-key functionality to a specific field, you can inline it to a specific input as follows:
<input ng-keyup="$event.keyCode == 13 && myFunc()" ...>
I wanted something a little more extensible/semantic than the given answers so I wrote a directive that takes a javascript object in a similar way to the built-in ngClass:
HTML
<input key-bind="{ enter: 'go()', esc: 'clear()' }" type="text"></input>
The values of the object are evaluated in the context of the directive's scope - ensure they are encased in single quotes otherwise all of the functions will be executed when the directive is loaded(!)
So for example:
esc : 'clear()' instead of esc : clear()
Javascript
myModule
.constant('keyCodes', {
esc: 27,
space: 32,
enter: 13,
tab: 9,
backspace: 8,
shift: 16,
ctrl: 17,
alt: 18,
capslock: 20,
numlock: 144
})
.directive('keyBind', ['keyCodes', function (keyCodes) {
function map(obj) {
var mapped = {};
for (var key in obj) {
var action = obj[key];
if (keyCodes.hasOwnProperty(key)) {
mapped[keyCodes[key]] = action;
}
}
return mapped;
}
return function (scope, element, attrs) {
var bindings = map(scope.$eval(attrs.keyBind));
element.bind("keydown keypress", function (event) {
if (bindings.hasOwnProperty(event.which)) {
scope.$apply(function() {
scope.$eval(bindings[event.which]);
});
}
});
};
}]);
Another approach would be using ng-keypress ,
<input type="text" ng-model="data" ng-keypress="($event.charCode==13)? myfunc() : return">
Submit an input on pressing Enter with AngularJS - jsfiddle
Very good, clean and simple directive with shift + enter support:
app.directive('enterSubmit', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('keydown', function(event) {
var code = event.keyCode || event.which;
if (code === 13) {
if (!event.shiftKey) {
event.preventDefault();
scope.$apply(attrs.enterSubmit);
}
}
});
}
}
});
If you want data validation too
<!-- form -->
<form name="loginForm">
...
<input type="email" ng-keyup="$loginForm.$valid && $event.keyCode == 13 && signIn()" ng-model="email"... />
<input type="password" ng-keyup="$loginForm.$valid && $event.keyCode == 13 && signIn()" ng-model="password"... />
</form>
The important addition here is $loginForm.$valid which will validate the form before executing function. You will have to add other attributes for validation which is beyond the scope of this question.
Good Luck.
Just wanted to point out that in the case of having a hidden submit button, you can just use the ngShow directive and set it to false like so:
HTML
<form ng-submit="myFunc()">
<input type="text" name="username">
<input type="submit" value="submit" ng-show="false">
</form>
Use ng-submit and just wrap both inputs in separate form tags:
<div ng-controller="mycontroller">
<form ng-submit="myFunc()">
<input type="text" ng-model="name" <!-- Press ENTER and call myFunc --> />
</form>
<br />
<form ng-submit="myFunc()">
<input type="text" ng-model="email" <!-- Press ENTER and call myFunc --> />
</form>
</div>
Wrapping each input field in its own form tag allows ENTER to invoke submit on either form. If you use one form tag for both, you will have to include a submit button.
Will be slightly neater using a CSS class instead of repeating inline styles.
CSS
input[type=submit] {
position: absolute;
left: -9999px;
}
HTML
<form ng-submit="myFunc()">
<input type="text" ng-model="name" />
<br />
<input type="text" ng-model="email" />
<input type="submit" />
</form>
FWIW - Here's a directive I've used for a basic confirm/alert bootstrap modal, without the need for a <form>
(just switch out the jQuery click action for whatever you like, and add data-easy-dismiss to your modal tag)
app.directive('easyDismiss', function() {
return {
restrict: 'A',
link: function ($scope, $element) {
var clickSubmit = function (e) {
if (e.which == 13) {
$element.find('[type="submit"]').click();
}
};
$element.on('show.bs.modal', function() {
$(document).on('keypress', clickSubmit);
});
$element.on('hide.bs.modal', function() {
$(document).off('keypress', clickSubmit);
});
}
};
});
you can simply bind #Hostlistener with the component, and rest will take care by it. It won't need binding of any method from its HTML template.
#HostListener('keydown',['$event'])
onkeydown(event:keyboardEvent){
if(event.key == 'Enter'){
// TODO do something here
// form.submit() OR API hit for any http method
}
}
The above code should work with Angular 1+ version
I focused to below row input in the table
<input ng-keydown="$event.keyCode == 13 && onPressEnter($event)" id="input_0" type="text" >
$scope.onPressEnter = function (event) {
let inputId = event.target.id;
let splited = inputId.split('_');
let newInputId = 'input' + '_' + ((+splited[1]) + 1);
if (document.getElementById(newInputId))
document.getElementById(newInputId).focus();
// else submit form
}

Resources