disabled.bind in Aurelia not working correctly - javascript

I have a form, in the form there is a custom component that has certain fields in it. At the end of the form there is a button. The button has...
disabled.bind="!(formValid && subFromValid)"
Now, on the custom component I have a two-way binding of a variable "subFormValid" The subFormValid is only valid when the validation in the custom component is valid. So, the sub form validates some fields and sets subFormValid = true. Even though the "formValid" is false, the button is now enabled.
I can't figure out why and it is driving me nuts. I even went so far as to add a get function to a variable and add console logs in it, like so...
<button type="submit" disabled.bind="wholeFormValid">Submit</button>
Then in my class I have...
get wholeFormValid() {
console.log("validating form");
console.log(!(this.formValid && this.subFormValid));
return !(formValid && subFormValid);
}
I get a million plus lines in the console, but I was able to watch it, the entire time. When I first load the page it was logging...
validating form
true
Then I filled out the subform, and checked the console. The console showed...
validating form
true
Yet, the button was now enabled.
For some reason whenever subFormValid = true, the button is enabled, regardless of formValid.
Does anyone know how to disable a button unless 2 conditions are met? Everything I do enables the button as soon as subFormValid is true, even though the console is still logging "true", which should disable the button.
Just to help out, if anyone is wondering why there is a subform in the form it is because the address needs to be validated using Smarty Streets and we want to be able to reuse that part of the form in other places, so I created a custom component for the address section that validates the input, and validates the address. It is being called in the form like so...
<require from="components/smarty-streets"></require>
Then using like this...
<smarty-streets form-is-validated.two-way="subFormValid"></smarty-streets>
Then in smarty streets I have...
#bindable formIsValidated;
and I change the value from true to false and vice-versa depending on the validation in the component.

I have tried to recreate your problem using the following:
<input type="checkbox" checked.bind="formValid"/>
<input type="checkbox" checked.bind="subFormValid"/>
<button disabled.bind="wholeFormValid">Submit</button>
I noticed in your function that you used this.formValid in the console.log line, but in the return line you used formValid, without this. This seems to be a different variable than your actual binding variables. I think your function should look like this:
get wholeFormValid() {
console.log("validating form");
console.log(!(this.formValid && this.subFormValid));
return !(this.formValid && this.subFormValid);
}
Edit: I also strongly recommend using the #computedFrom decorator on your get() to reduce the amount of calculations aurelia does. You can read more on that here.

Related

Is there an HTML5 validation API to set the state of an element to be invalid?

