Bootstrap TypeAhead.js prevent invalid entry - javascript

I am using the bootstrap typeahead.js feature for autocomplete capability for 'state' lookup. How can I best prevent individuals from typing all (and not successfully picking Alaska) before submitting the form?

Typeahead.js does not currently support this behavior.
You can use other libraries better suited for restricted options, for example Select2
However I have working fork of Typeahead that supports this.
See the JQuery example page here:
https://github.com/Svakinn/typeahead.js/blob/typeaheadSimple/Examples.md

Depending on your requirements you could enforce picking from valid options only and clearing any invalid input.
Start with creating a custom source which tracks search results:
var sync = false;
var current_results = [];
var current_q = '';
var selected_val = '';
function search(q, sync) {
current_q = q;
window.sync = sync;
engine.search(q, cust_sync);
}
function cust_sync(datums) {
current_results = datums;
sync(datums);
}
$('#typeahead').typeahead(
{
highlight: true,
minLength: 0
},
{
source: search // custom search engine
}
);
Then bind select and change event handlers.
$('#typeahead').bind('typeahead:change', function(ev) {
var current_val = $('#typeahead').val();
// user moved cursor out of input without selecting from the menu
if(current_val != selected_val){
// current query has search results
if(current_results.length)
// change input to the first valid search result
$('#typeahead').typeahead('val', current_results[0].name);
// no results for this query - clear input
else
$('#typeahead').typeahead('val', '');
}
});
$('#typeahead').bind('typeahead:select', function(ev, suggestion) {
selected_val = $('#typeahead').val(); // keep track of a selected value
});

Related

Tabulator autocomplete custom editor and css. Cant display editor outside of a cell

I use tabulator.js lib. My goal - to create autocomplete editior with values returned from API. I tried implement this as described in documentation in the custom editiors section.
My JS code:
function AutocompleteEditor(cell, onRendered, success, cancel, editorParams) {
var editor = document.createElement("input");
editor.setAttribute("type", "text");
editor.setAttribute("autocomplete", "off");
editor.style.width = "100%";
// editor.style.height = "100%";
editor.style.boxSizing = "border-box";
if (cell.getValue()) {
editor.value = cell.getValue();
}
$(editor).autoComplete({
minLength: 1,
resolverSettings: {
url: apiBaseUrl + 'ItemMatching/ItemCode',
},
formatResult: function (item) {
return {
value: item.vendorCode,
text: item.vendorCode + " - " + item.vendorName,
};
},
});
$(editor).on('autocomplete.select', function (event, item) {
if (item) {
selectedManufacturer = item;
$(editor).value(item.vendorName);
}
});
onRendered(function () {
console.log($(editor));
editor.focus();
editor.style.css = "100%";
});
function successFunc() {
success(selectedManufacturer.vendorCode);
}
editor.addEventListener("change", successFunc);
editor.addEventListener("blur", successFunc);
return editor;
}
And I got behavior when autocomplete part "hided" by cell.
If I use standard html input type like date - no problem.
Please see attached pictures.
Any suggestions needed how to fix or implement this (autocomplete part near a cell)?
PS I use bootsrap-autocomplete bootstrap-autocomplete
The reason you are seing this is because Tabulator cells have overflow set to hidden. Most autocomplete widgets let you specify that the list should be appended to the body not the element itself,which over comes these sort of issues. But I cannot see that option on your chosen widget.
I would recommend using Tabulators built-in autocomplete editor that can offer all the functionality you are looking for. See the Built in editor docs for full details

Troubleshooting Conditional Form

