How to set custom validator manually in Angular - html

I would like to set my custom validator "validateName" manually in my component to true in order to show the following error message:
<mat-error *ngIf="nameControl.hasError('validateName')">Name not found.</mat-error>
The user should type in a name and click a button. After this, the name(input) is validated in the background. When name is not found the error message needs to be shown.
Is there a way to achieve this? Unfortunately I haven't found any solution.

What you can do is to include another condition for your *ngIf at your component.html:
<mat-error *ngIf="yourForm.controls['nameControl'].hasError('validateName') && isSubmitted">Name not found.</mat-error>
<button (click)="submitForm">submit</button>
And on your component.ts, when the button is clicked, the submitForm method will be fired, which will switch isSubmitted to true, if validateName error is present.
isSubmitted: boolean = false;
.
.
submitForm() {
if (this.yourForm.controls['nameControl'].hasError('validateName')) {
this.isSubmitted = true;
} else {
// handle the rest if no error;
}
}

Related

'Error: A 'return' statement can only be used within a function body' - HTML Form

I am getting an error in my old HTML form onsubmit return statement. It was working perfectly fine before but recently the same statement is showing an error. I am attaching the screenshot of the error HTML form return statement error
<form action="index.html" onsubmit = 'return validate();'>
Error: A 'return' statement can only be used within a function body.*
I have tried removing 'return' but the form gets submitted even if the validate function returns false.
Then I added preventDefault(), but now the form doesn't get submitted or redirected even if the validate function returns true.
<form action="index.html" onsubmit = ' preventDefault() validate();'>
JS code
function validate() {
if (em.value.trim() == "" || pas.value.trim() == "") {
alert("Fields not filled");
em.style.border = "2px solid red";
pas.style.border = "2px solid red";
return false;
}
else if (regexp.test(em.value)) {
er.innerHTML = "VALID!";
er.style.color = "green";
return true;
}
else {
er.innerHTML = "INVALID E-MAIL!!"; //!Alert this is important line
er.style.color = "red";
em.style.border = "2px solid red";
return false;
}
}
If I'm understanding you correctly, you are referring to a trick to use return false; to prevent a form from submitting. See here and here.
As of February 16, it seems that vscode has been throwing an error on the return false;. However, the code still works, even if vscode says there is an error. Therefore it might be best just to ignore vscode's error message.
There is a github issue currently open on vscode mentioning the new behavior change. The github issue also has a guide on disabling errors with vscode. Specifically, I followed tjx666's comment to disable the error squiggles.
Just remove the return
for example:
onsubmit="verif();"
in your case:
onsubmit = 'validate();'

After Input goes Invalid in HTML5 set error message and prevent default error message from kendo in a grid

I stuck with the inline validation in the kendo grid.
I don't want to validate after losing focus. I want to validate immediately after typing. So I start using the HTML validator. It works pretty well but the problem is I cant answer these two questions:
which event set the input from valid to invalid.
which event displays the error message.
My Current work: https://dojo.telerik.com/OSONo/56
which event set the input from valid to invalid.
...
which event displays the error message.
Just run your kendoValidator with validator.validate();
The error messages are also set with validate().
Something like this should work:
$(document).on('input propertychange', function() {
validator.validate();
});
The warning seems to be hidden behind some elements, so you can also add the folowing errorTemplate to your kendoValidator:
errorTemplate: '<div class="k-widget k-tooltip k-tooltip-validation" style="margin: 0.5em; display: block;"><span class="k-icon k-i-warning"></span>#=message#<div class="k-callout k-callout-n"></div></div>'
And the whole solution:
https://dojo.telerik.com/OSONo/66
Solved my Problem on my Own. I will edit the post so you can see what i mean but first i just give the dojo projcet.
https://dojo.telerik.com/OSONo/64
my edit:
I am sorry for my previous anwser, i just want to give him my solution i mention in my comment.
In my solution i created an event listener, how listen to all input elements. When something has changed it, saves the current cursor position (its import for ie support) and after this it trigger my "change" event. The "change" event check if it is valid or invalid. If it is invalid the kendo validator shows imidently the error-message (not as default by a blur event).
var ValidierungCheckClass = (function () {
return {
AllDOMElements: function () {
$('body').on('input', function () {
var myActiveElement = $(':focus');
if ((myActiveElement) && (myActiveElement.context.activeElement.nodeName.toLowerCase() !== "body")) {
var myActiveDOMElement = myActiveElement[0],
start = myActiveDOMElement.selectionStart, //just for IE Support
end = myActiveDOMElement.selectionEnd; //just for IE Support
myActiveElement.trigger("change");
myActiveDOMElement.setSelectionRange(start, end); //just for IE Support
}
})
}
}
});
The change event is allready created from kendo so you dont have to write your own.
At least you have to call the method when creating the website.
<script>
ValidierungCheckClass().AllDOMElements();
</script>
This is my Solution to my problem.
best regards.

