Shift+Enter in Textarea using AngularJS - javascript

This code shows how to use a directive to submit a form by hitting 'enter' while in a textarea. However, I would like to be able to shift+enter and go to the next line and submit the result as it is. Whenever the submission is made, it shows up in the same line. How do I submit and show the submitted text in the next line as the user intends.
<div ng-app="testApp" ng-controller="MyController">
<textarea ng-model="foo" enter-submit="submit()"></textarea><br/>
Last submitted text: {{ lastSubmitted }}<br/>
</div>
The AngularJS code:
var app = angular.module('testApp', []);
function MyController($scope) {
$scope.foo = ""
$scope.lastSubmitted = ""
$scope.submit = function() {
$scope.lastSubmitted = $scope.foo;
}
}
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);
}
}
});
}
}
});
What should I do?

It looks like you need to convert \n\r into <br/> then use ng-bind-html to sanitize the string.
Here is a code example
You will also have to include the angularjs sanitize js file:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular-sanitize.js"></script>

Related

How to use the Angular jQuery Validate's checkForm() function

EDIT:
I've added a JsFiddle so you can easily troubleshoot instead of having to set up the environment yourself. As you can see, validation is done on the Email field even before the blur event on the input element, which was triggered by the $scope.Email being changed. If you comment out the ng-show="!mainForm.validate()" on the <p> element, you'll see that the issue doesn't take place.
I am using the Angular implementation of jQuery Validate, and I am in need of the ability to check if a form is valid without showing the error messages. The standard solution I've seen online is to use jQuery Validate's checkForm() function, like this:
$('#myform').validate().checkForm()
However, the Angular wrapper I'm using doesn't currently implement the checkForm function. I have been trying to modify the source code to bring it in, and I'm afraid I'm in over my head. The code is small and simple enough that I'll paste it here:
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
//This is the part I've tried adding in.
//It runs, but still shows error messages when executed.
//form.checkForm = function() {
// return validator.checkForm();
//}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
I want to be able to use it to show or hide a message, like this:
<p class="alert alert-danger" ng-show="!mainForm.checkForm()">Please correct any errors above before saving.</p>
The reason I don't just use !mainForm.validate() is because that causes the error messages to be shown on elements before they are "blurred" away from, which is what I'm trying to avoid. Can anyone help me implement the checkForm() function into this angular directive?
You can add checkForm() function to the plugin as following.
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.checkForm = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.checkForm();
validator.submitted = {};
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
Please find the updated jsFiddle here https://jsfiddle.net/b2k4p3aw/
Reference: Jquery Validation: Call Valid without displaying errors?
If I understand your question correctly, you want to be able to show an error message when the email adress is invalid and you decide you want to show the error message.
You can achieve this by setting the input type to email like this <input type=email>
Angular adds an property to the form $valid so you can check in your controller if the submitted text is valid. So we only have to access this variable in the controller and invert it. (Because we want to show the error when it is not valid)
$scope.onSubmit = function() {
// Decide here if you want to show the error message or not
$scope.mainForm.unvalidSubmit = !$scope.mainForm.$valid
}
I also added a submit button that uses browser validation on submit. This way the onSubmit function won't even get called and the browser will show an error. These methods don't require anything except angularjs.
You can check the updated JSFiddle here
Make sure to open your console to see when the onSubmit function gets called and what value gets send when you press the button.
You can use $touched, which is true as soon as the field is focused then blurred.
<p class="alert alert-danger" ng-show="mainForm.Email.$touched && !mainForm.validate()">Please correct any errors above before saving.</p>
you can achieve onblur event with ng-show="mainForm.Email.$invalid && mainForm.Email.$touched" to <p> tag
by default mainForm.Email.$touched is false, on blur it will change to true
for proper validation change the <input> tag type to email
you can add ng-keydown="mainForm.Email.$touched=false" if you don't want to show error message on editing the input tag
I didn't used angular-validate.js plugin
<div ng-app="PageModule" ng-controller="MainController" class="container"><br />
<form method="post" name="mainForm" ng-submit="OnSubmit(mainForm)" >
<label>Email:
<input type="email" name="Email" ng-keydown="mainForm.Email.$touched=false" ng-model="Email" class="email" />
</label><br />
<p class="alert alert-danger" ng-show="mainForm.Email.$invalid && mainForm.Email.$touched">Please correct any errors above before saving.</p>
<button type="submit">Submit</button>
</form>
</div>
Updated code : JSFiddle
AngularJs Form Validation
More info on Angular validation
Update 2
checkForm will return whether the form is valid or invalid
// added checForm, also adds valid and invalid to angular
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
to hide default messages adding by jQuery validation plugin add below snippet, to $.validator.setDefaults
app.config(function ($validatorProvider) {
$validatorProvider.setDefaults({
errorPlacement: function(error,element) { // to hide default error messages
return true;
}
});
});
here is the modified plugin looks like
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
var formName = validator.currentForm.name;
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
// added checkForm
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
controller
app.controller("MainController", function($scope) {
$scope.Email = "";
$scope.url = "";
$scope.isFormInValid = false; // to hide validation messages
$scope.OnSubmit = function(form) {
// here you can determine
$scope.isFormInValid = !$scope.mainForm.checkForm();
return false;
}
})
need to have following on every input tag(example for email)
ng-show="isFormInValid && !mainForm.Email.$invalid "
if the form and email both are invalid the validation message shows up.
JSFiddle
try this code for validation this is the form
<form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate>
<div class="form-group">
<input type="text" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }" ng-model="name" name="name" class="form-control" placeholder="{{ 'regName' | translate }}" required>
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">Your name is required.</p>
</div>
<div class="form-group">
<input type="tel" ng-class="{ 'has-error' : userForm.mob.$invalid && !userForm.mob.$pristine }" ng-model="mob" class="form-control" name="mob" ng-maxlength="11" ng-minlength="11" ng-pattern="/^\d+$/" placeholder="{{ 'regPhone' | translate }}" required>
<p ng-show="userForm.mob.$invalid && !userForm.mob.$pristine" class="help-block">Enter a valid number</p>
</div>
<div class="form-group">
<input type="email" ng-model="email" name="email" class="form-control" placeholder="{{ 'regEmail' | translate }}" required>
<p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
</div>
<div class="form-group">
<input type="password" ng-model="pass" name="pass" class="form-control" placeholder="{{ 'regPass' | translate }}" minlength="6" maxlength="16" required>
<p ng-show="userForm.pass.$invalid && !userForm.pass.$pristine" class="help-block"> Too short Min:6 Max:16</p>
<input type="password" ng-model="repass" class="form-control" ng-minlength="6" placeholder="{{ 'regConPass' | translate }}" ng-maxlength="16" required>
</div>
<button class="loginbtntwo" type="submit" id="regbtn2" ng-disabled="userForm.$dirty && userForm.$invalid" translate="signUp" ></button>
</form>
You will need to modify the Angular Validate Plugin a bit. Here is a working version of your code in JSFiddle. Note the updated plugin code as well as a pair of modifications to your original code.
Updated plugin code simply adds this to validator.SetDefaults parameter:
errorPlacement: function(error,element) { return true; } // to hide default error message
Then we use a scope variable to hide/show the custom error message:
$scope.OnSubmit = function(form) {
if (form.$dirty) {
if (form.validate()) {
//form submittal code
} else {
$scope.FormInvalid = true;
}
}

angular directive does not work with input type = "number"

The code below works only when the input type is text, and it doesn't work when the type is number.
<div ng-app="myApp" ng-controller="myCtrl as model">
<input type="text" ng-model="cero" ng-decimal >
</div>
angular
.module("myApp",[])
.controller('myCtrl', function($scope){
var model=this;
})
.directive('ngDecimal', function ($parse) {
var linkFunction =function(scope, element, attrs){
element.bind("keypress", function(event) {
if(event.which === 13) {
scope.$apply(function(){
scope.$eval(attrs.format, {'event': event});
if(scope.cero===undefined || scope.cero===''){
scope.cero="0.",
event.preventDefault();
}else{
}
});
}
});
};
return{
restrict : 'A',
scope:{
cero: '=ngModel'
},
link: linkFunction
}
});
What I need help with is changing the type to number and still making the code work. The code is also on CodePen.
Updated pen : http://codepen.io/anon/pen/QKOVkP?editors=1011
Works with number, constraint being you cannot assign
scope.cero = "0." // string value
to a type="number" so replace it with the minimum number you want to assign, maybe
scope.cero = parseFloat("0.01") // parseFloat("0.") won't work
In the else condition add this.
scope.cero = parseFloat(scope.cero).toFixed(2);
Convert string to decimal
Here is the code: working code

Form validation with Bootstrap and AngularJS

I'm trying to unite the AngularJS validation model with the Bootstrap form validation display.
If a user loads an empty form, I don't want the form to display error message right away. I want to wait until the user interacts with the form.
If a user submit the form with required fields not filled out, I also want to display an error message.
If a user starts typing in the field, I want error messages to show up right away.
So I have to check myForm.$submitted, myForm.<fieldName>.$dirty as well as myForm.<fieldName>.$touched.
However, it makes a lot of duplicated code with very few variation.
I've tried to make a directive to fix this issue but I can't seem to find the right way to wrap this complexity away.
HTML:
<div class="form-group required" ng-class="{ 'has-error': myForm.firstname.$invalid && (myForm.firstname.$dirty || myForm.$submitted || myForm.firstname.$touched) }">
<label for="firstname" class="control-label" translate>Profile.FirstName</label>
<input type="text" class="form-control" id="firstname" name="firstname" required ng-model="vm.profile.firstName"/>
<p class="help-block" ng-if="myForm.firstname.$error.required" translate>Forms.Default.Required</p>
</div>
I want to take the whole ng-class attribute and replace it by something more succinct. The directive seemed like the way to go so tried this:
(function(){
'use strict';
angular.module('app')
.directive('hasError', [function(){
return {
restrict: 'A',
scope: {
form: '=bsForm',
control: '=bsControl'
},
link: function(scope, element){
scope.$watch('form', function(){
var isInvalid = scope.control.$invalid && scope.control.$dirty;
element.toggleClass('has-error', isInvalid);
});
}
};
}]);
})();
Usage:
<div class="form-group required" has-error bs-form="myForm" bs-control="myForm.firstname">
...
</div>
This however was not refreshing when properties of form changed.
What am I missing?
So... I managed to make a directive work properly for exactly my usage.
If there is a better way, please prove me wrong.
(function(){
'use strict';
angular.module('app')
.directive('hasError', [function(){
return {
restrict: 'A',
scope: {
form: '=bsForm',
control: '=bsControl'
},
link: function(scope, element){
scope.$watchGroup(['control.$invalid', 'control.$dirty', 'control.$touched', 'form.$submitted'], function(){
var isInvalid = scope.control.$invalid && (scope.control.$dirty || scope.form.$submitted || scope.control.$touched);
element.toggleClass('has-error', isInvalid);
});
}
};
}]);
})();
I did something like this one. My solution took a slightly different approach, but it may be helpful here (you can view the gist on Github).
Essentially, what I do is wrap all my form data inside a single object and I assign that object to a <form> attribute. I then watch that object and any time it changes, I select all elements with the ng-dirty and ng-invalid classes (this selector could be changed to whatever you like). I then loop through each of these elements and update messages for each of them.
Here's the code:
(function() {
"use strict"
angular.module('app')
.directive('formValidator', function() {
return {
require: '^form',
scope: {
formData: '=',
validateAll: '='
},
link: function(scope, element, attrs, ctrls) {
window.frm = ctrls;
var selector = '.ng-dirty.ng-invalid';
function validate() {
$(".formValidator-input-validation-error-message").remove();
element.find(selector).each(function(index, el) {
$el = $(el);
var messages = [];
var classes = $el.attr('class').match(/[\d\w-_]+/g);
for (var i in classes) {
var lastIndex = classes[i].lastIndexOf('-invalid-');
if (lastIndex != -1) {
var validationMessageAttr = "data-" + classes[i].substr(lastIndex + 9) + "-validation-message";
var msg = $el.attr(validationMessageAttr);
if (!msg) {
msg = element.attr(validationMessageAttr);
if (!msg) {
msg = "Invalid!";
}
}
messages.push("<div class='validator'>" + msg + "</div>");
}
}
$(el).after("<div style='position:absolute;' class='formValidator-input-validation-error-message'>" + messages.join() + "</div>");
});
}
scope.$watch(function() {
return scope.formData;
}, function() {
validate();
}, true);
scope.$watch('validateAll', function(newValue, oldValue) {
selector = !!newValue ? '.ng-invalid' : '.ng-dirty.ng-invalid';
validate();
});
}
};
})
})();

inject HTML when enter key pressed on input

I have an input field and when people press enter I'd like the field to be emptied and its value printed below with an 'x' icon to delete it afterwards just like the 'search' field on angel.co: https://angel.co/jobs
Here is my HTML:
<form ng-submit="searchAds(searchInput)">
<input id="search-field" type="search" placeholder="Start typing your search..." ng-change="searchRequest()" ng-model="searchInput"/>
</form>
<div id="search-tags"></div>
And my JS in my controller:
$scope.searchAds = function(item){
if (item === "") return;
$scope.searchInput = "";
$('#search-tags').append('<div ng-show="showDetails">' + item + '<div ng-click="showDetails = ! showDetails"> (my DVG icon here) </div></div>');
}
I have 2 problems here:
1 - I believe the code is not compiled when printed so the 'ng-show' and 'ng-click' are so working - how can I make this work?
2 - How can I make sure that when there are several tags, when clicking on my delete icon it hide only this specific tag?
Many thanks
Why not angular instead of jQuery?
You can add a directive to manage the "enter" key:
angular.module('yourModule').directive(
'ngEnter',
function () {
'use strict';
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
And then change a bit your code:
<form ng-submit="searchAds(searchInput)">
<input type="search" placeholder="Start typing your search..." ng-enter="add(searchInput)" ng-model="searchInput"/>
</form>
<div ng-repeat="tag in tags">
<div>{{tag}}<div ng-click="delete(tag)">(my DVG icon here)</div></div>
</div>
Your controller:
$scope.add = function(item) {
$scope.tags.push(item);
$scope.searchInput = "";
}
$scope.delete = function(item) {
var index = $scope.tags.indexOf(item);
$scope.tags.splice(index, 1);
}

Keypress in Angular-UI

I am running into some problems using the keypress as follows-
<div ng-controller="GBNController">
...
<input id="search-field" type="text" placeholder="JSON Query" ng-model="queryText" ui-keypress="{enter: foo()}"/>
...
</div>
and my javascript has -
var AngApp = angular.module('gbn', ['ui']);
var GBNController = function($scope) {
$scope.queryText = '';
$scope.foo = function() {
alert('test');
}
};
Now this function foo is called only when the document is loaded and then after that, the return keypress event in the text field is never handled.
I am using the current head of the master branch.
Am I doing something wrong here, or is this broken??
You need to put foo() in quotes.
<input ui-keypress="{enter: 'foo()'}">
You could easily just roll your own keypress directive
Here's a plunker to demo
And the code:
app.directive('zKeypress', function(){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('keypress', function(){
scope.$apply(function(s) {
s.$eval(attr.zKeypress);
});
});
}
};
});
HTML
<input type="text" z-keypress="foo()"/>

Categories