Sync current selected item between radio and select - javascript

Short version
I've two forms. One with Radio-Buttons, one with Dropdowns (select).
Both have the same structure. If e.g the value of the Radio-Button changes, the dropdown-counterpart should change to the same value.
Limitations:
The ID and the name attribute of each radio and select are random. The backend will generate some random values. So i'm not able to use them. Messy, I know. But I can't change that.
The only thing that won't change is the CSS-class.
Here is what I got already:
I gave every select and every single radio button a class which clearify the value:
// All Mobile Selects
var $mobRechnung = $mobile.find('.js-notification-set--rechnung'),
$mobJahr = $mobile.find('.js-notification-set--jahr'),
$mobMonat = $mobile.find('.js-notification-set--monat'),
$mobErinnerung = $mobile.find('.js-notification-set--erinnerung');
// All Desktop Radios
var $deskRechnungBrief = $desktop.find('js-notification-set--rechnung-brief'),
$deskRechnungMail = $desktop.find('js-notification-set--rechnung-mail'),
$deskJahrBrief = $desktop.find('js-notification-set--jahr-brief'),
$deskJahrMail = $desktop.find('js-notification-set--jahr-mail'),
$deskJahrNo = $desktop.find('js-notification-set--jahr-no'),
$deskMonatMail = $desktop.find('js-notification-set--monat-mail'),
$deskMonatSMS = $desktop.find('js-notification-set--monat-sms'),
$deskMonatNo = $desktop.find('js-notification-set--monat-no'),
$deskErinnerungMail = $desktop.find('js-notification-set--erinnerung-mail'),
$deskErinnerungSMS = $desktop.find('js-notification-set--erinnerung-sms'),
$deskErinnerungNo = $desktop.find('js-notification-set--erinnerung-no');
As you see, I can't combine the radio buttons since I'm unable to use their name. So I needed to give every single value a seperate class to seperate them.
Then I thought I put them in Arrays an loop them through with jQuery.map(), but now I'm stuck. I have no idea how I should continue wihtout wiriting a novel with the code...
Let me know if you need more code.
Edit HTML Markup:
Desktop Code example. Every row is build up the same.
<div class="js-notification-set--desk>
{# Rechnung Row #}
<div class="row">
<fieldset>
<legend class="col-sm-3">Rechnung</legend>
{# Brief Radio #}
<div class="mod-formelem col-sm-1">
<input type="radio" id="__radio1__" name="__row1__" class="js-notification-set--rechnung-brief" aria-labelledby="__sr01__"/>
<label for="__radio1__" class="mod-formelem--icon" aria-hidden="true"></label>
</div>
{# E-Mail Radio #}
<div class="mod-formelem col-sm-1">
<input type="radio" id="__radio2__" name="__row1__" class="js-notification-set--rechnung-mail" checked="checked"
aria-labelledby="__sr02__"/>
<label for="__radio2__" class="mod-formelem--icon" aria-hidden="true"></label>
</div>
</fieldset>
</div>
(...)
</div>
Note: The aria-labelledby declares the label to each radio button. The buttons are in a table-like grid where the label stands at the top of the table. So there is no directed linked label.
Example for Mobile Select:
<div class="js-notification-set--mob">
{# Rechnung Row #}
<div class="row">
<div class="col-sm-4">
<label for="___select1___" class="control-label">
Rechnung
</label>
</div>
<div class="col-sm-8 js-tooltip--container">
{# select1 #}
<select data-select-type="default" data-placeholder="Rechnung"
class="form-control js-select js-notification-set--rechnung" name="Rechnung" id="___select1___">
<option value="___select1_option1___">Brief</option>
<option value="___select1_option2___" selected>E-Mail</option>
</select>
</div>
</div>
(...)
</div>

Use the index of the radio button to select the corresponding option in the <select>.
$(".js-notification-set--desk :radio").click(function() {
var index = $(".js-notification-set--desk :radio").index(this);
$(".js-notification-set--rechnung").prop('selectedIndex', index);
});

Related

Javascript hide/show elements does not work properly

I have added this checkbox to my form:
<div class="row">
<div class="form-group col">
<input type="checkbox" name="prd_presell" id="product_presell"
onclick="presellTXT()" value="TRUE" #if(!empty($product)) #if($product->prd_presell == 'TRUE') checked #endif #endif>
<label for="presell_product">Presell Product</label>
</div>
</div>
So there is an onClick function named presellTXT() which goes like this:
function presellTXT() {
var presell_checkbox = document.getElementById("product_presell"); // get checkbox
var presell_text = document.getElementById("show_presell_text"); // text div
var presell_text_input = document.getElementById("presell_product_text"); // text input
if (presell_checkbox.checked == true){
presell_text.style.display = "block";
} else {
presell_text_input.value = "";
presell_checkbox.value = "";
presell_text.style.display = "none";
}
}
So when the checkbox is checked, it basically shows the element with an id of show_presell_text:
<div class="row" id="show_presell_text">
<div class="col-lg-12">
<div class="form-group">
<label>Product Presell Text:</label>
<input name="prd_presell_text" id="presell_product_text" class="form-control" value="{{ old('prd_presell_text', !empty($product) ? $product->prd_presell_text : '') }}">
</div>
</div>
</div>
So when the page loads, it should not be showing the Product Presell Text unless the checkbox is checked.
Now if you take a look at jsfillde example, you can see as soon as the page loads, the text input appears however the checkbox is not checked at all!
So how to hide the text input when the page loads and the checkbox is not checked?
Note: I don't want to use CSS for this because I need to determine correctly if prd_presell is checked on page loads (because of #if($product->prd_presell == 'TRUE') which retrieves data from the DB) then it has to show the Product Presell Text text input.
UPDATE:
I tried adding this:
#show-presell-text.hidden {
display: none !important;
}
And adding this to the div:
<div class="row" id="show_presell_text" class="#if(!empty($product)) #if($product->prd_presell != 'TRUE') hidden #endif #endif">
But does not work and hide the element.
to hide/show the elements on load then this can be easily done by adding an if statement like so
#if (!empty($product))
<div class="row" id="show_presell_text">
<div class="col-lg-12">
<div class="form-group">
<label>Product Presell Text:</label>
<input name="prd_presell_text" id="presell_product_text" class="form-control" value="{{ old('prd_presell_text', !empty($product) ? $product->prd_presell_text : '') }}">
</div>
</div>
</div>
#endif
This will completely omit the element you want at page load if empty and you can add it via JS code. However, If you want to just hide it using CSS classes you can do this:
<div class="row" id="show_presell_text" class="#if (empty($product)) hidden #endif">
<div class="col-lg-12">
<div class="form-group">
<label>Product Presell Text:</label>
<input name="prd_presell_text" id="presell_product_text" class="form-control" value="{{ old('prd_presell_text', !empty($product) ? $product->prd_presell_text : '') }}">
</div>
</div>
</div>
If the product is empty the class will not be present and you can use CSS to set the element to display: none if the class is absent. Let me know if I can clarify further or if I got something wrong.
Edit: A better alternative for the second code block would be to add a hidden class as suggested below if the product is empty and then use it to hide it via CSS. You can then simply add or remove this class via JS as needed.
#show-presell-text.hidden {
display: none;
}
You can try out something like this.
<div class="row" id="show_presell_text" style="display: none">
By default set the display as none and based on the condition in function set it as block/ none.

Multi step form - how to show data from steps before?

Is this a good solution to check multiple radio buttons with 1 label? I have a form with multiple steps. The last step shows a summary about the previous steps and I need to get all data from there. Is there a better option? How can I get the text from the input fields and insert it to the summary? JavaScript?
$('label').click(function() {
id = this.id.split('-');
if (id[0] === '1') {
id[0] = '2';
} else {
id[0] = '1';
}
$('#' + id[0] + '-' + id[1]).prop('checked', true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="one">
<input type="radio" id="1-1" name="1-level">
<label for="1-1" id="1-1">1</label>
<input type="radio" id="1-2" name="1-level">
<label for="1-2" id="1-2">2</label>
</div>
<div class="two">
<input type="radio" id="2-1" name="2-level">
<label for="2-1" id="2-1">1</label>
<input type="radio" id="2-2" name="2-level">
<label for="2-2" id="2-2">2</label>
</div>
Add a form element to wrap your input elements in. Forms can access all the inputs that are inside of it and see their names and their values. So in this case it is important that you use the value attribute on your input elements. Start by doing the above and make your code look like the example below.
Also, be careful with id's. They need to be unique, so they can only appear once in every document. Right now the label and their input elements have the same id.
<form id="step-form">
<div class="one">
...
</div>
</form>
Like #Shilly suggested, use the FormData API. This API is designed to get all the values from a form, think input, textarea and select elements and puts all of that data into a single object. This way you can create as many form-elements as you want, add them to the form and store their values in a single object.
The data in that object will be read as key-value pairs, which in this case are the name and value attribute values. For example: ['1-level', '2'], here we see the input with the name '1-level' and the value '2'.
I would not recommend using other input elements to show your results or summary. This could be confusing for the user as it suggests input. Instead print your results in plain text or create a list.
I do not know the jQuery equivalent of many of these API's or methods, so I've used Vanilla JavaScript to create a demo which, hopefully, demonstrates what you try to accomplish.
If you have any question, I've been unclear, or have not helped you in any way. Please let me know.
const form = document.getElementById('step-form');
const summary = document.getElementById('step-summary');
const clear = document.getElementById('step-clear');
// Remove all children of the summary list.
function clearSummary() {
while(summary.firstElementChild) {
summary.firstElementChild.remove();
}
}
// Clear list on click.
clear.addEventListener('click', event => {
clearSummary();
});
form.addEventListener('submit', event => {
// Clear list first.
clearSummary();
// Create a fragment to store the list items in.
// Get the data from the form.
const fragment = new DocumentFragment();
const formData = new FormData(event.target);
// Turn each entry into a list item which display
// the name of the input and its value.
// Add each list item to the fragment.
for (const [ name, value ] of formData) {
const listItem = document.createElement('li');
listItem.textContent = `${name}: ${value}`;
fragment.appendChild(listItem);
}
// Add all list items to the summary.
summary.appendChild(fragment);
event.preventDefault();
});
<form id="step-form">
<div class="one">
<input type="radio" id="1-1" name="1-level" value="1">
<label for="1-1">1</label>
<input type="radio" id="1-2" name="1-level" value="2">
<label for="1-2">2</label>
</div>
<div class="two">
<input type="radio" id="2-1" name="2-level" value="1">
<label for="2-1">1</label>
<input type="radio" id="2-2" name="2-level" value="2">
<label for="2-2">2</label>
</div>
<div class="three">
<input type="radio" id="3-1" name="3-level" value="1">
<label for="3-1">1</label>
<input type="radio" id="3-2" name="3-level" value="2">
<label for="3-2">2</label>
</div>
<ul id="step-summary"></ul>
<button type="submit">Review form</button>
<button type="button" id="step-clear">Clear summary</button>
</form>

Repeat Selectize select field

I have a form where the user can input multiple addresses, city, street+nbr and country.
For this field to be repeated I use the jquery repeater library. For the city field I want to use a selectize input field.
I am trying to repeat those 4 fields when clicking on the button, it copies everything correctly but the selectize field does not contain inputs (i guess this is because they have the same id?) but I don't know how to instantiate another selectize instance on that object.
This is my code:
HTML:
<div class="row">
<div class="form-group col-12 mb-2 address-repeater">
<div data-repeater-list="stcity">
<div class="input-group mb-1" data-repeater-item>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="companystreet"><?=lang("flow_company_street")?></label>
<input type="text" id="companystreet" class="form-control" placeholder="<?=lang("flow_company_streetname")?>" name="companystreet" required data-validation-required-message="<?=lang("flow_company_street_validation")?>">
<div class="help-block font-small-3"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="companystreetnumber"><?=lang("flow_company_nbr")?></label>
<input type="text" id="companystreetnumber" class="form-control" placeholder="<?=lang("flow_company_streetnbr")?>" name="companystreetnumber" required data-validation-required-message="<?=lang("flow_company_nbr_validation")?>">
<div class="help-block font-small-3"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="companycity"><?=lang("flow_company_city_or_commune")?></label>
<select id="companycity" class="companycity-select" name="companycity" autocomplete="new-password" required data-validation-required-message="<?=lang("flow_company_city_or_commune_validation")?>">
<option value="" selected><?=lang("flow_company_select_city_or_commune")?></option>
<?php
foreach ($citiesbe as $city) {
//Values are prefilled from javascript
$key = strtolower($city->name_nl) . "," . $city->zip_code;
echo "<option value=\"$key\"> $city->name_nl ($city->zip_code)</option>";
}
?>
</select>
<div class="help-block font-small-3"></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="companycountry"><?=lang("flow_company_country")?></label>
<select id="companycountry" class="companycountry-select" name="companycountry" autocomplete="new-password" disabled>
<option value="BE" selected><?=lang("flow_company_country_belgium")?></option>
</select>
</div>
</div>
</div>
</div>
</div>
<button type="button" data-repeater-create class="btn btn-primary">
<i class="ft-plus"></i> Add new address
</button>
</div>
Javascript:
// Custom Show / Hide Configurations
$('.address-repeater').repeater({
show: function () {
$(this).slideDown();
},
hide: function(remove) {
$(this).slideUp(remove);
}
});
Since the button is not the selectize element, I don't know how to assign it to the newly created element.
Funny, I ran into a similar problem, but couldn't find a solution, so I had to work it out myself. Here's an explanation to the solution I applied to get selectize and jquery.repeater to work nicely.
First, checking through the browser console, you'll find out that selectize removes all the select options except the empty option, and uses it to populate it's own dropdown which is generated via javascript. This becomes a problem for jquery.repeater because it only repeats or creates a duplicate based on the initial page load, and not after. So, what gets repeated is the only select option left in the select element, which in this case (unfortunately) is the empty select option. Here's a pen explaining this, feel free to toggle the category targeting selectize in the select element to see for yourself.
So, here are the steps I took to get it to work nicely:
On repeating of the form (show() of the repeater instance), you'll need to delete the duplicated element completely from the DOM.
Create another select element(s) in the DOM with the preferred (or same) attributes/options.
Instantiate selectize on the newly created select element(s).
I'll suggest you add a class to the .form-group wrapper housing the .companycity-select select element. This will help to append a new select element at the exact place only, since there are other .form-group in the code. Check my solution below:
// Assuming your have the select element wrapper as <div class="form-group select-wrapper">
$('.address-repeater').reapeter({
show: function() {
$(this).slideDown();
// Remove the created element
$(this).find('.companycity-select').remove();
// Repeater rewrites your name attributes to avoid collisions within the same form,
// so we need to follow this same rule
// Get the length of the currently repeated items, to be used as the index for new elements
var count = $('div[data-repeater-item]').length;
// Create the new select element. The select name is based on the new name by repeater
var new_select_option = '<option value="" selected>Select city or community</option>';
var new_select_element = '<select id="companycity" class="companycity-select" name="stcity['+count+'][companycity]" autocomplete="new-password" required>'+new_select_option+'</select>';
// Append newly created element to DOM. Remember the new class added to the form-group?
$(this).find('.form-group.select-wrapper').append(new_select_element);
// Create a new instance of selectize on the new select element
$(this).find('.companycity-select').selectize({
// Populate your select options data via ajax,
// see docs: https://selectize.dev/docs.html
valueField: '',
labelField: '',
searchField: [],
options: []
});
}
});

Cloning a DIV with Multiple DIVs that include a select inside a modal that uses chosen()

enter image description hereI have a modal which opens a form, the form has a line with 4 fields
Select input field
Text
Select input field (filtered by first select)
Select input field (filtered by second select)
I want to clone this line with empty values. I was able to clone it, but in the cloned line, whenever I try to select a new value, it expands the first field in first line only.
Modal Code
<div id="add-ins-company">
<div class="form-group">
<div class="col-md-4">
<div class="input-group col-md-12">
<select id="mq_ins_company" name="mq_ins_company[]" class="modal-select-chosen" data-placeholder="Insurance Company" onchange="getpolicyclass(this.value);" required>
<option value=""></option>
<?php
$company_id = mysqli_real_escape_string($GLOBALS['con'], $_SESSION['company_id']);
$sql = "select * from insurance_companies where ins_comp_company = $company_id";
$data = FetchMultipleData($sql);
for($i=0;$i<count($data);$i++) {
?>
<option value="<?php echo $data[$i]['ins_comp_id']; ?>"><?php echo $data[$i]['ins_comp_name'];?></option>
<?php } ?>
</select>
</div>
</div>
<div class="col-md-2">
<input type="email" id="mq_fees" name="mq_fees[]" class="form-control" placeholder="Fees" required="required">
</div>
<div class="col-md-3">
<div id="mq_class"></div>
</div>
<div class="col-md-3">
<div id="mq_size"></div>
</div>
</div>
</div>
JavaScript
function addcompanyrow() {
var row = $('#add-ins-company').clone(true);
$(row).insertAfter("#add-ins-company");
}
Any Suggestion on the following:
Clear all input values
Remove the chosen class and reapply it on the cloned line
In general:
If the list is dynamic you should have some workaround, such as:
Consider move the php generations to external ajax calls hosted in js functions.
Use a binding of option of 3rd-parties like JQuery/KnockoutJS.
Anyway, if i understand your specific question well:
Clearing input values is possible like this:
$('<the_input_selector>').removeAttr('value');
OR
$('<the_input_selector>').val('');
For clearing "select" elem you can also use:
$('<the_select_selector>').val('');
if the empty option exists. OR you can set it to first one:
$('<the_select_selector>').prop('selectedIndex',0);
Removing class is possible too:
$('<the_select_selector>').removeClass('modal-select-chosen');
You can then add any other class:
$('<the_select_selector>').addClass('<any_other_class>');
Good luck!

POST DATA issues when adding new elements to the page

Hi all I have a form in which I dynamically add in a new row consisting of a text box and check button on button press. However I need some sort of way to know which checkbuttons were pressed in the post data and therefore need a value field consisting of an ID on each of the the check buttons, code is seen below:
<div id='1'>
<div class="template">
<div>
<label class="right inline">Response:</label>
</div>
<div>
<input type="text" name="responseText[]" value="" maxlength="400" />
</div>
<div>
<input type="radio" name="responseRadio[]" value="" />
</div>
</div>
<div>
<input type="button" name="addNewRow" value="Add Row" />
</div>
</div>
JS to add new row:
var $template = $('.template');
$('input[type=button]').click(function() {
$template.clone().insertAfter($template);
});
can anyone suggest a good way to help me know in the post data which text field, links to which check button, and to know if it was pressed?
at the moment if you were to add 3 rows and check row 3 I have no way of identifying that row three was the button pressed - This is my issue
after you cloned it, change the name so you know about this input
also it's good to have a counter for naming:
like : 'somename[myInput' + counter + ']'
update:
var counter = 0;
var $template = $('.template');
$('input[type=button]').click(function() {
counter++;
$template.clone().attr('name' , 'somename[myInput' + counter + ']').insertAfter($template);
});
now you have array named:somename which you can have a loop over its content on your form handler.

Categories

Resources