Ng-submit with textarea - angularjs

I have a form with only a text area. Is it possible to execute ng-submit when a user hits enter in the textarea? I'm able to accomplish this using ng-keyup but was wondering if there was a better solution.
<form ng-show="messages.conversation" ng-submit="messages.reply()">
<textarea class="msg-textarea" ng-model="messages.replyText"
ng-keyup="$event.keyCode == 13 ? messages.reply() : null">
</textarea>
<button type="submit" value="submit" class="btn-primary btn-sm btn-block"
ng-click="messages.reply()">Reply
</button>
</form>

#EpokK once solved the problem with the following code:
How to use a keypress event in AngularJS?
You need to add a directive, like this:
Javascript:
app.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.preventDefault();
}
});
};
});
HTML:
<div ng-app="" ng-controller="MainCtrl">
<input type="text" ng-enter="doSomething()">
</div>

Related

ng-show ng-hide using controller

I am trying to edit a field and convert label into text field on click of a button and change it back to label on keypress event (ng-keypress).
I am changing the ng-show variable through controller but it is not working.
HTML:
<div ng-app>
<div ng-controller="showCrtl">
<form>
<label ng-hide="editMode" >{{field}}</label>
<input ng-show="editMode" ng-keypress="changemode($event) " ng-model="field" >
<span class="pull-right" >
<button ng-click="editMode=true" class="btn-lg btn-warning" >edit </button> </span>
</form>
</div>
</div>
JS:
function showCrtl($scope){
$scope.field="Chanel";
$scope.changemode=function(event){
if(event.charCode==13){
$scope.editMode = false;
}
}
}
My updated JS-Fiddle link: http://jsfiddle.net/8Yz7S/281/
Use ng-blur instead of ng-keypress,
<input ng-show="editMode" ng-blur="changemode() " >
DEMO
EDIT:
Use the following directive to handle the enter key event,
app.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.preventDefault();
}
});
};
});
DEMO
Can you try the below solution.
<input ng-show="editMode" ng-keypress="changemode($event) " >
Added interval to update the view
function showCrtl($scope, $timeout){
$scope.changemode=function(event){
if(event.charCode==13){
$timeout(function() {
$scope.editMode = false;
}, 500);
}
}
}
http://jsfiddle.net/gsjsfiddle/hcu5mkhm/3/
The reason its not working for you is that, you are not preventing the default behavior of Enter key. So After changemode function is executed and editmode is set to false, click event of Edit button is also getting executed, setting editmode back to true.
All you need to do is call event.preventDefault(); as shown below:
function showCrtl($scope){
$scope.field="Chanel";
$scope.changemode=function(event){
if(event.charCode==13){
$scope.editMode = false;
event.preventDefault(); // <<<<<<<
}
}
}
To verify this behavior you can check this fiddle: http://jsfiddle.net/vnathalye/8Yz7S/301/
Try it after commenting the line event.preventDefault(); and check the console.
You want to obfuscate as much logic as possible from the view. So as he suggested, use
<input ng-show="editMode" ng-keypress="changemode($event)">
Then, do all your logic inside the changemode() function:
$scope.changemode = function(evt) {
$timeout(function() {$scope.editMode = false;},100);
}
http://jsfiddle.net/8Yz7S/293/

File name doesn't get cleared after form.$setPristine for a custom angular directive for file upload

I am using angular 1.5.8. After following some resources, I got the file upload working. I had to create a custom directive for that.
Directive
//file-upload-model-directive.js
'use strict';
export default function (app) {
app.directive('fileUploadModel', fileUploadModelDirective);
function fileUploadModelDirective () {
'ngInject';
return {
restrict: 'A',
link: linkFn,
require: 'ngModel'
};
function linkFn (scope, element, attrs, ngModel) {
element.bind('change', function(event){
var files = event.target.files;
var file = files[0];
ngModel.$setViewValue(file);
scope.$apply();
});
}
}
}
I am also using angular's form. And I have a "reset" button on this form. I want to clear all the form fields when clicked. And it happens with all form fields except file.
View
<form ng-submit="dataCtrl.upload(form)" name="form">
<div class="form-group" ng-class="{'has-error' : form.file.$invalid && !form.file.$pristine}">
<label>Select file</label>
<input type="file" name="file" ng-model="dataCtrl.newUpload.csvFile" file-upload-model required/>
</div>
<div class="form-group" ng-class="{'has-error' : form.comment.$invalid && !form.comment.$pristine}">
<label>Comment</label>
<textarea class="form-control" name="comment"
ng-model="dataCtrl.newUpload.comment" required></textarea>
</div>
<div class="form-group pull-right">
<button type="submit" class="btn btn-success" ng-disabled="form.$invalid">Upload</button>
<button class="btn btn-default" ng-click="dataCtrl.reset(form)" ng-disabled="!form.$dirty">Reset</button>
</div>
</form>
And the Controller
'use strict';
function DataController($log, catalogCnst, requestSV, $http) {
'ngInject';
this.reset = function(form) {
this.newUpload = {};
// form.file.$setViewValue(null); // this didn't work either
form.$setPristine()
};
this.upload = function(form) {
// some code
};
}
When "reset" is clicked, I see that
form.file.$pristine is false
form.file.$invalid is false
But I still see filename near the file upload element.
I also tried adding watch and handling event on the element in the directive
scope.$watch(attrs.fileUploadModel, function(value) {
console.log('attrs.file');
});
element.on('$pristine', function() {
console.log('destroy');
});
But they didn't get invoked.
How do I do this? Please guide me.
When you clear newUpload, file input does not get cleared. You need to do this separately.
See JSFiddle:
Basically, I added to the directive scope:
scope: {
model: '=ngModel'
},
... and watch:
scope.$watch('model', function(file) {
if (!file) {
element.val('');
}
});
Instead of using button tags, why not use input tags. This, in theory, might work.
<input type="submit" class="btn btn-success" ng-disabled="form.$invalid" value="Upload">
<input type="reset" class="btn btn-default" ng-click="dataCtrl.reset(form)" ng-disabled="!form.$dirty" value="Reset">

