Disable submit until all fields are valid in reactstrap - reactstrap

I have a form in reactstrap that has several input fields that uses FormFeedback like this:
<Input invalid={typeof data.name === "undefined" || data.name.length<1} bssize="sm" type="text" name="name" id="name" placeholder="Name" value={data.name} onChange={this.props.handleInputChange} />
<FormFeedback >A name is required</FormFeedback>
<Button color="primary" onClick={this.save} disabled={!this.state.okToSubmit}>Submit</Button>
Is it possible to have the submit button of the form disabled until all fields are validating ok?
I can´t find any way to access the "invalid" prop of a field. The closest I have come so far is to look at the classList of target in the handleInputChange-function. But that feels very hacky and not the best way.
Quite new to React so all help is really appreciated.

There are a number of ways you can accomplish this: Since you are using onChange event handler, you can set another state var.
So, for example, say you have five form elements that you want to have be required. Every time an element is validated, increase that state var by one. Then add a conditional for the button to be disabled or not by disabled={this.state.okToSubmit != 5} (this can also be done using hooks if you're using a functional component.
Another option would be to keep the button live, and do all the validation within the onSubmit handler, but I think most modern day UX is to validate on a per element basis.

Related

Fetch attribute value as Variable in GTM

Hello I have this code on my website that gives the query of a site search in the attribute 'value'
In this case, it is the word 'disjoncteur' that want in my variable in GTM.
<div class="dfd-searchbox-main">
<input type="search" name="search[query]" value="disjoncteur" autocapitalize="off" autocomplete="off" autocorrect="off" class="dfd-searchbox-input" id="dfd-searchbox-id-MIkFo-input" placeholder="Chercher…" dfd-value-indices="" dfd-hook="Input">
<div class="dfd-searchbox-autocomplete"></div>
What should i do to fetch that value in a variable ?
Thanks for the help
A general solution would be making a custom JS variable in GTM looking like this:
function(){
return document.querySelector("input[type='search']").value;
}
However, it's a little bit awkward due to how universal it attempts to be. And realistically, you likely only need that search value on the CTA click, so a relative path from that CTA could have been used through a {{Click Element}} variable. That would be a cleaner solution.
And, of course, the best solution would be asking front-end devs to give you the value with a dataLayer push so that you wouldn't need to rely on the html structure of the page to get your info.
Update:
I acheived to create a dom element variable by inserting the class of the element into ID and the attribute "value" as the attribute, it works like a charm.

Custom validation in react-bootstrap forms not working

I'm trying to add custom validation logic to my react-bootstrap forms, but isInvalid doesn't seem to be respected. As soon as validated={true} is set on the form, it always validates non-empty strings, regardless of isValid or isInvalid. The invalid message is displayed, but the field shows as green. See here:
Here is the offending code:
<Form noValidate validated={formValidated} id="bidForm">
<Form.Group className="mb-3" controlId="formBasicBidding">
<Form.Label>Bid Amount</Form.Label>
<InputGroup hasValidation className="mb-3">
<InputGroup.Text id="inputGroupPrepend">$</InputGroup.Text>
<Form.Control
required
value={bidAmount}
isInvalid={!(parseInt(bidAmount) > 0) && formValidated}
onChange={e => setBidAmount(e.target.value)}
/>
<InputGroup.Text id="inputGroupAppend">.00</InputGroup.Text>
<Form.Control.Feedback type="invalid">
Please select a dollar amount {`>`} 0
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
<...>
</Form>
I was able to get it to work using a pattern= regex on the input, but I'm planning to do more complex validation where a regex won't be sufficient. How can I get react-bootstrap to follow isValid and isInvalid properly? Thanks!
The docs don't do a great job of making this clear, but the form-level validated attribute hooks directly into HTML5's native validation library and can't be used simultaneously with other validation techniques. So if you're using the native option and an input doesn't violate any of the native validation options (required, pattern, etc), then the input will be considered valid. Since you don't have any of the native validation attributes besides required on your bid input, "foo" is valid as far as React-Bootstrap is concerned.
(If you're thinking 'well that's bad code design to let you use both simultaneously', I'd tend to agree with you.)
You'll note that with your current code, if you enter "foo" and submit the form the element actually does have an is-invalid class applied to it, but it's also got the :valid psuedo-selector applied to it because the entire form was validated, which seems to take precedence from a CSS perspective:
The best solution here is to use either the native HTML5 validation option (detailed here) or roll your own (with or without a helper library like Formik), but not both simultaneously.
If you're trying to avoid validating until the input is actually in a "dirty" state (e.g. the user filled it out or submitted the form), you can do something like this (CodePen here):
<Form.Control
required
value={bidAmount}
isInvalid={!(parseInt(bidAmount) > 0) && (bidAmount.length || formSubmitted)}
onChange={(e) => setBidAmount(e.target.value)}
/>

Referencing Ractive component's text

I want to enable a button when two text fields have length > 0: How do I refer to these text fields lengths to express this? Seems simple, but its not obvious to me how to refer to the component's and their text (length). I basically want to use FRP to enable/disable button for form submission. These would be "sibling" components I suppose.
If two-way binding is an option, you could do something along these lines:
<input value='{{foo}}'>
<input value='{{bar}}'>
<button disabled='{{ !foo || !bar }}'>submit</button>
This works because the empty string ('') is falsy in JavaScript, so !foo || !bar is only false when both foo and bar are non-empty.
#Rich Harris: It seems that the problem with the <button disabled="{{ !(''+foo) || !(''+bar) }}">submit</button> trick is that the button is enabled at the start, because both foo and bar are initially undefined and ''+undefined gives the string 'undefined'. The technique also becomes unwieldy if you have several fields with various validation requirements.
As you may know, Angular has a $invalid that you can apply to a form, e.g., <button ng-disabled="myForm.$invalid">submit</button> where myForm is the form's name attribute. In Ractive, I guess one could write an isvalid function and then use <button disabled="{{ !isvalid() }}">submit</button> but that only works for one form (or is there some way to "attach" it to a particular element?).

What is the easiest way to disable a form but keep it readable?

I have my form fields in a Panel which, if a read-only version is required, I set Enabled = False on the Panel. This was quick and dirty and the results are mostly dirty, mostly in IE. Can't scroll through large ListBoxes. Multi-line TextBoxes only show the first few lines. There's some funky styling to disabled Labels.
Do you have any ideas as to how to disable an entire form, letting the user read the data, visually indicating that it is disabled (gray input or text in place of input), but to the server keep the control disabled so it's not loading any data that could be manipulated by enabling fields by nefarious means.
(Also, I'm hoping I don't have to add a label corresponding to each data field.)
You could remove all the buttons and use jQuery to change the background color on all inputs. This would be a quick and easy solution.
$(':input').addClass('disabled');
You can have your fields assigned the readonly attribute, ie:
<input type="text" name=myText value="Enter Your Name" readonly>
This can easily be done with js but is more robust if done right in html.
You could also disable or even remove the submit button.
I would use the ASP web controls. The TextBox for the input type="text".
All web controls have the enabled property
<asp:TextBox id="txtSomething" runat="server" />
You can now enable/disable all controls from code like you do today (for the panel). But you have to do it for every one (I don´t know how many you have).
txtSomething.Enabled = False
You can also do this with JavaScript.
Loop all elements in the form, and disable/enable them.
function DisableEnableForm(myForm,setDisable){
elems = myForm.elements;
for(i=0;i<elems.length;i++){
elems[i].disabled = setDisable;
}
}
You can trigger this JavaScript function from ASP like this:
Button1.Attributes.Add("onclick", "javascript:DisableEnableForm(´form1´,true)");

Webform checkbox value in javascript

I have a checkbox list control on my asp.net web form that I am dynamically populating from an arraylist. In javascript I want to be able to iterate through the values in the list and if a particular value has been selected to display other controls on the page.
My issue is that all the values in the checkbox list are showing up as 'on' instead of the actual value set. How do I get the actual values for each checkbox?
Thanks.
Javascript:
checkBoxs=document.getElementById(CheckboxList);
var options=checkBoxs.getElementsByTagName('input');
for(var i=0;i<options.length;i++)
{
if(options[i].value=="Other")
{
if(options[i].checked)
{
var otherPub=document.getElementById('<%=alsOtherPublicity.ClientID%>');
otherPub.style.display='block';
}
}
}
Edit: The line that I'm having problems with is if(options[i].value=="Other") as the values showing up in firebug are given as 'on' rather than the values that I set.
Edit 2: The html that is produces looks like:
<span id="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity" class="ucFieldCBL" onChange="alValidate();" onClick="alPublicity('ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity');">
<input id="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_0" type="checkbox" name="ctl00$ContentPlaceHolderMetadata$Allocation1$alfPublicity$0"/>
<label for="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_0">Text1</label>
<input id="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_1" type="checkbox" name="ctl00$ContentPlaceHolderMetadata$Allocation1$alfPublicity$1"/>
<label for="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_1">Text2</label>
<input id="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_2" type="checkbox" name="ctl00$ContentPlaceHolderMetadata$Allocation1$alfPublicity$2"/>
<label for="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_2">Text3</label>
<input id="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_3" type="checkbox" name="ctl00$ContentPlaceHolderMetadata$Allocation1$alfPublicity$3"/>
<label for="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_3">Text4</label>
<input id="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_4" type="checkbox" name="ctl00$ContentPlaceHolderMetadata$Allocation1$alfPublicity$4"/>
<label for="ctl00_ContentPlaceHolderMetadata_Allocation1_alfPublicity_4">Text5</label>
</span>
It looks as if the issue stems from the lack of a value attribute available on the asp.net checkbox control as described by Dave Parslow. I'm currently trying a workaround by calling a function server side to return the text of the checkbox and using that instead.
options[i].checked will return true or false.
options[i].value will give you the value attribute of the checkbox tag.
I think your problem is not with the javascript but with the code that is populating the checkboxes. Are you binding the ArrayList as the CheckBoxList data source or iterating through the ArrayList and adding new ListItems to the CheckBoxList. If the former, consider switching to the latter and make sure that you use the ListItem constructor that takes both text and value parameters. If you look at the HTML source I suspect that you will see that the generated code has the value parameter set to on for all of your checkboxes which means that the values weren't actually bound in the codebehind.
Not 100% applicable here, but be aware that if you give a checkbox a cssclass, it gets a span wrapped around it, and the class is placed on that. This causes all sorts of cross browser problems when youre navigating the dom, or disabling checkboxes
I realised after much playing about with prerender events that I didn't actually need to know the exact value of the checkbox as the arraylist values would be in the same order as the checkboxes. I searched through the arraylist to get the position of the value that I needed and then used that position on the list of checkboxes.
It sounds a bit fiddly and I don't know if it would work for everyone but I thought I would put it up here anyway incase it helps someone else someday.
Thanks for all your help.

Resources