I don't want to use the HTML 5 validation API but for one thing. I will do my custom validation using JavaScript but I would like to use the nice tool-tip like thingy that the browser uses to display the validation message.
So, in short, I'd like to selectively use the element.setCustomValidity("my own message") in my own event handler, so I can avoid using a third-party tool-tip.
However, even though I set the custom validity, it won't display until I somehow invalidate the state of the controls.
If I call into the validation API (element.checkValidity()), it will start doing its own in-built validation looking for attributes on my HTML elements. But I don't want any of that.
function submitEventHandler() {
let errors = myOwnValidateFunction();
if (errors && errors.length > 0) {
let txt = document.getElementById("txt");
txt.setCustomValidity("No, no, no, no, you're doing it wrong!");
// Is there a way to invalidate an HTML element?
// ...???
}
}
Well, as always, each browser simply act differently on pretty much any new API.
To invalidate an input, its enough to set this: input.setCustomValidity('just an error');, this will let the browser know this input have an issue with it.
HOWEVER each browser will do its own things:
Chrome - Won't show any error until you try to submit the form, only than it will let the user know that the first field with an error have an error, it will ignore the rest of the inputs with errors.
Firefox - will show your custom message and highlight the input in red right away after you set it, you don't need to wait for a submit to show the errors, when submit is clicked it shows a different tooltip on the invalid input.
Edge - Will show an tooltip with custom message only after the user hover over it, and will highlight in red with different tooltip after submit
Didn't test it on other browsers, but i'm sure each browser will use its own way of showing the error, some might wait for submit, some will show right away, but all who support this API should invalid the input after you input.setCustomValidity('Some error message')
This is why you might consider showing your own tooltip to avoid this browser dependency, and make sure its working the same way on all of them.
https://jsfiddle.net/q60bwteL/17/
Update
You don't need to set any type, and the validation above works the same way for type='text', i'm not sure what you see, but the code snippet below have 2 inputs, 1 with no type and 1 with type='text', both works.
You can create a fiddle with your issue so I could take a look, but as you can see from the fiddle, its working for all type of inputs:
https://jsfiddle.net/q60bwteL/21/
But again, note that it works differently on different browsers, chrome only shows the first field with the error, not all of them and only on submit, while firefox shows errors for all of the fields (if have multiple errors) and before you click on submit.
This is why I personally never trust the implementation of the browser with stuff I could do on my own, it is very easy to implement a basic error handling stuff, from the question you already have it, you simply need to add the styling and the tooltip to it, there are many ways to create a tooltip with CSS alone on the web (for example: https://stackoverflow.com/a/25391104/8727608).
Create a function that will handle your error things:
function setError(inputElement, errorMessage) {
inputElement.setAttribute('title', 'errorMessage');
inputElement.classList.add('errorInput')
}
Create a function that will remove all the error things:
function removeError(inputElement) {
inputElement.removeAttribute('title');
inputElement.classList.remove('errorInput')
}
And style the errorInput class as you wish with CSS.
Now I assume you only return the errors in array of strings with the error messages, but you can use an array of objects that each object contain the error message and the input element which have the error:
if (errors && errors.length > 0) {
for(var i = 0; i<errors.length; i++) {
setError(errors[i].element, errors[i].message);
}
}
Before you validate the input simply call the removeError function and don't forget to return false when you submit if there are errors. (as you already do)
UPDATE 2
I don't know why I didn't think of it. but there is a way to stop validation and start it when you want:
Adding the novalidate attribute on the form will let the browser know that you don't want to perform a validation on that form, so this won't show any errors and will handle submit as you like it to.
But you still want to use that validation and for this you can call the reportValidity() on the form element, basically this function enable the validation on submit, it doesn't matter where you call it, it will run the validation when submit is clicked BUT this will show only the first input with the error message and not all of them (even on firefox), it looks like there are 2 states of validation, the before and after submit, not sure why, but those are 2 different checks, and you can only control the after submit check, not the before.
check this fiddle: https://jsfiddle.net/q60bwteL/64/
So you can control when you do the validation, but there are 2 types of validation, before and after submit, you can control only after submit, and it only show the first input error not all of them.
Do we like it? no, why its like that? I have no idea, to be honest, it really looks like the firefox developers simply break the loop after first error is found.
P.S - after thinking about it, they simply implement the title attribute tooltip method, but because only 1 element can be hovered or focused they can only show 1 error message, this is how tooltips works.

How to toggle a Formcontrol as disabled or enabled on different button clicks in React/JS?

I'm new to ReactJS, so I apologize in advance if the questions a bit fragmented.
Basically, I am working on creating a page of a website where someone can change their username and password. I want to implement this in a bootstrap Form where one form control has username, a second has password, etc. One button (edit) will make the FormControl text fields editable (enabled) and the other (save) will make the text fields disabled.
Here's where I run into a problem. From what I've learned of react so far, this involves changing the state. However, the way the prop disabled works, is it isn't "disabled=true" or "disabled=false", it's simply "disabled". Therefore, I can't make it "disabled={this.state.x}" or anything along those lines. Here's the relevant line of code...
< FormControl controlId="testControl" type="text" placeholder="Username" />
Basically, on a button click (edit) I would like to make this disabled, but I'm unsure of how to do that, when any mention of disabled will result in the FormControl being disabled, regardless of it being set equal to true or false.
Thanks! And please let me know if I can provide more information - as I said, I'm very new to ReactJS.
You'd have to trigger a state change on edit event handler so that react knows to re render the form(which react does intelligently).
Without any state change you will have to manipulate the DOM and achieve whatever you want

Enable ASP.Net validator without immediately running validation

Question
Can I enable an ASP.Net validator without running validation immediately (i.e. giving the user a chance to input values before running it, but still force running validation on form submit)?
Background
I have a form that allows a person to input their family data when they check in their child(ren) into a public daycare system. We have five fields that I need to force parents to actively consider (allergies, special needs, etc). The values are not actually required, so too many parents were just skipping over the fields when their children should have had values specified.
My solution is to have a required field validator that's disabled if they click an N/A checkbox next to the textbox. (If someone has a better solution, I'm all ears; the UI of this form--which I inherited--makes me want to gouge out my eyes.)
The other thing is that when the "Add Family" button is clicked, four empty rows are auto-generated: two adults and two children. Whether a row represents a child or an adult is determined by a drop-down in that row. If "adult" is selected, or if the first name textbox in that row is empty, the validators are disabled.
The validators of all five fields are enabled as soon as both the drop-down selected value is "child" AND the first name textbox is not empty. The issue is that running ValidatorEnable() causes the form to validate. In the common case, the fields will be empty, since first name and "family role" (adult/child) will be inputted before whether that person has allergies or are potty trained. This means as soon as they input the name into a row specified as child, ASP.Net's all like "HEY, DUMMY, YOU HAVE AN INVALID FIELD!!!1!".
So, I would like to enable the validator, but prevent validation until the user actually either inputs an empty value into the allergy textbox, or they try to submit the form.
Is this possible?
Note, I would use a custom field validator, but validation isn't run on empty fields; afaik, only required field validators do that.
I've just adapted the answer here: http://veskokolev.blogspot.co.uk/2007/11/how-to-disable-validation-group-with.html to enable some validators client-side with jQuery. Once they were enabled, the validation function did run - I don't know how to stop it (without modifying the ASP.NET JS code, which I guess is an option?); so I simply hid the messages until the validation is run again (which is easy enough with $(x).hide()).
Considering all the client-side code does is show the warning and stop you submitting I think this is OK. The usual things that will cause the validator to re-run will re-show the message.
So if I have validators like:
<asp:Validator runat="server" CssClass="js-validator-set-a" />
I can use this Javascript:
toggleValidators('.js-validator-set-a', true);
function toggleValidators(selector, enable) {
// get the page validators into a jQuery object
var vals = getJqueryObjectFromArrayOfEls(Page_Validators)
vals.filter(selector).each(function (i, o) {
ValidatorEnable(o, enable);
$(o).hide();
});
};
function getJqueryObjectFromArrayOfEls(elsArray) {
var x = $();
$.each(Page_Validators, function (i, o) {
x = x.add($(o));
});
return x;
}
I just came across a similar requirement. WhatI did was first to set a valid value to the compnent to be validated, then enable the validator and finally I cleared the value in the component again. Something like
$('#<%= tbxValue.ClientID %>').val('X'); // set a value to the textbox
ValidatorEnable(<%= rfvValue.ClientID %>, true); // enable the required field validator
$('#<%= tbxValue.ClientID %>').val(''); // clear the value from the textbox
Yes, it's possible in a variety of ways. The two most common and perhaps sensible things to do are :
Have validation occur completely in the code-behind via code only
Have ASP.NET validators that are set to enabled=false and then turn them on and call Page.Validate()
Instead of using that function, you can make your own function that has some of the same code as ValidatorEnable, but wont trigger the validation.
function myValidatorEnable(val, enable) {
val.enabled = (enable != false);
}