Only display element on hover and user is grabbing file

I've got the following setup:
a button which says: "upload your file here", which is just a plain <input type="file" multiple>
When the user goes into finder and wants to drop the file, I want to show a larger area where they can drop the file, since the button isn't very big. This should only be available when the user hovers over the 'bigger input' AND is holding a file.
How do I go about implementing #2?
I have seen a stylechange on this site: http://www.dropzonejs.com/ when the user 'hovers with a file' above the upload area, but haven't been able to figure out how they do it.
Bind a function to the eventtype you want to listen to (dragover, dragenter, dragstart, dragend and dragleave) and make sure this function has at least one argument (the event). Then use event.dataTransfer. Without more details of how you want to implement it, giving example code is hard.
Reference: https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer
FYI the dropzonejs you mentioned uses:
return function(e) {
var efct;
try {
efct = e.dataTransfer.effectAllowed;
} catch (_error) {}
e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy';
noPropagation(e);
return _this.emit("dragover", e);
}
Above code was bound to "dragover"
You can use Javascript for File Drop Style Change :
check this Example :
// file drag hover
function FileDragHover(e) {
e.stopPropagation();
e.preventDefault();
e.target.className = (e.type == "dragover" ? "hover" : "");
}

AngularJS - Server side validation and client side forms

I am trying to understand how to do the following things:
What is the accepted way of declaring a form. My understanding is you just declare the form in HTML, and add ng-model directives like so:
ng-model="item.name"
What to send to the server. I can just send the item object to the server as JSON, and interpret it. Then I can perform validation on object. If it fails, I throw a JSON error, and send back what exactly? Is there an accepted way of doing this? How do I push validation errors from the server to the client in a nice way?
I really need an example, but Angulars docs are pretty difficult to understand.
Edit: It seems I've phrased my question poorly.
I know how to validate client side, and how to handle error/success as promise callbacks. What I want to know, is the accepted way of bundling SERVER side error messages to the client. Say I have a username and password signup form. I don't want to poll the server for usernames and then use Angular to determine a duplicate exists. I want to send the username to the server, validate no other account exists with the same name, and then submit form. If an error occurs, how do I send it back?
What about pushing the data to the server as is (keys and values) with an error field appended like so:
{
...data...
"errors": [
{
"context": null,
"message": "A detailed error message.",
"exceptionName": null
}
]
}
Then binding to the DOM.
I've also been playing around with this kind of thing recently and I've knocked up this demo. I think it does what you need.
Setup your form as per normal with any particular client side validations you want to use:
<div ng-controller="MyCtrl">
<form name="myForm" onsubmit="return false;">
<div>
<input type="text" placeholder="First name" name="firstName" ng-model="firstName" required="true" />
<span ng-show="myForm.firstName.$dirty && myForm.firstName.$error.required">You must enter a value here</span>
<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
</div>
<div>
<input type="text" placeholder="Last name" name="lastName" ng-model="lastName"/>
<span ng-show="myForm.lastName.$error.serverMessage">{{myForm.lastName.$error.serverMessage}}</span>
</div>
<button ng-click="submit()">Submit</button>
</form>
</div>
Note also I have added a serverMessage for each field:
<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
This is a customisable message that comes back from the server and it works the same way as any other error message (as far as I can tell).
Here is the controller:
function MyCtrl($scope, $parse) {
var pretendThisIsOnTheServerAndCalledViaAjax = function(){
var fieldState = {firstName: 'VALID', lastName: 'VALID'};
var allowedNames = ['Bob', 'Jill', 'Murray', 'Sally'];
if (allowedNames.indexOf($scope.firstName) == -1) fieldState.firstName = 'Allowed values are: ' + allowedNames.join(',');
if ($scope.lastName == $scope.firstName) fieldState.lastName = 'Your last name must be different from your first name';
return fieldState;
};
$scope.submit = function(){
var serverResponse = pretendThisIsOnTheServerAndCalledViaAjax();
for (var fieldName in serverResponse) {
var message = serverResponse[fieldName];
var serverMessage = $parse('myForm.'+fieldName+'.$error.serverMessage');
if (message == 'VALID') {
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
serverMessage.assign($scope, undefined);
}
else {
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
serverMessage.assign($scope, serverResponse[fieldName]);
}
}
};
}
I am pretending to call the server in pretendThisIsOnTheServerAndCalledViaAjax you can replace it with an ajax call, the point is it just returns the validation state for each field. In this simple case I am using the value VALID to indicate that the field is valid, any other value is treated as an error message. You may want something more sophisticated!
Once you have the validation state from the server you just need to update the state in your form.
You can access the form from scope, in this case the form is called myForm so $scope.myForm gets you the form. (Source for the form controller is here if you want to read up on how it works).
You then want to tell the form whether the field is valid/invalid:
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
or
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
We also need to set the error message. First of all get the accessor for the field using $parse. Then assign the value from the server.
var serverMessage = $parse('myForm.'+fieldName+'.$error.serverMessage');
serverMessage.assign($scope, serverResponse[fieldName]);
I've got similar solution as Derek, described on codetunes blog. TL;DR:
display an error in similar way as in Derek's solution:
<span ng-show="myForm.fieldName.$error.server">{{errors.fieldName}}</span>
add directive which would clean up an error when user change the input:
<input type="text" name="fieldName" ng-model="model.fieldName" server-error />
angular.module('app').directive 'serverError', ->
{
restrict: 'A'
require: '?ngModel'
link: (scope, element, attrs, ctrl) ->
element.on 'change', ->
scope.$apply ->
ctrl.$setValidity('server', true)
}
Handle an error by passing the error message to the scope and telling that form has an error:
errorCallback = (result) ->
# server will return something like:
# { errors: { name: ["Must be unique"] } }
angular.forEach result.data.errors, (errors, field) ->
# tell the form that field is invalid
$scope.form[field].$setValidity('server', false)
# keep the error messages from the server
$scope.errors[field] = errors.join(', ')
Hope it would be useful :)
Well, the Answer Derek Ekins gave is very nice to work on. But: If you disable the submit button with ng-disabled="myForm.$invalid" - the button will not automatically go back to enabled as the server-based error state doesn't seem to be changed. Not even if you edit ALL fields in a form again to comply with valid inputs (based on client side validation).
By default, the form is submitted normally. If you don't provide a name property for each field in the form then it won't submit the correct data. What you can do is capture the form before it submitted and submit that data yourself via ajax.
<form ng-submit="onSubmit(); return false">
And then in your $scope.onSubmit() function:
$scope.onSubmit = function() {
var data = {
'name' : $scope.item.name
};
$http.post(url, data)
.success(function() {
})
.failure(function() {
});
};
You can also validate the data by setting up required attributes.
If you choose ngResource, it would look like this
var Item = $resource('/items/');
$scope.item = new Item();
$scope.submit = function(){
$scope.item.$save(
function(data) {
//Yahooooo :)
}, function(response) {
//oh noooo :(
//I'm not sure, but your custom json Response should be stick in response.data, just inspect the response object
}
);
};
The most important thing is, that your HTTP-Response code have to be a 4xx to enter the failure callback.
As of July 2014, AngularJS 1.3 has added new form validation features. This includes ngMessages and asyncValidators so you can now fire server side validation per field prior to submitting the form.
Angular 1.3 Form validation tutorial :
Taming forms in Angular 1.3
Video | Repo | Demo
References:
ngMessages directive
ngModel.NgModelController
I needed this in a few projects so I created a directive. Finally took a moment to put it up on GitHub for anyone who wants a drop-in solution.
https://github.com/webadvanced/ng-remote-validate
Features:
Drop in solution for Ajax validation of any text or password input
Works with Angulars build in validation and cab be accessed at formName.inputName.$error.ngRemoteValidate
Throttles server requests (default 400ms) and can be set with ng-remote-throttle="550"
Allows HTTP method definition (default POST) with ng-remote-method="GET"
Example usage for a change password form that requires the user to enter their current password as well as the new password.:
Change password
Current
Required
Incorrect current password. Please enter your current account password.
<label for="newPassword">New</label>
<input type="password"
name="newPassword"
placeholder="New password"
ng-model="password.new"
required>
<label for="confirmPassword">Confirm</label>
<input ng-disabled=""
type="password"
name="confirmPassword"
placeholder="Confirm password"
ng-model="password.confirm"
ng-match="password.new"
required>
<span ng-show="changePasswordForm.confirmPassword.$error.match">
New and confirm do not match
</span>
<div>
<button type="submit"
ng-disabled="changePasswordForm.$invalid"
ng-click="changePassword(password.new, changePasswordForm);reset();">
Change password
</button>
</div>
As variant
// ES6 form controller class
class FormCtrl {
constructor($scope, SomeApiService) {
this.$scope = $scope;
this.someApiService = SomeApiService;
this.formData = {};
}
submit(form) {
if (form.$valid) {
this.someApiService
.save(this.formData)
.then(() => {
// handle success
// reset form
form.$setPristine();
form.$setUntouched();
// clear data
this.formData = {};
})
.catch((result) => {
// handle error
if (result.status === 400) {
this.handleServerValidationErrors(form, result.data && result.data.errors)
} else {// TODO: handle other errors}
})
}
}
handleServerValidationErrors(form, errors) {
// form field to model map
// add fields with input name different from name in model
// example: <input type="text" name="bCategory" ng-model="user.categoryId"/>
var map = {
categoryId: 'bCategory',
// other
};
if (errors && errors.length) {
// handle form fields errors separately
angular.forEach(errors, (error) => {
let formFieldName = map[error.field] || error.field;
let formField = form[formFieldName];
let formFieldWatcher;
if (formField) {
// tell the form that field is invalid
formField.$setValidity('server', false);
// waits for any changes on the input
// and when they happen it invalidates the server error.
formFieldWatcher = this.$scope.$watch(() => formField.$viewValue, (newValue, oldValue) => {
if (newValue === oldValue) {
return;
}
// clean up the server error
formField.$setValidity('server', true);
// clean up form field watcher
if (formFieldWatcher) {
formFieldWatcher();
formFieldWatcher = null;
}
});
}
});
} else {
// TODO: handle form validation
alert('Invalid form data');
}
}
As I understand the question is about passing errors from the server to the client. I'm not sure if there are well-established practices. So I'm going to describe a possible approach:
<form name="someForm" ng-submit="submit()" ng-controller="c1" novalidate>
<input name="someField" type="text" ng-model="data.someField" required>
<div ng-show="someForm.$submitted || someForm.someField.$touched">
<div ng-show="someForm.someField.$error.required" class="error">required</div>
<div ng-show="someForm.someField.$error.someError" class="error">some error</div>
</div>
<input type="submit">
</form>
Let's say a server returns an object of the following kind:
{errors: {
someField: ['someError'],
}}
Then you can pass the errors to the UI this way:
Object.keys(resp.errors).forEach(i => {
resp.errors[i].forEach(c => {
$scope.someForm[i].$setValidity(c, false);
$scope.someForm[i].$validators.someErrorResetter
= () => $scope.someForm[i].$setValidity(c, true);
});
});
I make each field invalid and add a validator (which is not really a validator). Since validators are called after every change, this let's us reset the error status.
You can experiment with it here. You might also want to check out ngMessages. And a couple of related articles.

Disable null on form:input field

I am using a <form:input> on my jsp. The input field should be editable but not nullable. Is there a way to handle this on the client side? i,e, disable the deletion of the value in the field but keep the field editable.
Disabling deletion would be inconvenient for users. It would be better to check the value when focus leaves the field and show error message if it's empty. For example, using jQuery:
<form:input id = "f" ... />
.
var f = $("#f");
f.blur(function() {
if (!f.val()) {
... // show error message
}
});
f.change(function() {
if (f.val()) {
... // hide error message
}
});