I'm new to Javascript and trying to build a conditional form using bootstrap and JQuery. I would really appreciate the help as I've been working most of the day on this to no avail.
I'm trying to show the div with id physician (and subsequent field) when the select field with the name AppointmentType has a value of Orthopedic or Rheumatology. Here is the link to the live form.
Here is my javascript:
$( document ).ready(function() { //wait until body loads
//Inputs that determine what fields to show
var appttype = $('#secureform input:select[name=AppointmentType]');
var physician = document.getElementById("physician");
appttype.change(function(){ //when the Appointment Type changes
var value=this.value;
physician.addClass('hidden'); //hide everything and reveal as needed
if (value === 'Orthopedic' || value === 'Rheumatology'){
physician.removeClass('hidden'); //show doctors
}
else {}
});
});
These lines are going to cause errors (which you should see in your devtools console):
var appttype = $('#secureform input:select[name=AppointmentType]'); // `input:select` is not a valid selector and causes the rest of the script to fail
physician.addClass('hidden'); // `addClass` is a jQuery method, so this should be `$(physician).addClass('hidden')`
physician.removeClass('hidden');// `removeClass` is a jQuery method, so this should be `$(physician).removeClass('hidden')`
Correct those lines and it should work.
If it helps, I would write it like this:
$( document ).ready(function () {
//Inputs that determine what fields to show
var apptType = $('#secureform select[name="AppointmentType"]'); // dropped the `input:` part
var physician = document.getElementById('physician');
physician.classList.add('hidden'); //hide this initially, outside the change handler
apptType.change(function () { // when the Appointment Type changes
var value = $(this).val().toLowerCase(); // leave case-sensitivity out of it.
var showables = [ // using an array as I prefer using a simple `indexOf` for multiple comparisons
'orthopedic',
'rheumatology',
];
var isShowable = showables.indexOf(value) > -1;
physician.classList.toggle('hidden', !isShowable);
// or, the jQuery equivalent:
// $(physician).toggleClass('hidden', !isShowable);
});
});
Your selector is incorrect:
var appttype = $('#secureform input:select[name=AppointmentType]');
// this should be
var appttype = $('#secureform select[name=AppointmentType]');
Furthermore you are mixing jquery with vanilla JS. Your are using vanilla js here
var physician = document.getElementById("physician");
Physician is now a dom object and not a jquery object. You should use this instead:
var physician = $("#physician");
Additionally you should replace
var value=this.value;
with this
var value= $(this).val();

Bootstrap-select, behavior like SO tags field