Getting two errors using Parsley.js to add validators to fields that are dynamically cloned

I have a form which I am using Parsley.js to validate. Everything works like a charm. Except, there is a part of the form where users are allowed to add new fields:
addFieldsToContainer = function($fields, $container) {
$fields.clone(true).removeClass('empty-form').appendTo($container);
if (typeof(Parsley) !== 'undefined'){
$('form.form-horizontal').parsley().destroy();
addValidatorsListeners();
}
};
My validations are a little complicated, because there are sections, and in each section, the inputs must all add up to a total number, which is the value of another input. I've got the inputs triggered to blur, and if any of the inputs are entered and the total for the section is wrong, all the inputs for the section are given the parsley-error class, and vice versa. Now, on the new input that is being added to the DOM, the parsley ui is not working on it, i.e. the parsley-success/error classes are not being added to it. But the rest of the section still works fine, and even includes whatever number is in the input in the total calculation. I'm also seeing these two errors in the dev console:
Uncaught TypeError: Cannot set property 'validatedOnce' of undefined parsley.min.js:8
Uncaught TypeError: Cannot read property '$errorsWrapper' of undefined
My code here.
How can I correctly bind these new inputs to the parsley validator?
Edit:
So I just realized that the when the user clicks the add input button, all of the inputs that have parsley:success/error classes have them all removed (because of model_form.parsley().destroy() I assume?) except for the new input that has been added. This input class never changes with the rest of the section, as I've pointed out. Also, the total enrollment input doesn't change, I'm guessing because of the { excluded: '[data-parsley-sum-total="all"]' } line. So it looks like the input that is being cloned from the page isn't having it's binding destroyed or it's validators correctly added, so some sort of event handling problem?
Maybe related?
If you clone Parsley's elements with their data, yeah, Parsley will be confused as hell.
I'd simply recommend not doing that. More precisely, clone without the data and events, or else clone before binding with parlsey.
If you really have to go this way, you might be able to get away with cloning afterwards if you $yourClone.removeData('Parsley'). I haven't tested it and can't guarantee that even if it works now it would in the future.

jQuery issues on testing form elements values

Good day all.
I have a form where users must fill out some fields, and this form is created dinamically y a php script.
I've done a script that do a test on input fields to check if the users has filled everything.
It is basically a cascade test in where if an error variable is true, the form isn't submitted.
I have done some modifications and I have added a new hidden field to the form, filled by jquery when user clicks a image.
$( '.selectLogo' ).bind("click",function(e){
$( "#operator" ).val( $(this).data("opvalue") );
});
then, on the submit event, there is the whole test...
if ( !$( "#operator" ).val().length ){
$(".operatorError").show();
error=true;
} else{
$(".operatorError").hide();
}
if(error){
return false;
}
this is the last test I've added on the function, just before testing the error variable and decide if return true or false.
the problem is that:
IF i'm debugging the script, i.e. I put a breakpoint just over the if(error), everything is fine.
IF i filled the whole form, i.e. the checkForm function just go throught every test and arrive on the decision of returning true or false, everything is ok.
BUT if i filled the form partially, and I try to make a submit without selecting the operator (the new field i've added), the checkForm function stops me, display the error, but at this point, I must click on the operator logo to make the hiden field fills, then I have to click SEVERAL (read 2,3 or sometimes 4) times the submit button to have the form submitted.
It sounds like that the error variable retain the value, and the jQuery cache it... or something, does anyone has experienced a similar problem? it is possible to "force" jQuery to "really" test a variable...? Am I complitely wrong and maybe the problem is elsewhere?

Categories