I am using BackboneJS MVC pattern and have a form with 2 fields which the user can select.
I call changeAction whenever there is any change in selection by the user (to call validation);
changeAction: function (event) {
var self = this;
var target = event.target;
target.value = $.trim(target.value);
change[target.name] = target.value;
this.model.set(change);
var check = self.model.validateItem(target.id);
if (check.isValid === false) {
self.addValidationError(target.id, check.message);
} else {
self.removeValidationError(target.id);
}
}
My validation is defined in the Model as below;
this.validators.myDropDownField = function(value) {
return !_.isUndefined(value) && !_.isNull(value) && $.trim(value).length > 0 ? {
isValid: true
} : {
isValid: false,
message: "Select dropdown field"
};
};
validateItem: function(key) {
var result = (this.validators[key]) ? this.validators[key](this.get(key)) : {
isValid: true
};
return result;
}
Now my question is I do not want to do anything to the Model in changeAction.
But if I remove the line this.model.set(change) in changeAction()
the validation does not work correctly. I do not get the value in the function
this.validators.myDropDownField
How do I handle this ?
Related
When i click a field and pass another, span tag is getting red color. Then i press the submit button it is showing alert message. But when i turn to red span and fill in the field and press submit button it is showing success even if other fields are blank.
const regForm = document.getElementById('regForm');
var validObjects = document.querySelectorAll('[customValidate]');
validObjects.forEach(function(element) {
element.addEventListener('blur', function() {
var emoji = element.previousElementSibling;
var label = emoji.previousElementSibling;
if (!element.value) {
emoji.className = "far fa-frown float-right text-danger";
var span = document.createElement("span");
span.innerHTML = " * Required";
span.style.color = "red";
if (!label.getElementsByTagName("span")[0])
label.appendChild(span);
isValid = false;
} else {
emoji.className = "far fa-smile float-right text-success";
var span = label.getElementsByTagName("span")[0];
if (span)
label.removeChild(span);
isValid = true;
}
});
});
regForm.addEventListener('submit', function(event) {
event.preventDefault();
var isValid = true;
validObjects.forEach(function(element) {
isValid = element.value ? true : false;
})
if (!isValid) {
alert("empty!");
} else {
alert("success!");
}
});
JSFiddle :https://jsfiddle.net/roop06/cjmdabrf/
because isValid is only going to be equal to the last item in the forEach
validObjects.forEach(function(element) {
isValid = element.value ? true : false; // replaces false with true on last iteration
})
If you want to use a forEach you would want to code it like this so it does not overwrite isValid. It uses its previous state.
var isValid = true;
validObjects.forEach(function(element) {
isValid = element.value ? isValid : false;
})
But if you are not doing anything else in the forEach loop, there is a better option. That option is to use every which will exit when it gets to false.
var isValid = validObjects.every(function (element) {
return element.value.length
})
var form = document.querySelector('form');
var validObjects = Array.from(document.querySelectorAll('[customValidate]'));
form.addEventListener("submit", function (e) {
var isValid = validObjects.every(function (element) {
return element.value.length
})
return isValid
})
<form>
<input customValidate>
<input customValidate>
<input customValidate>
<button>submit</button>
</form>
Or you can just use the built in HTML5 validation using required and let the browser do it for you.
<form>
<input customValidate required>
<input customValidate required>
<input customValidate required>
<button>submit</button>
</form>
Try this
JSFiddle
validObjects.forEach(function(element) {
if(!(element.value)){
isValid = false;
}
})
The problem you have is that if the last field is valid then the isValid flag will always be true. One way to get around this is to stop setting the flag once you have determined that there is an invalid field:
validObjects.forEach(function (element) {
if (isValid) {
isValid = element.value ? true : false;
}
});
So I have a function that displays a list from an API:
displayEventTicketDetails() {
this.Service
.getEventTicketDetails().subscribe((data: any) => {
this.eventTicketDetails = data.map(ticket => ticket.ticket_name);
console.log(this.eventTicketDetails);
});
}
This is the result from the function above:
["Regular", "VIP", "Table", "Testing", "Cabana"]
Here is how the form array is declared:
ngOnInit() {
this.composeMessage = this.fb.group({
ticket: new FormArray([])
});
Then I use this function below to track if the check boxes are checked
onChange(event: any, isChecked: boolean){
const control = <FormArray>this.composeMessage.controls.ticket;
if(isChecked){
control.push(new FormControl(event))
} else{
const index = control.controls.findIndex(x => x.value === event);
control.removeAt(index)
}
}
Then finally in my ts file, here is my onsubmit function that submits the data on the form:
submitComposeMessage() {
this.submitted = true;
if (this.composeMessage.invalid) {
return;
}
const ticket = this.f.ticket.value;
this.Service
.createMessage(
ticket)
.subscribe(
(res: any) => {
if (res.err) {
this.toaster.errorToastr(res.message, null, { toastTimeout: 5000 });
return false;
}
this.toaster.successToastr(res.message, null, { toastTimeout: 5000 });
console.log("Message successfully created");
},
err => {
console.log(err);
}
);
}
So in my Html file here is my input field:
<ng-container *ngFor="let event of eventTicketDetails; let i = index" >
<label class="w-checkbox checkbox-field" >
<input
type="checkbox"
id="{{i}}"
name="checkbox-9"
class="w-checkbox-input checkbox"
(change)="onChange(event, $event.target.checked)"
[checked]="composeMessage.controls.ticket.value.indexOf(event)>=0">
<span class="no-margin w-form-label">{{event}}</span>
</label>
</ng-container>
With that loop, I'm able to get this result
So, I need help with two things:
1). I want all the checkbox to be checked by default when the page loads at first instance.
2). I want to validate the checkbox to ensure at least one checkbox is checked on submission.
I'll appreciate any help I can get.
If you want to only show validation message after submit, I would suggest the following, where we instead iterate the formarray in template, initially set all checked (as that is what you wish). We would listen to valueChanges of the formarray, but filter out as long as form is not submitted. We would introduce a new variable, for example isEmpty, which based on we would show/hide validation message. So all in all....
TS:
isEmpty = false;
submitted = false;
constructor(private fb: FormBuilder) {
const ctrls = this.eventTicketDetails.map(control => this.fb.control(true));
this.composeMessage = this.fb.group({
ticket: this.fb.array(ctrls)
});
this.tickets.valueChanges.pipe(
filter(() => !!this.submitted)
).subscribe((value) => {
value.some(x => x === true) ? this.isEmpty = false : this.isEmpty = true;
})
}
get tickets() {
return this.composeMessage.get("ticket") as FormArray;
}
onSubmit() {
this.submitted = true;
const selectedTickets = this.tickets.value
.map((checked, i) => (checked ? this.eventTicketDetails[i] : null))
.filter(value => !!value);
selectedTickets.length ? this.isEmpty = false : this.isEmpty = true
}
HTML:
<label formArrayName="ticket" *ngFor="let t of tickets.controls; index as i">
<input type="checkbox" [formControlName]="i">
{{eventTicketDetails[i]}}
</label>
<small *ngIf="isEmpty">Choose at least one checkbox</small>
STACKBLITZ
change Id to something like this
id="ticket{{i}}"
In this method write like this and call displayEventTicketDetails on ngOnit. This will check all the values:
displayEventTicketDetails() {
this.Service
.getEventTicketDetails().subscribe((data: any) => {
this.eventTicketDetails = data.map(ticket =>ticket.ticket_name);
setTimeout(() => {
for(var i= 0;i < this.evenTicketDetails.length ; i++){
var id = "ticket" + i;
(<HTMLInputElement>document.getElementById(id)).checked = true;
console.log(this.eventTicketDetails);
}, 500);
});
}
2. In submit method write something like this
submitComposeMessage() {
for(var i= 0;i < this.evenTicketDetails.length ; i++){
var id = "ticket" + i;
var resval = (<HTMLInputElement>document.getElementById(id)).value;
if(resval){
// this will check atleast one value is checked and if it true we are coming
out of the loop and performing other operations..
i = this.evenTicketDetails.length;
}
else{
// show error message or block from going forward..
}
});
}
This will solve your issues.
I have a submit button that is initially disabled (through v-bind:disabled) and will only be enabled until all form inputs are non-empty and errors are resolved. For each of my input, I have a spinner that will become a check or an x after verifying the validity of the input. This takes a few seconds and I was hoping that the same delay be applied to the enabling of the submit button. At the moment, this is what the form looks like:
This is the form (in pug):
.form-group
label Email Address
.input-group
input.form-control(type="email" name="emailAddress" value=profile.email
v-model="email"
v-validate
data-vv-delay="1000"
data-vv-rules="required|email"
data-vv-as="email"
:class="{ 'input': true, 'is-danger': errors.has('emailAddress') }"
placeholder="eg. andres#gmail.com")
.input-group-append
span.input-group-text
i.fal.fa-pulse.fa-spinner(v-if="email && emailBusy")
i.fal.fa-check.text-green(v-if="email && !emailBusy && !isEmailTaken && !errors.has('emailAddress')")
i.fal.fa-times.text-red(v-if="email && !emailBusy && (isEmailTaken || errors.has('emailAddress'))")
span.text-danger.text-error(v-show="errors.has('emailAddress')") {{ errors.first('emailAddress') }}
span.text-danger.text-error(v-if="email && email.length > 0 && isEmailTaken") Email address has already been taken
.form-group
label Username
.input-group
input.form-control(type="name" name="username"
v-model="username"
v-validate
data-vv-delay="1000"
data-vv-rules="required|verify_username"
:class="{ 'input': true, 'is-danger': errors.has('username') }"
placeholder="eg. andres45")
.input-group-append
span.input-group-text
i.fal.fa-pulse.fa-spinner(v-if="username && usernameBusy")
i.fal.fa-check.text-green(v-if="username && !usernameBusy && !isUsernameTaken && !errors.has('username')")
i.fal.fa-times.text-red(v-if="username && !usernameBusy && (isUsernameTaken || errors.has('username'))")
span.text-danger.text-error(v-show="errors.has('username')") {{ errors.first('username') }}
span.text-danger.text-error(v-if="username && username.length > 0 && isUsernameTaken") Username has already been taken
.form-group
button.btn.btn-blue(:disabled="errors.any() || isEmailTaken || isUsernameTaken || !username || !email" type="submit")
i.fal.fa-sign-in.mr-2
span Complete Sign Up
The vue instance:
var register = new Vue({
el: '#register',
data: {
email: email,
username: null,
isUsernameTaken: false,
usernameTimer: null,
usernameBusy: false,
isEmailTaken: false,
emailTimer: null,
emailBusy: false
},
methods: {
validateEmail: function(email) {
var self = this;
var url = '/api/users?email=' + email;
self.$http.get(url)
.then(function(res){
self.isEmailTaken = true;
self.emailBusy = false;
}, function(err){
self.isEmailTaken = false;
self.emailBusy = false;
});
},
validateUsername: function(username) {
var self = this;
var url = '/api/users/' + username;
self.$http.get(url)
.then(function(res){
self.isUsernameTaken = true;
self.usernameBusy = false;
}, function(err){
self.isUsernameTaken = false;
self.usernameBusy = false;
});
}
},
watch: {
username: function(val) {
var self = this;
clearTimeout(self.usernameTimer);
self.usernameBusy = true;
self.usernameTimer = setTimeout(function() {
self.validateUsername(val);
}, 1600);
},
email: function(val) {
var self = this;
clearTimeout(self.emailTimer);
self.emailBusy = true;
self.emailTimer = setTimeout(function() {
self.validateEmail(val);
}, 1600);
}
}
});
I’m on mobile so apologies about formatting and lack of code. For me I would probably set up a variable to track the disabled state, say var isFormComplete = false; I would use the vue disabled prop to control the button/form state. :disabled=“!isFormComplete”.
Then I would set up a vue watch or even computed method in the JS which basically will check if each form control is empty or whatever arbitrary value checking you want to do, since it’s dynamic behind the scenes with variables it should be pretty simple to check through each form control and when all conditions are satisfied, set the isFormComplete or whatever you want to call it to true and your control will be enabled.
For extra fun and bonus points, you could set up some generic validation code to be reusable and abstract it out as a vue mixin and have yourself a nifty custom form validation you can reuse. I know this isn’t a traditional answer but since I’m mobile I felt this was more indepth than a comment even though there is a lack of code. You can add a timer as well in the validation method to when all conditions are satisfied delay by however long you want and then set the disabled variable to false.
I have some textbox and I change the value of this textboxes in clientside (javascript) ,value was changed but when I read in server side after postback actually value not changed. my textbox isn't read only or disable.
notice that I use updatepanel and my postbacks is async.any idea to solve this issue?
update
I use this jquery to support placeholder in ie,but it cause value of my textboxes equal to placeholder value, and this conflict when my postback is async. for solving this problem I use below jquery code:
function EndRequestPostBackForUpdateControls() {
//*****************************For place holder support in ie******************************
if (runPlaceHolder != 0) {
//alert('end');
$('input, textarea').placeholder();
var $inputs = $('.placeholder');
$inputs.each(function () {
var $replacement;
var input = this;
var $input = $(input);
var id = this.id;
if (input.value == '') {
if (input.type == 'password') {
if (!$input.data('placeholder-textinput')) {
try {
$replacement = $input.clone().attr({ 'type': 'text' });
} catch (e) {
$replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
}
$replacement
.removeAttr('name')
.data({
'placeholder-password': $input,
'placeholder-id': id
})
.bind('focus.placeholder', clearPlaceholder);
$input
.data({
'placeholder-textinput': $replacement,
'placeholder-id': id
})
.before($replacement);
}
$input = $input.removeAttr('id').hide().prev().attr('id', id).show();
// Note: `$input[0] != input` now!
}
$input.addClass('placeholder');
$input[0].value = $input.attr('placeholder');
} else {
$input.removeClass('placeholder');
}
});
}}
function safeActiveElement() {
// Avoid IE9 `document.activeElement` of death
// https://github.com/mathiasbynens/jquery-placeholder/pull/99
try {
return document.activeElement;
} catch (err) { }}
function BeginRequestPostBackForUpdateControls() {
//*****************************For place holder support in ie******************************
if (runPlaceHolder != 0) {
// Clear the placeholder values so they don't get submitted
var $inputs = $('.placeholder').each(function () {
var input = this;
var $input = $(input);
if (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) {
if ($input.data('placeholder-password')) {
$input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
// If `clearPlaceholder` was called from `$.valHooks.input.set`
if (event === true) {
return $input[0].value = value;
}
$input.focus();
} else {
alert($(this)[0].value);
$(this)[0].value = '';
alert($(this)[0].value);
$input.removeClass('placeholder');
input == safeActiveElement() && input.select();
}
}
});
}}
$(document).ready(function () {
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_beginRequest(BeginRequestPostBackForUpdateControls);
prm.add_endRequest(EndRequestPostBackForUpdateControls);
});
I use this code to clear my textbox value before sending to server in add_beginRequest,and set value in add_endRequest (for placeholder in ie).
can anyone help solve this problem? thank you.
You changed the value of TextBox with javascript and the respective ViewState is not updated. You can use hidden field to store the value in javascript and get it in code behind.
Html
<input type="hidden" id="hdn" runat="server" />
JavaScript
document.getElementById("hdn").value = "your value";
Code behind
string hdnValue = hdn.Value;
Use hidden field to store the value, and retrieve it on the server side.
i used to use jquery validation plugin but because of lack of this plugin with wysiwyg plugins i wrote a simple script to validate my form
i tried to do it like this
function validateArticle(formData, jqForm, options) {
$('#errors').empty();
if ($('#editor').val() == 0) {
$('#errors').show();
$('#errors').append('<li>please enter your article body</li>');
return false;
}
if ($('#ArticleTitle').val() == 0) {
$('#errors').show();
$('#errors').append('<li>please enter your article title</li>');
return false;
}
$('#errors').hide();
return true ;
}
i found to 1 problem when it validate the form it's validating it field by field so the errors messages doesn't appear at once
i tried to do something like
var errors = [];
function validateArticle(formData, jqForm, options) {
$('#errors').empty();
if ($('#editor').val() == 0) {
errors.push('<li>please enter your article body</li>');
var invalid = 1 ;
return false;
}
if ($('#ArticleTitle').val() == 0) {
errors.push('<li>please enter your article title</li>');
var invalid = 1 ;
return false;
}
if(invalid == 1){
$.each(errors , function(i, val) {
$('#errors').append(errors [i]);
});
}
$('#errors').hide();
return true ;
}
i tried to push errors as array elements and loop through them in case of invalid is true
bu this one doesn't work at it all ?
is there any way to make it work ?
if ($('#editor').val() == 0) // This is checking if value is 0
This does not make sense..
Try
if ($('#editor').val() == '') //Instead check for empty string
EDIT
Also you seem to be hiding the error's div in the end.
$('#errors').hide();
Try this code Instead
$('#validate').on('click', function() {
var errors = [];
var html = '<ul>' ;
valid = true;
$('#errors').empty();
if ($('#editor').val() == '') {
errors.push('<li>please enter your article body</li>');
valid = false;
}
if ($('#ArticleTitle').val() == '') {
errors.push('<li>please enter your article title</li>');
valid = false;
}
if (!valid) {
html += errors.join('') + '</ul>'
$('#errors').append(html);
}
else{
$('#errors').hide();
}
return valid;
});
DEMO