AngularJS: Hiding ng-message until hitting the form-submit button

This is a typical example of the use of ng-messages in AngularJS (1.x):
<form name="demoForm">
<input name="amount" type="number" ng-model="amount" max="100" required>
<div ng-messages="demoForm.amount.$error">
<div ng-message="required">This field is required</div>
</div>
<button type="submit">test submit</button>
</form>
see: http://jsfiddle.net/11en8swy/3/
I now want to change this example so the "This field is required" error only shows when the field is touched ($touched) or the user hits the submit button.
I cannot use the ng-submitted class on the form since the validation error prevents the submitting of the form.
How should I do this?
Thanks
You can do this using ng-show:
<div ng-messages="demoForm.amount.$error" ng-show="demoForm.amount.$touched">
<div ng-message="required">This field is required</div>
</div>
And use a custom directive. See a working demo:
var app = angular.module('app', ['ngMessages']);
app.controller('mainCtrl', function($scope) {
});
app.directive('hasFocus', function($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
element.on('focus', function() {
$timeout(function() {
ctrl.hasFocusFoo = true;
})
});
element.on('blur', function() {
$timeout(function() {
ctrl.hasFocusFoo = false;
})
});
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-messages.js"></script>
<body ng-app="app" ng-controller="mainCtrl">
<form name="demoForm">
<input name="amount" type="number" ng-model="amount" max="100" required has-focus>
<div ng-messages="demoForm.amount.$error" ng-show="demoForm.amount.$touched || demoForm.amount.hasFocusFoo">
<div ng-message="required">This field is required</div>
</div>
<button type="submit">test submit</button>
</form>
</body>
The directive is basically setting another hasFocusFoo field on the ngModel controller then we can easily use that directive.
Ah, at the PC at last.
https://plnkr.co/edit/EX3UmoAOKmTKlameBXRa?p=preview
<form name="mc.form">
<input type="text" name="empty" ng-model="mc.empty" required />
<label ng-show="mc.form.empty.$dirty && mc.form.empty.$error.required">i'm empty</label>
</form>
MainController.$inject = ['$timeout'];
function MainController($timeout) {
var vm = this;
$timeout(function(){
vm.form.$setPristine();
});
vm.submit = function(){
if(vm.form.$valid){
alert('yay');
}else{
(vm.form.$error.required || []).forEach(function(f){
f.$dirty = true;
});
}
}
}
Here is how I handle this task in my solution. form.$setPristine() - sets the field in a pristine state, so field isn't $dirty and error hidden. But after submit I manually state required fields in a $dirty state, so errors become visible. + if you type something, and delete it after, the error would be visible without submitting a form.

angular- bind form submit with multiple buttons

I have a form with multiple submit buttons:
<form name="myForm" customSubmit>
<input type="text" ng-minlength="2">
<button type="submit" ng-click="foo1()"></button>
<button type="submit" ng-click="foo2()"></button>
</form>
and a directive:
angular.module('customSubmit', [])
.directive('customSubmit', function() {
return {
require: '^form',
scope: {
submit: '&'
},
link: function(scope, element, attrs, form) {
element.on('submit', function() {
scope.$apply(function() {
form.$submitted = true;
if (form.$valid) {
return scope.submit();
}
});
});
}
};
});
my goal is to submit the form only when it's valid, with multiple submit buttons (i.e. I can't use the ng-submit directive in the form). The above code doesn't work. What is the correct way to do that? Is that even possible?
I'd suggest you to use one of the simpler way of doing it. Just check your form is valid or not on ng-click & if its valid call the desired method from it.
Markup
<form name="myForm" customSubmit>
<input type="text" ng-minlength="2">
<button type="button" ng-click="myForm.$valid && foo1()"></button>
<button type="button" ng-click="myForm.$valid && foo2()"></button>
</form>
But checking myForm.$valid on each click looks bit repeating code in number of times. Rather than that you could have one method in controller scope which will validate form and call desired method for submitting form.
Markup
<form name="myForm" customSubmit>
<input type="text" ng-minlength="2">
<button type="button" ng-click="submit('foo1')"></button>
<button type="button" ng-click="submit('foo2')"></button>
</form>
Code
$scope.submit = function(methodName){
if($scope.myForm.$valid){
$scope[methodName]();
}
}
In both the cases you could make you button type to button instead
of submit
Update
To make it generic you need to put it on each button instead of putting directive on form once.
HTML
<form name="myForm">
<input type="text" name="test" ng-minlength="2" ng-model="test">
<button custom-submit type="submit" fire="foo1()">foo1</button>
<button custom-submit type="submit" fire="foo2()">foo2</button>
</form>
Code
angular.module("app", [])
.controller('Ctrl', Ctrl)
.directive('customSubmit', function() {
return {
require: '^form',
scope: {
fire: '&'
},
link: function(scope, element, attrs, form) {
element.on('click', function(e) {
scope.$apply(function() {
form.$submitted = true;
if (form.$valid) {
scope.fire()
}
});
});
}
};
});
Plunkr
The solution was to put the directive on the submit button, and use directive 'require':
<form>
<button my-form-submit="foo()"></button>
</form>
angular.module('myFormSubmit', [])
.directive('myFormSubmit', function() {
return {
require: '^form',
scope: {
callback: '&myFormSubmit'
},
link: function(scope, element, attrs, form) {
element.bind('click', function (e) {
if (form.$valid) {
scope.callback();
}
});
}
};
});

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