Hide virtual keyboard after selecting value on Select2 v3 - javascript

I'm using select2 v.3.4.5 solely for my project. Currently, when viewing on mobile, the keyboard does not close after it open and value selected, I would like to close it thought. I would like open only when user focus on it and type something.
$(document).ready(function() {
$('#Salutation,#Gender').select2()
.on('change select-open', function(e) {
setTimeout(function() {
$('.select2-input').blur();
}, 500);
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.min.js"></script>
<div class="container">
<div class="row">
<div class="col-xs-4 col-xs-offset-4">
<h3>Application Form</h3>
<form class="form" action="/action_page.php">
<div class="form-group">
<label for="GivenName">Given Name:</label>
<input class="form-control" type="text" id="GivenName">
</div>
<div class="form-group">
<label for="Surname">Surname:</label>
<input class="form-control" type="text" id="Surname">
</div>
<div class="form-group">
<label for="Salutation">Salutation:</label>
<select class="" name="" id="Salutation">
<option value="Mrs">Mrs</option>
<option value="Mr">Mr</option>
<option value="Miss">Miss</option>
</select>
</div>
<div class="form-group">
<label for="Gender">Gender:</label>
<select class="" name="" id="Gender">
<option value="Female">Female</option>
<option value="Male">Male</option>
<option value="Transgender">Transgender</option>
</select>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
As this js
$('#Salutation,#Gender').select2()
.on('change select2-open',function(e){
setTimeout(function(){
$('.select2-input').blur();
}, 500);
});
I set input-search box to blur already but keyboard does not close.
How can I do to archive this purpose? Please kindly help. Thanks.
PS: Understandably, select2 v4 fixed this bug, yet I could not upgrade my select2 version since my project is solely depend on v3.*

Ensuring the search box does not autofocus
There is no way to do this well in Select2 - whenever you try to call the blur() function on this input, it just refocuses it.
However, by listening on the open event, we can replace the search box with our own one, that does not autofocus. Only the currently active search box has the class select2-focused, so we use that to find it, and then create a new search box (with the same select2-input class so it retains the same look and feel), and then re-implement the search feature ourselves, finally inserting that into the DOM, and removing the old search box.
Not showing the keyboard after closing the selection popup
Select2 seems to try and implement its own blur() event in a very weird way (see here).
So, rather than try and use that, take advantage of CSS selectors. The :focus selector in CSS selects anything that has focus. Since Select2 doesn't actually add any new DOM elements (i.e. once in the HTML, it becomes standard <div> elements, <input> elements, etc), we can find the one that has focus, and successfully call blur on it.
Therefore, by calling $(":focus").blur(), we find the DOM element that currently has focus, and we blur it.
Also, by using select2-close as our event, rather than change, the keyboard won't open even if the user doesn't select an item, but instead clicks outside of it.
I have tested it, and it does work for me on an iPad running iOS 11. Here is the final, working code:
$(document).ready(function() {
$("#Salutation,#Gender").select2().on("select2-open",()=>{
let oldSearchBox = $(".select2-focused")[0]; //Get the current search box
let parent = oldSearchBox.parentNode; //The parent of the search box (i.e. the element that holds it)
let search = document.createElement("input"); //Create a new input box
search.classList.add("select2-input"); //Make it look like the old one
search.addEventListener("keyup", ()=>{ //Whenever someone releases a key, filter the results
let results = parent.parentNode.getElementsByClassName("select2-result"); //Get all of the select box options
let query = search.value.toLowerCase(); //Get what the user has typed (in lower case so search is case-insensitive)
for (let result of results) { //Loop through all of the select box options
let resultText = result.children[0].childNodes[1].nodeValue.toLowerCase(); //Get the text for that option (also in lower case)
result.style.display = (resultText.indexOf(query)==-1) ? "none" : "block"; //If the result text contains the search, it is displayed, otherwise it is hidden
}
})
parent.appendChild(search); //Add the new search box to the page
oldSearchBox.remove(); //Remove the old one
});
$("#Salutation,#Gender").select2().on("select2-close",()=>{
setTimeout(()=>{
$(":focus").blur();
}, 50);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.min.js"></script>
<div class="container">
<div class="row">
<div class="col-xs-4 col-xs-offset-4">
<h3>Application Form</h3>
<form class="form" action="/action_page.php">
<div class="form-group">
<label for="GivenName">Given Name:</label>
<input class="form-control" type="text" id="GivenName">
</div>
<div class="form-group">
<label for="Surname">Surname:</label>
<input class="form-control" type="text" id="Surname">
</div>
<div class="form-group">
<label for="Salutation">Salutation:</label>
<select class="" name="" id="Salutation">
<option value="Mrs">Mrs</option>
<option value="Mr">Mr</option>
<option value="Miss">Miss</option>
</select>
</div>
<div class="form-group">
<label for="Gender">Gender:</label>
<select class="" name="" id="Gender">
<option value="Female">Female</option>
<option value="Male">Male</option>
<option value="Transgender">Transgender</option>
</select>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>

I have an alternative work around that I've been using for about a week now. So far it seems to work well on all android and ios devices I've tried. I use this on select2 instances that have 'multiple' set to false (i.e. 'single' type). In this case, I want the user to make a single selection, and the the keyboard should disappear.
In short, during the select2-close event you set a flag that indicates that you want to disable any focus event the select2-focusser receives. When the focus event is triggered, you check if the flag is set and if so you simply move the focus to another target. I add the flag as a data property and I reset this flag after a second using a setTimeOut.
This works because the select2 close handler is split into 2 parts, and the 'select2-close' event is triggered at the end of part 1 (and before part 2). Part 1 is the 'abstract' close handler, which actually closes the selection dialog, and sets the control's value. Part 2 is the 'single' close handler, which really just causes the select2 to refocus on itself (which is the problem!).
For me, I added a '.focus-bait' class to one of my nav bar buttons, and I use this to divert focus during the focusser's focus event execution. If you have issues getting this refocus step to work, try a different element (I had a problem getting it to work on a button I had made for the purpose of focusing on. I'm still not sure why, but I didn't investigate more as my nav button solution worked perfectly for my needs).
$('body').on('focus','.select2-focusser', function(e) {
let isDisabled = $(this).parent().first().data("disable-focus");
if (isDisabled) {
console.log('Focusser: focus event aborted');
$('.focus-bait').focus();
}
});
//select2_focus_ctrl is a class that I add to any select2 container
//that I wish to use this focus logic e.g. add it to #Salutation,#Gender
$('body').on('select2-close','select2_focus_ctrl', function(e) {
console.log('Focusser: disabling focus event');
if ($(this).data('select2').opts.multiple != true) {
$(this).prev().data("disable-focus",true);
setTimeout(function() {
console.log('Focusser: enabling focusser');
$(this).prev().data("disable-focus",false);
}, 1000);
}
});
Here is a full code snippet. While writing it I noticed that if the select2 container is sourced from a 'select' element, the 'multiple' property does not exist (mine used a 'div'), so I've changed one line of code: .opts.multiple != true (instead of == false).
$(document).ready(function() {
$('#Salutation').select2(
);
$('body').on('focus','.select2-focusser', function(e) {
let isDisabled = $(this).parent().first().data("disable-focus");
if (isDisabled) {
console.log('Focusser: focus event aborted');
$('.focus-bait').focus();
}
});
$('body').on('select2-close','.select2_focus_ctrl', function(e) {
console.log('Focusser: disabling focus event');
if ($(this).data('select2').opts.multiple != true) {
$(this).prev().data("disable-focus",true);
setTimeout(function() {
console.log('Focusser: enabling focusser');
$(this).prev().data("disable-focus",false);
}, 1000);
}
});
$('body').on('change','#Salutation', function(e) {
let theVal = $('#Salutation').select2("val");
$('#currentVal').val(theVal);
});
});
body {
background: #dddddd;
padding: 20px;
font-family: Helvetica;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
cursor: pointer;
}
button:focus {
background: #fff;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.js"></script>
<button type="button" class="focus-bait">
Just the bait!
</button>
<br>
<div>
<input id="currentVal" style="height:20px;width:150px"/>
</div>
<br><br>
<select class="select2_focus_ctrl" id="Salutation" style="width:200px;">
<option value="Mrs">Mrs</option>
<option value="Mr">Mr</option>
<option value="Miss">Miss</option>
<option value="Esquire">Esquire</option>
<option value="Other Options">Other Options</option>
<option value="Just for interest">Interesting longer item</option>
</select>

Related

Change Add to Cart text on hover

Is it possible to change the Add to cart button in Woocommerce to "Select size", for example, if a customer has yet to choose an (required) option. Then, change it back to "add to cart" once the option is selected?
The Website of manolo blahnik has this feature, and I find it's a good UX for customers. On their website, the first stage is "Add to cart".
If someone hovers over the button, but hasn't chosen their option, it displays "Please select a size".
But if someone has choosen an option, it stays as "Add to cart".
On Mobile, because there is no hover like on pc, it always shows "Please select a size" until the option is chosen, then it changes to "Add to cart".
I'm wondering if it is possible to do this with woocommerce.
You can use mouseover and mouseout event handlers on the Add to cart button. The following code snippet demonstrates the functionality.
On mouseover of the button, the values of the required form fields are checked and the button text and title are amended using the data-warn attribute of the form field.
On mouseout the button text and title are reset using the content of the data-title attribute on the button.
// handle to button
var addToCartBtn = document.getElementById('add-to-cart-button');
// 'mouseover' event handler
addToCartBtn.addEventListener('mouseover', function(event) {
// get all form elements
var inputs = this.form.elements;
for (var i = 0; i < inputs.length; i++) {
// find the first empty required field
if (inputs[i].required && inputs[i].value == '') {
// set the button's mouse over text
event.target.title = inputs[i].dataset.warn;
// set the button's text
event.target.innerHTML = inputs[i].dataset.warn;
break;
}
}
});
// 'mouseout' event handler
addToCartBtn.addEventListener('mouseout', function(event) {
event.target.innerHTML = event.target.dataset.title;
event.target.title = event.target.dataset.title;
});
.form-field {
margin: 20px;
}
#add-to-cart-button {
font-size: 18px;
width: 200px;
height: 50px;
}
<form action="#" name="add-to-cart-form">
<div class="form-field">
<label>
<span>Select Size:</span>
<select name="item-size" data-warn="Please choose a size" required>
<option value="">Choose a size</option>
<option value="s">Small</option>
<option value="m">Medium</option>
<option value="l">Large</option>
</select>
</label>
</div>
<div class="form-field">
<label>
<span>Select Colour:</span>
<select name="item-colour" data-warn="Please choose a colour" required>
<option value="">Choose a colour</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
</label>
</div>
<div class="form-field">
<button type="submit" name="add-to-cart-button" id="add-to-cart-button" title="Add to Basket" data-title="Add to Cart">Add to Basket</button>
</div>
</form>
Yes, it is possible to change the text on hover. You could do something like this;
#cart-btn {
width: 200px;
background: #000;
color: #fff;
}
#cart-btn:after{
content:'ADD TO BAG';
}
#cart-btn:hover:after{
content:'PLEASE SELECT SIZE';
}
<button id="cart-btn" type="button"></button>
This is just the CSS part of how you can get the result
.textSwap::before {
content: "Add to Cart";
}
.textSwap:hover::before {
content: "Please Select";
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" rel="stylesheet"/>
<style>
.textSwap
{
min-width:200px;
}
.textSwap::before {
content: "Add to Cart";
}
.textSwap:hover::before {
content: "Please Select";
}
</style>
<button type="button" class="btn btn-secondary btn-lg textSwap"></button>

Angular 2 how can i add click event inside option?

This is my html,When i click option "new-item" it will open input type box , and then i enter value it want to add to select option
<form (submit)="addItem()">
<input type="text" [(ngModel)]="add.name" name="name">
<input type="text" [(ngModel)]="add.price" name="price">
<input type="text" [(ngModel)]="add.description" name="description">
<select [(ngModel)]="add.type" name="room-type">
<option [value]="c">Select</option>
<option>BreakFast</option>
<option>Lunch</option>
<option>Dinner</option>
<option><button (click)="addSelect()">Add-item</button></option>
<input *ngIf='edited' type="text" >
</select>
and my type script is,
addSelect() {
this.edited = true;
}
constructor() {
this.edited = false;
}
You can't add such an event to an <option>.
You can see that the event doesn't fire in all browsers (the only browsers it works in is < ie11 and Firefox):
$("#trig").click((event) => console.log(event));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select>
<option>default</option>
<option id="trig">trigger</option>
</select>
The tag does not propagate down any click events. So any click events you try and allocate inside an option will not work. Your best bet is to look at the value you receive in the onChange() callback and then turn on another component which allows the user to enter data. You could even use a window.prompt() to get such data.
You can instead do this:
<select (change)="onChange($event.target.value)">
onChange(val) {
console.log(val);
this.edited = false;
}
For further information on implementing this approach, see: How can I get new selection in "select" in Angular 2?

Action listener for select's once form is reset

I have a server form with input, select & radio, and it occasionally need to be reset, so I'm using the jQuery function .trigger('reset') and this works great except I can't seem to have an action triggered once that happens. e.g. .on("reset") or .on("change") on my <select>'s.
Have a look at the example bellow; click on a select field and chose something, then input a name and click reset, the value are reset but, the actions reset or change are not called on the <select>'s.
$('select[name="opt"]').on("click reset change",function(){
var selected = $(this).val();
$(".jobs>div").hide(); // Hide all jobs first.
$(".jobs>."+selected).show(); // Show selected job.
});
$(".reset").on("click",function(){
$('form.theff').trigger("reset");
});
.theff * {
display:block;
margin:10px;
}
.jobs>div {
display:none;
background:gray;
padding:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form class="theff">
<input placeholder="Your name..">
<select name="opt">
<option selected>Select Job</option>
<option value="banker">Banker</option>
<option value="programmer">Programmer</option>
</select>
<div class="jobs">
<div class="banker">
Really? a banker?
</div>
<div class="programmer">
Great, your a programmer!
</div>
</div>
<button>Submit</button>
Reset
</form>
The form is not the select, triggering reset on the form wouldn't trigger an event handler set to a completely different element.
You probably want to do
$(".reset").on("click",function(){
$('form.theff').get(0).reset();
$('select[name="opt"]').trigger('change');
});

Show a dialog box next to a textarea without pop-up or alert box

I want to show a short message besides a textarea once we click inside the textarea.
Here is the simple code that i need to modify :
<textarea id="txt" ></textarea>
and :
$('#txt').click(function(){
// what should i put here to show a dialogbox besides textarea ?
});
Here is a fiddle demo except that i need to put whatever i want as a message once we click inside textarea.
I am a complete newbie so please bear with me if i didn't put things the way it should. Thank you.
input, textarea, select {
display: block;
}
<form>
<p>Try submitting an empty form and one with invalid email addresses.</p>
<label for="one">One Email: </label><input type="email" id="one" required data-errormessage-value-missing="Something's missing" data-errormessage-type-mismatch="Invalid!">
<label for="another">Another Email: </label><input type="email" id="another" data-errormessage="Generic error message">
<label for="textarea">A textarea: </label><textarea id="textarea" required data-errormessage-value-missing="Add some text"></textarea>
<select required data-errormessage-value-missing="Please, pick one">
<option selected disabled value="">Pick one</option>
<option value="1">One</option>
</select>
<button>Submit</button>
</form>
You could do something like the following - and I would use focus rather than click . The following code adds the text message you need besides your textarea.
If you want to style the message with an arrow too, have a look at this: cssarrowplease.com
// show hidden message on focus
$('#txt').on('focus', function() {
$('#txt-message').show();
});
// hide hidden message on blur - optional extra
$('#txt').on('blur', function() {
$('#txt-message').hide();
});
/* start message hidden */
#txt-message {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="txt"></textarea>
<span id="txt-message">message here</span>
Add:
<span id='shortMessage'></span>
tag right after the textarea div.
Then replace your comment with:
$('#shortMessage').innerHTML('your message');
Hope this will help you .
$(document).ready(function() {
$('#textarea').click(function() {
$('#showMsgId').text("some message .......")
});
});
input,
textarea,
select {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<p>Try submitting an empty form and one with invalid email addresses.</p>
<label for="one">One Email:</label>
<input type="email" id="one" required data-errormessage-value-missing="Something's missing" data-errormessage-type-mismatch="Invalid!">
<label for="another">Another Email:</label>
<input type="email" id="another" data-errormessage="Generic error message">
<label for="textarea">A textarea:</label>
<div style="width: 100%; overflow: hidden;">
<textarea id="textarea" required data-errormessage-value-missing="Add some text" style="width: 200px; float: left;"></textarea>
<span id="showMsgId" style="margin-left: 10px;"></span>
</div>
<select required data-errormessage-value-missing="Please, pick one">
<option selected disabled value="">Pick one</option>
<option value="1">One</option>
</select>
<button>Submit</button>
</form>
Here is the fiddle for my non-JavaScript alternative.
Pete's answer works if you are satisfied with simply displaying text. If you need the info-box to look pretty and be displayed above the other elements then you will need something different like this:
CSS:
.cPopTable {
position: absolute;
top: 50px;
right: 200px;
background-color: #ffffff;
z-index: 10;
display:none;
}
.cContainer:active .cPopTable {
display:table;
}
HTML:
<div class="cContainer">
<textarea id="txt">Default text here</textarea>
<table class="cPopTable"><tr><td>message pop-up here</td></tr></table>
</div>
Also, the benefit is not using any JavaScript. In fact, unless you are worried about really old browsers you can easily handle all the tasks like these using CSS z-index and event-processing as shown in this example.
You can easily change the position and the way the box is displayed (font, background, etc.) by working with the cPopTable CSS.

How to add same from input area when user press a button?

I am doing a form right now, I want to automatically add another input area, same as the line above, when user press a button.
<div class="row" id="1">
<div class="form-group col-lg-2">
<select class="form-control" id="select">
<option selected>Tag Name</option>
<option value="p">p</option>
<option value="br">br</option>
</select>
</div>
<div class="form-group col-lg-2">
<select class="form-control" id="class">
<option selected>Tag Class</option>
<option value="Day">Day</option>
<option value="BlockTime">BlockTime</option>
<option value="BlockTitle">BlockTitle</option>
<option value="Session">Session</option>
<option value="Person">Person</option>
<option value="Firm">Firm</option>
</select>
</div>
<div class="form-group col-lg-7">
<textarea class="form-control" rows="3" id="textArea">Please put the content inside this html tag.</textarea>
</div>
<div class="form-group col-lg-1">
<input type="button" class="btn btn-default" onclick="addLine()" value="Add">
</div>
</div>
This is a line of input area, I want to add the same html below the input area we have now when user press the "Add" button. Maybe using JQuery?
It should looks like this one.
This is what I tried:
function addLine() {
$('#1').clone().attr('id', '').appendTo('form');
}
For now, it seems work, but how should I do if I want to add id to the new created element, say, 2, 3, 4?
Also I am not sure am I did it the right, or best way.
Solution by jQuery
var n = 8 // adjust it in some way
var inputArea = ['<div class="form-group col-lg-'+n+'">',
'<textarea class="form-control" rows="3" id="textArea-'+n+'">',// let's be nice and not use same IDs twice
'Please put the content inside this html tag.',
'</textarea></div>'].join('')
$('.row').append(inputArea);
However make sure that your back end is ready to handle that input.
EDIT:
The solution might not be fancy and using clone() is completely fine too.
To keep track of ids I would add a simple variable like n that I would increment every time a new input area is added, and then add it to id.
So, init
var n = 0;
In addLine:
n++;
Set the id (doable in addLine too)
$target.attr('id', 'inputArea-'+n);//Assuming that $target is the inputArea in question
You can copy from a blueprint structure in the DOM and append your copy after the button.
var addline = function() {
var invisibleNewLine = jQuery('#blueprint').clone();
var visibleNewLine = invisibleNewLine.removeClass('invisible');
jQuery('#target').append(visibleNewLine);
};
jQuery('#add-line').click(addline);
Remove the onClick handler on the element and bind the event using jQuery.
<button id="add-line" class="btn btn-default">Add</button>
See the fiddle here: JSFiddle

Categories

Resources