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: []
});
}
});
Related
I am creating a web app (using thymeleaf, html, css, javascript) and I ran into a problem. Say I have a search bar and a button like this:
Now this represents the functionality of an app and currently it can only search records from a table by their name. But I want to add some other functions like "search by population", "search by capital" etc. I was planning on creating a drop-down list next to the search bar where these options will be included, and the user will select from that list how he wants to search for a record. I can't see a way to do that. Currently this is a search bar code:
<h4 class="left">
<form ui-jp="parsley" th:action="#{/events/showByState}" th:object="${myState}" method="get">
<div class="row m-b">
<div class="child">Search by State Name:</div>
<div class="child"><input id="filter" type="text" th:field="*{officialStateName}" class="form-control input-sm w-auto inline m-r"/></div>
<div class="child box-3">
<button class="btn">Search!</button>
</div>
</div>
</form>
</h4>
So it is unclear for me how I do this because I need to specify the link for button based on what user will choose from the list. Any help is appreciated!
You can create a <select> element with options whose value indicate what the action of the form should be. Whenever its value changes, you can update the form's action.
document.getElementById('search-by').addEventListener('change', function(e) {
let searchBy = this.value;
console.log(searchBy);
this.form.action = `/events/${searchBy}`;
});
<form ui-jp="parsley" th:action="#{/events/showByState}" th:object="${myState}" method="get">
<div class="row m-b">
<div class="child">Search by
<select id="search-by">
<option value="showByState">State Name</option>
<option value="showByPopulation">Population</option>
<option value="showByCapital">Capital</option>
</select>:</div>
<div class="child"><input id="filter" type="text" th:field="*{officialStateName}" class="form-control input-sm w-auto inline m-r" /></div>
<div class="child box-3">
<button class="btn">Search!</button>
</div>
</div>
</form>
I have a set of fields which can be duplicated. Now within those fields there are also particular fields which are duplicated.
This is an example of my markup
<div class="item_1">
<button type="button" class="fluid-inline btn btn-primary add_items">Add fields</button>
<hr />
<div class="col-sm-4 m-b-10px">
<label><h5>OCCUPATION: </h5></label>
<input name=b_occ[] type="text" class="form-control" required=required>
</div>
<div class="col-sm-4 m-b-10px">
<label><h5>WORK ADDRESS: </h5></label>
<input name=b_work_add[] type="text" class="form-control" required=required>
</div>
<div class="item_victim_relation">
<div class="col-sm-4 m-b-10px">
<label><h5>VICTIM: </h5></label>
<select class="form-control" name="victim_name[]" required=required>
<option value="victim_id"><h5>Victim</h5></option>
</select>
</div>
<div class="col-sm-4 m-b-10px">
<label><h5>RELATION TO VICTIM: </h5></label>
<input name=b_relation[] type="text" class="form-control" required=required>
</div>
<div class="col-sm-4 m-b-10px">
<h5 class="text-info">(IF SUSPECT HAS RELATION TO MULTIPLE VICTIMS) </h5>
<button type="button" class="dashed-button add_victim_b">Add</button>
</div>
</div>
</div>
JS
var removeButtonV = "<button type=button class='dashed-button remove_item_v'>Remove</button>";
var removeButton = "<button type=button class='btn btn-primary m-b-10px remove_items'>Remove</button>";
$('.add_victim_b').click(function() {
$('div.item_victim_relation:last').
after($('div.item_victim_relation:first').clone());
$('.add_victim_b:last').remove();
$('.text-info:last').text("(REMOVE THESE FIELDS)");
$(removeButtonV).insertAfter(('.text-info:last'));
});
$(document).on('click', '.remove_item_v', function(){
$(this).closest('div.item_victim_relation').remove();
});
$('.add_items').click(function() {
$('div.item_1:last').after($('div.item_1:first').clone());
$('div.item_1:last').append(removeButton);
$('hr.item_b_separator:last').removeClass('hidden');
});
$(document).on('click', '.remove_items', function(){
$(this).closest('div.item_1').remove();
});
This piece of code duplicates victim and relation to victim fields. It works fine when item_1 is not yet duplicated, but when it is, those two fields are appended on the last instance of the fields inside the last instance of item_1 too. What I want to happen is for these two fields to be appended after their last instances on the item_1 where they belong.
I think my way of traversal is wrong. I've tried several methods but I can't seem to get it work.
Here is a demonstration of the problem:
DEMO
Here is a sample of what I want (each has their own class names and item_1 cannot be duplicated but it would not work if item_1 would be cloned)
jQuery is only aware of the elements in the page at the time it runs, so new elements added to the DOM dynamically are unrecognized by jQuery. To combat the problem use event delegation, bubbling events from newly added items up to a point in the DOM which was there when jQuery ran on page load. Many people use document as the place to catch the bubbled event, but it isn't necessary to go all the way up the DOM tree. Ideally you should delegate to the nearest parent existing at the time of page load.
$(document).on('click', 'button.ok', function(e){...
Using the .on() function should solve your issue.
I managed to solve it by changing my traversal methods and just assigning the fields to be added in a variable.
I have changed the handler of add_victim_b to this
var victimFields = '<div class="item_victim_relation"><div class="col-sm-4 m-b-10px"><label><h5>VICTIM: </h5></label><select class="form-control" name="victim_name[]" required=required><option value="victim_id"><h5>Victim</h5></option></select></div><div class="col-sm-4 m-b-10px"><label><h5>RELATION TO VICTIM: </h5></label><input name=b_relation[] type="text" class="form-control" required=required></div><div class="col-sm-4 m-b-10px"><h5 class="text-info">(REMOVE FIELDS) </h5><button type="button" class="dashed-button remove_victim_b"><i class="fa fa-minus" aria-hidden=true></i></button></div><div class="clearfix"></div></div>';
$(document).on('click', '.add_victim_b', function(){
var item_b_index = $(this).closest('.item_b').index('.item_b');
$(victimFields).insertAfter($('div.item_b').eq(item_b_index).find('.item_victim_relation:last'));
});
It now works perfectly as I wanted it. You may view it here:
DEMO
Alright so I have a form. In the form I have a lot of check boxes. If a person clicks on the checkbox. It shows the field below the box. If they click on the checkbox again it makes the field below the checkbox disappear and makes the field have no value.
here is the code. I have JS running the show and hide. and Html calling it.
function ShowCutSewDescription() {
var select = $('#send_item_to_cutsew');
console.log(select)
//select = parseInt(select);
if (select.attr('checked', true)) {
$('#cutsew-checked').show();
}else {
$('#cutsew-checked').hide();
}
}
<div class="form-group">
<label class="col-md-3 control-label">Sending item to Cut/Sew Manager</label>
<div class="col-md-9">
<input type="checkbox" name="send_item_to_cutsew" class="form-control input-inline input-medium" placeholder="Enter text" onchange="ShowCutSewDescription()">
</div>
Changes made
► select.attr('checked', true) to select.is(":checked")
► $('#send_item_to_cutsew') to $('[name="send_item_to_cutsew"]') since there is no element with that Id.
Working Demo
function ShowCutSewDescription() {
var select = $('[name="send_item_to_cutsew"]');
if (select.is(":checked")) {
$('#cutsew-checked').show();
} else {
$('#cutsew-checked').hide();
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group">
<label class="col-md-3 control-label">Sending item to Cut/Sew Manager</label>
<div class="col-md-9">
<input type="checkbox" name="send_item_to_cutsew" class="form-control input-inline input-medium" placeholder="Enter text" onchange="ShowCutSewDescription()">
</div>
<div id="cutsew-checked">
Sample box
</div>
I assume this is using jQuery. If so, the selector that you have input is looking for something with an id of send_item_to_cutsew.
jQuery uses css selectors as a base, as referenced by this page: https://api.jquery.com/category/selectors/
The proper way to get the input that you want based on the name is as follows:
var select = $('[name="send_item_to_cutsew]');
or you can set the id to the above like so:
<input type="checkbox" id="send_item_to_cutsew" name="send_item_to_cutsew" class="form-control input-inline input-medium" placeholder="Enter text" onchange="ShowCutSewDescription()">
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);
});
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!