Select2 Bootstrap Modal with Modal Scroll - javascript

Update:
I added this:
$("#id_project").select2({dropdownParent: $(".modal-body")});
...and this causes the dropdown to be correctly placed, and the search can be typed into. Unfortunately...this causes the data delivered to be cleared out, and no options are available to be selected.
I have a form that is populated in a Bootstrap modal that looks like this:
<form method="post" action="/dataanalytics/sparc/tasks/create/" class="js-task-create-form">
<input type="hidden" name="csrfmiddlewaretoken" value="W6cnRq9zPDvUdQOpqceXPVulbWJAMFazRStzwnZhLi8UEqa87SYiRKmMoHAKwmvb">
<div class="modal-body">
<div class="form-group">
<select name="project" data-minimum-input-length="2" class="form-control select2-hidden-accessible" required="" id="id_project" data-autocomplete-light-url="/dataanalytics/projectautocomplete/" data-autocomplete-light-function="select2" tabindex="-1" aria-hidden="true">
<option value="" selected="">---------</option>
</select>
<span class="select2 select2-container select2-container--bootstrap select2-container--focus" dir="ltr" style="width: 505.091px;">
<span class="selection"><span class="select2-selection select2-selection--single" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-labelledby="select2-id_project-container">
<span class="select2-selection__rendered" id="select2-id_project-container">
<span class="select2-selection__placeholder">
</span>
</span>
<span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span></span></span><span class="dropdown-wrapper" aria-hidden="true">
</span>
</span>
</div>
<div class="form-group">
<select name="dataSources" data-minimum-input-length="2" class="form-control select2-hidden-accessible" id="id_dataSources" data-autocomplete-light-url="/dataanalytics/datasourceautocomplete/" data-autocomplete-light-function="select2" multiple="" tabindex="-1" aria-hidden="true">
</select>
<span class="select2 select2-container select2-container--bootstrap" dir="ltr" style="width: 505.091px;">
<span class="selection"><span class="select2-selection select2-selection--multiple" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="-1">
<ul class="select2-selection__rendered">
<li class="select2-search select2-search--inline">
<input class="select2-search__field" type="search" tabindex="0" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="textbox" aria-autocomplete="list" placeholder="" style="width: 0.75em;">
</li>
</ul>
</span>
</span>
<span class="dropdown-wrapper" aria-hidden="true">
</span>
</span>
</div>
</div>
</form>
</div>
</div>
The first form group with the select2 single exhibits the problematic behavior. The second form group with the select2 multiple works as expected. Why is there a disparity here?
JavaScript:
var loadForm = function () {
var btn = $(this);
$.ajax({
url: btn.attr("data-url"),
type: 'get',
dataType: 'json',
beforeSend: function () {
$("#modal-task").modal("show");
},
success: function (data) {
$("#modal-task .modal-content").html(data.html_form);
}
});
};
Versions:
jQuery: 1.12.1
Select2: 4.0.5
Bootstrap: 4
Everything works great in Chrome. In Firefox, the Select2 boxes in the modal don't allow typing in the search inputs. This is a known issue (https://select2.org/troubleshooting/common-problems) but none of the known solutions appear to work for me.
To solve this issue, I added this code to set the dropdownParent of each Select2:
$.fn.select2.defaults.set("dropdownParent", $('#modal-task'));
This allows typing in the search inputs. However, my modal is long enough that it requires scrolling. If the modal is scrolled beyond the original position, clicking on a Select2 box causes the choices and the search input to appear above the box at the top of the modal. This makes sense, because all of the Select2 boxes were tied to the modal itself with dropdownParent.
How do I prevent this behavior and force the Select2 choices and search input to appear normally (directly above or below the Select2 depending on where it is in relation to the window edge)? Also, I have Select2 boxes on the page even when a modal is not activated, so affecting all Select2 boxes in this manner is not ideal.
Update: I tried swapping the other code for this line:
$.fn.modal.Constructor.prototype.enforceFocus = function () {};
This has the same effect as doing nothing at all: search inputs don't work in Firefox, but dropdowns are correctly placed.
Update 2: I tried this:
$('#id_project').set("dropdownParent", $('#id_project'));
This caused the dropdown to not appear anywhere, and the options are gone (replaced by ---------).
Update 3: I tried this...
$('#modal-task').css('overflow','visible');
...which resulted in the search input working...but modal scrolling is now broken. In addition, the dropdown is slightly misaligned on the left edge of the Select2 box.