I have a bootstrap-select with multiple mode and live-search on. I need to add a behavior, something like Stack Overflow Tags select: meaning that if you enter a keyword that doesn't exist in the list, it should be added as soon as you press comma. Is there any easy way of doing this?
<select id="#Html.IdForModel()" name="#Html.NameForModel()"
class="selectpicker form-control" data-live-search="true" multiple></select>
Just for completeness: I'm also using https://github.com/truckingsim/Ajax-Bootstrap-Select on top of it, but I doubt this matters.
Okay, this appeared to be extremely complex problem to solve. Partially because I was using Ajax-Bootstrap-Select (thought this was insignificant, but it was not). This code has some problems, like spamming setTimeout - I for most don't care, but this code should give an idea to anybody who is struggling with the same issue I did.
var keywordsSelectItemTemplate = $('##Html.IdForModel()selectItemTemplate').html();
var keywordsSelectBox = $('##Html.IdForModel()');
var keywordsSelectedElements = [];
// list of words that were persisted
var keywordsAddedElementsStable = [];
// Remembered list of words that are currently in the input box (currently entered)
var keywordsAddedElements = [];
// The search box input
var keywordsSearchBox = keywordsSelectBox.parent().find("div.bs-searchbox").find("input");
// Subscribe to all kind of keypress events to track changes
keywordsSearchBox.bind("propertychange change click keyup input paste",
function(event) {
var value = keywordsSearchBox.val();
// Parse words by splitting input box value with ,
var keywords = value.split(",").map(function (str) {
return str.trim();
}).filter(function(str) {
return str != undefined && str.length > 0;
});
// Removing last word, because this is the word that is currently being typed
if (keywordsAddedElements.slice(-1).length > 0) {
keywordsAddedElements.splice(-1, 1);
}
// Remembering all words so Bootstrap-Select-Ajax could process them.
keywords.forEach(function(keyword) {
if ($.inArray(keyword, keywordsAddedElements) === -1) {
keywordsAddedElements.push(keyword);
}
});
// Adding entered words as selected and refresh the selectbox. The timeout should be biger than the timeout defined
// in Bootstrap-Select-Ajax, so this refresh will happen after Bootstrap-Select-Ajax process the selected list
setTimeout(function() {
keywordsSelectBox.val(keywordsSelectBox.val().concat(keywords));
keywords.forEach(function(keyword) {
keywordsSelectBox.find("[value=" + keyword + "]").attr('selected', '1');
});
keywordsSelectBox.selectpicker('refresh');
keywordsSelectBox.selectpicker('render');
}, 500);
});
// If we leave search box input - remember the entered items as persisted.
// The user is no longer able to change them, unless by clicking in Bootstrap-Select (as any other items)
keywordsSearchBox.focusout(function() {
// Refreshing selected items of Bootstrap-Select-Ajax, ensuring that it thinks
// these items were processed as any other.
var selectedItems = keywordsSelectBox.ajaxSelectPicker()
.data()
.AjaxBootstrapSelect.list.selected;
keywordsAddedElements.forEach(function(el) {
if (!selectedItems.some(function(element) { return element.value === el;})) {
selectedItems.push({
"class": "",
data: {
content: el
},
preserved: true,
selected: true,
text: el,
value: el
});
}
});
// Remember items as "persisted"
keywordsAddedElementsStable = keywordsAddedElementsStable.concat(keywordsAddedElements);
keywordsAddedElements = [];
And then in ajaxSelectPicker in preprocessData:
// Adding both "persisted" and "temporary" items to the Bootstrap-Select-Ajax list.
keywordsAddedElementsStable.concat(keywordsAddedElements).forEach(function(el) {
result.push({
value: el,
text: el,
data: {
content: el
}
});
Without using Ajax-Bootstrap-Select, the issue is very simple: Find search box:
var keywordsSearchBox = keywordsSelectBox.parent().find("div.bs-searchbox").find("input")
Subscribe to change:
keywordsSearchBox.bind("propertychange change click keyup input paste",
function(event) { ...
And add elements via selectBox.selectpicker('val', searchBox.val().split(","));

Sharepoint 2013 People Picker Change event in Javascript

I want People picker Change Event in Javascript as i have to do some task if user is selected/changed in people picker using ClassName.
i have tried the following
$(".Assignedname").bind('input propertychange', function() {
alert("Onchange event" );
})
this fires when i type anything (i.e. text is changed ) , but not fires when user is selected in peoples picker.
Kindly give me some solution. thanks
Once the people picker is initialized, you can access it in the js dictionary and assign a function to the OnValueChangedClientScript property of the picker. The function accepts two parameters, where the second parameter (userInfo) is a collection of users in the picker
var picker = SPClientPeoplePicker.SPClientPeoplePickerDict[pickerId + "_TopSpan"];
picker.OnValueChangedClientScript = function (elementId, userInfo) {
for (var x = 0; x < userInfo.length; x++) {
console.log(userInfo[x].Key);
}
alert("Total number of " + userInfo.length + " users is selected")
};
You need to get the picker id for SharePoint Client People Picker change event. I have got the same using OnUserResolvedClientScript as below. Here to get the picker div I have followed the approach of getting it via the people picker text box id and the title name which you can get the by inspecting the element. put the below code in $(document).ready function. Happy Coding
SP.SOD.executeFunc('clientpeoplepicker.js', 'SPClientPeoplePicker', function() {
var pickerDiv = $("[id^='Employee_x0020_Name'][title='Employee Name']");
var picker = SPClientPeoplePicker.SPClientPeoplePickerDict[pickerDiv[0].id];
picker.OnUserResolvedClientScript = function(peoplePickerId, selectedUsersInfo) {
//It will get the desired display name of the people from picker div, similarly any other property can be accessed via selectedUsersInfo
var empname = selectedUsersInfo[0].DisplayText;
console.log(empname);
}
});
I used jQuery and a focusout event on the input field, instead, to achieve the same effect:
$('input[title="Title of my field"]').focusout(function() {
alert("Focusout event fired." );
doPeoplePickerStuff(); // function for doing validation
});
This has the advantage of being able to check the value of that field whenever they click on anything else - with the exception of the Submit button, if they click that immediately after typing in the field. Here's how I deal with that:
Create a new Submit button and hide the other one:
$('input[name*="diidIOSaveItem"]').parent().append('<input type="button" id="btnSubmit" onclick="doValidation()"></input>'); $('input[name*="diidIOSaveItem"]').hide();
Create the doValidation() function for your new Submit button:
function doValidation() {
doPeoplePickerStuff(); // do validation on the field here
if (personFound == true) {
$('input[name*="diidIOSaveItem"]').click(); // clicks the real button so it does what it normally would
}
}
If you're firing the event in order to grab its value and do validation on it, use:
var personFound = false;
function doPeoplePickerStuff() {
var personFieldSpan = $('span[id*="OriginalTitleOfMyField"]');
var personFieldValue = stripExtraTextFromPeoplePicker(personFieldSpan.text());
if (personFieldValue != "") { // you could do comparisons against the existing value, too, by getting the original value(s) via REST call
personFound = true;
}
}
function stripExtraTextFromPeoplePicker(person) {
var newPerson = person;
console.log("Span text: " + newPerson);
newPerson = newPerson.replace('Title of my field','');
newPerson = newPerson.replace('Enter a name or email address...','');
newPerson = newPerson.replace('Enter names or email addresses...','');
newPerson = newPerson.replace('xSuggestions are available. Use up and down arrows to select.','');
newPerson = newPerson.replace('Suggestions are available. Use up and down arrows to select.','');
newPerson = newPerson.replace('\r','');
newPerson = newPerson.replace('\n','');
newPerson = newPerson.replace('\t','');
newPerson = newPerson.trim();
return newPerson;
}

Creating Dependent Chechboxradio Buttons - jQuery Mobile

I am trying to create several checkboxradio buttons groups in jQuery mobile that depend on a limit checkboxradio button group value. For example if a limit of 6 is selected I want to only allow the user to be able to select up to a total of 6 children based on all of the other checkboxradio button group selected values and disable everything else. When the limit changes I want to update the UI accordingly.
I have the following code in my change event handler whenever any of the checkboxradio buttons are clicks:
function updateUI(element) {
var limit = parseInt($('input[name="Limit_Total"]:checked').val(), 10);
// Children
var childCount = parseInt($('input[name="Child_Total"]:checked').val(), 10);
var secondChildCount = parseInt($('input[name="Second_Child_Total"]:checked').val(), 10);
var thirdChildCount = parseInt($('input[name="Third_Child_Total"]:checked').val(), 10);
var fourthChildCount = parseInt($('input[name="Fourth_Child_Total"]:checked').val(), 10);
var fifthChildCount = parseInt($('input[name="Fifth_Child_Total"]:checked').val(), 10);
// Totals
var totalChildern = childCount + secondChildCount + thirdChildCount + fourthChildCount + fifthChildCount;
// Enable the correct combination of children
$('input[name*="Child_Total"]').not(element).checkboxradio('disable').checkboxradio('refresh');
for (var i = 0; i <= 6; i++) {
if (i <= (limit - totalChildren)) {
$('input[id$="Child_Total_' + i + '"]').not(element).checkboxradio('enable').checkboxradio('refresh');
} else {
$('input[id$="Child_Total_' + i + '"]').not(element).attr('checked', false).checkboxradio('refresh');
}
}
}
I basically want to simulate the behavior illustrated in the image below:
The problem is it doesn't quite give me the behavior I want. It deselects all but the button I select within the group. I am trying to figure out the most efficient way to do this but I am having a hard time. Any suggestions or help would be greatly appreciated!
I have setup the following jsfiddle to demonstrate the UI: http://jsfiddle.net/X8swt/29/
I managed to solve my problem with the following function:
$('div fieldset').each(function() {
// Disable all none checked inputs
$(this).find('input:not(:checked)').checkboxradio().checkboxradio("disable").checkboxradio("refresh");
// Grab the selected input
var selectedElement = $(this).find('input:checked');
// Calculate the remaining children that can be selected
var remaining = (limit - totalChildern);
// Enable all inputs less than the selected input
$.each($(selectedElement).parent().prevAll().find('input'), function() {
$(this).checkboxradio().checkboxradio("enable").checkboxradio("refresh");
});
// Enable up to the remaining boxes past the selected input
$.each($(selectedElement).parent().nextAll().slice(0,remaining).find('input'), function() {
$(this).checkboxradio().checkboxradio("enable").checkboxradio("refresh");
});
});
Please feel free to comment or critique my solution.

Categories