This works fine for me
$(document).ready(function () {
$('select.select2:not(.normal)').each(function () {
$(this).select2({
dropdownParent: $(this).parent().parent()
});
});
});

just use select2 like this to bypass bootstrap modal bugs:
$('.my-select2').each(function () {
$(this).select2({
dropdownParent: $(this).parent(),// fix select2 search input focus bug
})
})
// fix select2 bootstrap modal scroll bug
$(document).on('select2:close', '.my-select2', function (e) {
var evt = "scroll.select2"
$(e.target).parents().off(evt)
$(window).off(evt)
})

I'm pretty much late, could help someone else. If you have tabindex = -1 on your modal then you may not be able to type. Try to remove it. Worked for me.

For me I was using select2 v4 and bootstrap modal. The change event was working with older versions of select2.
I needed to update my event listeners from
selectList.on('change', function(e) {
to select (add item)
selectList.on('select2:select', function(e) {
and unselect (remove item)
selectList.on('select2:unselect', function(e) {
https://select2.org/programmatic-control/events

First of all in select2 options must have
dropdownParent: $(this).parent(),// That fix weird positioning select2 input
After that we doing little trick when select2 opening event. I realized if modal height smaller than window height when select2 opening no problem for scrolling even after need scrolling.
So we put overflow adjustments on select2 events. When opening select2 set modal body to no overflow, after select2 open set back to default.
$(document).on("select2:opening", (e) => {
$('.modal-body').css('overflow', 'visible');
});
$(document).on("select2:open", (e) => {
$('.modal-body').css('overflow', 'auto');
});
That will fix your problem.

Related

Close list of links after click

I have this code:
<input id="ville" placeholder="Enter a city">
<ul class="suggestions">
<li data-vicopo="#ville">
<strong data-vicopo-code-postal></strong>
<span data-vicopo-ville></span>
</li>
</ul>
<script src="https://vicopo.selfbuild.fr/api.js"></script>
$(document).on('click', '.suggestions li', function () {
$('#ville').val(
$(this).find('[data-vicopo-code-postal]').text()
);
});
When I click on my chosen city, the list of suggested cities do not disapear. What easy fix can I do so that when clicking, the display of suggestions close or hide?
Thanks
Insert the below code to always show the suggestions list after you have hidden with .hide().
The user can click back into the input field and start typing which will then show the list again, or by clicking on it.
$('#ville').on('click keyup', function() {
$('.suggestions').show();
})

Protractor : Selection of an element from Popup value

We have some textboxes where the value needs to be selected from a popup list. The elements and the popup are like this:
The related html codes are as follows:
<div _ngcontent-c6="" class="col px-0">
<input _ngcontent-c6="" aria-multiline="false" autocapitalize="off"
autocorrect="off" class="form-control ng-dirty ng-valid open ng-touched"
formcontrolname="ESYSITENAME" id="esySiteName" name="" placeholder=""
role="combobox" type="text" autocomplete="off" aria-autocomplete="list"
aria-expanded="true" aria-activedescendant="ngb-typeahead-2-0"
aria-owns="ngb-typeahead-2">
<ngb-typeahead-window class="dropdown-menu show ng-star-inserted"
role="listbox" id="ngb-typeahead-2" style="top: 39px; left: 0px;">
<button class="dropdown-item ng-star-inserted active" role="option"
type="button" id="ngb-typeahead-2-0">
<ngb-highlight _ngcontent-c6="" _nghost-c25="" class="ng-star-inserted">
<span _ngcontent-c25="" class="ngb-highlight ng-star-inserted">
Bull Run Elementary School
</span>
</ngb-highlight>
</button>
</ngb-typeahead-window>
</div>
I have tried to select the Popup element using different strategies like:
let EsyNamePopup = $('#ngb-typeahead-2-0 > ngb-highlight > span');
await helpers.waitForElementVisibility(EsyNamePopup);
await helpers.clickWhenClickable(EsyNamePopup);
// or following way:
let EsyNamePopup = element(by.cssContainingText('span', 'Bull Run Elementary School,));
await EsyNamePopup.click();
None of them worked but got following error messages:
NoSuchElementError: No element found using locator: By(css selector, #ngb-typeahead-2-0 > ngb-highlight > span)
Is there a better strategy to select these elements?
I think you can try a long sleep before click on the pop option. If long sleep can fix your issue, it proves your wait function waitForElementVisibility has issue or you not give sufficient wait time.
await $('input#esySiteName').sendKeys('Bull');
await browser.sleep(15000)
await $('#ngb-typeahead-2-0 > ngb-highlight > span').click()
You could set up breakpoints and debug your code by following the steps in here.
http://www.protractortest.org/#/debugging
Might want to verify if sendkeys will initiate the typeahead popup or if element needs to be focused in order for that.

Run js when pop over text input is loaded

Wanted to have cleave.js to format text input on the fly.
I have 2 text inputs
HTML text input and
also a pop over text input whenever search icon is clicked.
The issue is on popover text input where cleave text formating is not
working.
I believe it could be related to the element hasn't exist somehow? I have try to listen to listener but no luck so far. .on('shown.bs.popover)
My code as as per below
https://jsfiddle.net/fairul82/y3kf92oq/
Libraries used : cleave,js , bootstrap popover , jquery
HTML
<div class="container">
<h3>Bootstrap 3 Popover HTML Example</h3>
<input type="text" class="input-element"><br>
<ul class="list-unstyled">
<li><a data-placement="bottom" data-toggle="popover" data-
container="body" data-placement="left" type="button" data-html="true"
href="#" id="login"><span class="glyphicon glyphicon-search" style="margin:3px 0 0 0"></span></a></li>
<div id="popover-content" class="hide">
<form class="form-inline" role="form">
<div class="form-group">
<h1>
My Content
</h1>
<input type="text" class="input-element"><br>
</div>
</form>
</div>
//JS
$("[data-toggle=popover]").popover({
html: true,
content: function() {
return $('#popover-content').html();
}
});
$("[data-toggle=popover]").on('shown.bs.popover', function() {
// alert('called back');
const cleave = new Cleave('.input-element', {
numeral: true,
numeralThousandsGroupStyle: 'thousand'
});
});
const cleave = new Cleave('.input-element', {
numeral: true,
numeralThousandsGroupStyle: 'thousand'
});
Here is solution https://jsfiddle.net/ztkv8w60/19/
According to authority document https://github.com/nosir/cleave.js, it has a note .input-element here is a unique DOM element. If you want to apply Cleave for multiple elements, you need to give different css selectors and apply to each of them.
It is tricky question, because the bootstrap popover creates the same element as your specific div when the icon gets a click. Therefore there are two the same element, you have to point it out which element is in a popover.

Semantic ui dropdown, prevent auto select with input element

I added an option to the dropdown that allows user to add item if it doesn't exist.
For that matter, I added an input field to the dropdown but when the user enters something, the dropdown tries to match the entered text with items that are already in the list.
I find it quite annoying in that specific case. I have noticed in the docs that input elements are bound to the search function. Nevertheless, I couldn't find how to disable this behaviour.
Here's the HTML:
<div class="ui fluid selection dropdown playlist">
<input name="playlist" type="hidden">
<i class="dropdown icon"></i>
<div class="default text">playlist</div>
<div class="menu">
<div class="item create" data-value="0">
<span class="create-placeholder">+ new playlist</span>
<div class="ui action input add-playlist">
<input placeholder="new playlist">
<button class="ui button">Add</button>
</div>
</div>
<div class="item" data-value="1">foo</div>
<div class="item" data-value="2">bar</div>
<div class="item" data-value="3">baz</div>
</div>
</div>
The .add-playlist div and its content are not shown but I'm willing to spare you with the CSS here.
And the js:
$dropdown = $('.ui.dropdown');
$dropdown.dropdown({
action: (text, val) => {
if (val == 0) { // eslint-disable-line
$('.create-placeholder').hide(100);
$('.add-playlist').css('display', 'inline-flex');
$('.add-playlist input, .add-playlist button').show(200);
}
else $dropdown.dropdown('set selected', val).dropdown('hide');
},
onHide: () => {
// do that after dropdown has been hidden
setTimeout(() => {
$('.add-playlist, .add-playlist input, .add-playlist button').hide();
$('.create-placeholder').show();
}, 400);
}
});
I've set up a fiddle to have a clear exemple. Just type "foo" and you'll see what I mean in case it's not crystal clear.
To allow user to add new items just add allowAdditions: True To dropdown options, for more informtions see semantic-ui dropdown settings
Example:
$('dropdownSelector').dropdown({
allowAdditions: True
}).dropdown();

Bootstrap Tooltip remains stuck

I am dynamically creating a div using jquery which contains add & close button. I am using Bootstrap tooltip for the add & close buttons. The problem that I am facing is Tooltip of the first add button doesn't gets hidden even when the mouse is hovering other add button. The tooltip of first add button remains as it is.(Refer screenshot) Any idea as to how to make it hidden.
I am using jquery clone method to create the dynamic divs.
$(document).on('click', ".addFilesBtn", function(e) {
e.preventDefault();
$(".appendClass:first").clone().appendTo".addFiles");
$('.closeFilesBtn').show();
$('.closeFilesBtn:first').hide();
});
Also for hiding the tooltips, I am using the below code but still the first tooltip is not getting hidden.
$(document).on('mouseleave','[data-toggle="tooltip"]', function(){
$(this).tooltip('hide');
});
updated HTML Code
<div class="row addFiles">
<div class="appendClass" style="margin-bottom: 1.5%;">
<label style="white-space: nowrap;" class="responsive-enter-details col-sm-3 control-label">Select Files</label>
<div class="col-sm-8 col-md-9">
<div class="fileinput fileinput-new" data-provides="fileinput">
<div class="form-control" data-trigger="fileinput">
<i class="glyphicon glyphicon-file fileinput-exists"></i> <span class="fileinput-filename">Click to select file</span> <i class="fa fa-upload pull-right"></i>
</div>
<input id="inputfile" type="file" style="display: none;">
</div>
</div>
<button class="btn btn-box-tool addFilesBtn" data-toggle="tooltip" title="Click to add more files">
<i class="fa fa-plus"></i>
</button>
<button class="btn btn-box-tool closeFilesBtn" data-toggle="tooltip" title="Click to remove this block">
<i class="fa fa-times"></i>
</button>
</div>
</div>
Link to JS Fiddle:
https://jsfiddle.net/gLkrsbxc/4/
As you can see in JS Fiddle, the tooltip isn't getting closed.
Please check the last update for solution
As mentioned in the docs at http://getbootstrap.com/javascript/#tooltips, you need to initialize all the tooltips e.g.
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
So, here you just need to initialize the tooltips after adding them to the DOM.
Just add $('[data-toggle="tooltip"]').tooltip() in your click function after cloning.
$(document).on('click', ".addFilesBtn", function(e) {
e.preventDefault();
$(".appendClass:first").clone().appendTo".addFiles");
//initialize tooltips(add this line)
$('[data-toggle="tooltip"]').tooltip();
$('.closeFilesBtn').show();
$('.closeFilesBtn:first').hide();
});
And I think if initialized properly, you won't need the hide function.
Update:
I think calling the initializing function doesn't work properly because it is a problem when dom manipulation operations are performed. Add slight delay after the append function and before the initializing function with setTimeout like this:
$(document).on('click', ".addFilesBtn", function(e) {
e.preventDefault();
$(".appendClass:first").clone().appendTo".addFiles");
//initialize tooltips(give some time for dom changes)
setTimeout(function() {
$('[data-toggle="tooltip"]').tooltip();
}, 50);
$('.closeFilesBtn').show();
$('.closeFilesBtn:first').hide();
});
Update 2
Just hide the tooltip of the button you just clicked before cloning:
$(document).on('click', ".addFilesBtn", function(e) {
e.preventDefault();
//hide the tooltip
$(this).tooltip('hide');
$(".appendClass:first").clone().appendTo(".addFiles");
$('.closeFilesBtn').show();
$('.closeFilesBtn:first').hide();
});

Categories

Resources