select2 (remote data) throws exception because of typing to fast - jquery-select2-4

I'm using select2 for loading remote data. I declared the minimumInputLength to 3 letters, so after that it will start searching.
Whenever I hit the fourth letter while typing fast I get an Javascript exception saying :
Sorry. An error occured while communicating with the server. Please try again later.
How can I avoid this? I already changed the quietMillis (waitTimesMs) to lower or higher (does this even have something to do with it?).
Every help is appreciate.
My code is like:
$(function () {
$("#Search").select2({
minimumInputLength: 3,
ajax: {
url: site,
dataType: "json",
quietMillis: waitTimeMs,
data: function (params) {
var page = (params.page || 1) - 1;
return {
searchText: params.term,
pageCount: 10,
page: page
};
},
processResults: function (data) {
var select2Data = $.map(data.Items, function (obj) {
obj.id = obj.ID;
obj.text = obj.Name;
return obj;
});
return {
results: select2Data,
pagination: { more: (data.PageNo * 10) < data.TotalCount }
};
}

Finally it works!
select2 changed "quietMillis" to "delay" so I could change quietMillis as big as I wanted and nothing changed at all...

Related

select2 4.0 brings older list in suggestion with query method and minimumInputLength not taking effect

I am in process of upgrading select2 version 3.5.1 to 4.0. I required to use query method for mandate.
There are two specific problem arises
minimumInputLength is not taking effect
When user focus searchbox, The past results are displayed with Searching.. is first item. (If I assign empty result then it resolves the problem but then it displays No results found message)
Please refer to my code snippet below.
var self = this, $view = $(view);
$.fn.select2.amd.require(['select2/data/array', 'select2/utils', 'select2/data/minimumInputLength'], function (ArrayData, Utils, MinimumInputLength) {
function CustomData($element, options) {
CustomData.__super__.constructor.call(this, $element, options);
this.options = options;
}
Utils.Extend(CustomData, ArrayData);
CustomData.prototype.query = function (params, callback) {
//callback({ results: [] });
self.searchText(params.term);
q(ko.unwrap(self.qPromise)).then(function () {
var select2data = $.map(ko.unwrap(self.dataSource), function (obj) {
obj.id = obj.id || obj.Id + obj.KeyDoc;
obj.text = obj.text || obj.Headline;
return obj;
});
callback({ results: select2data });
});
}
// Decorate after the adapter is built
Utils.Decorate(CustomData, MinimumInputLength);
$view.select2({
dataAdapter: CustomData,
multiple: ko.unwrap(self.multiple),
templateResult: ko.unwrap(self.formatFunc),
escapeMarkup: function (markup) { return markup; },
dropdownParent: $('.' + ko.unwrap(self.containerClass)),
placeholder: ko.unwrap(self.placeHolderCaption),
minimumInputLength: 1,
allowClear: true
});
});
Every time I wish to assign new options in suggestion list (no cached no stored)
Please suggest workaround.
Thanks in advanced

turbolinks change url manually

I use endless scrolling in my rails 4 application.
The code automatically updates the url when I scroll a list:
var loading = false;
$(function() {
function nearBottomOfPage() {
return $(window).scrollTop() > $(document).height() - $(window).height() - 200;
}
$(window).scroll(function(){
if (loading || $(".infinite-scroll").length == 0) {
return;
}
if(nearBottomOfPage()) {
loading=true;
var qstring = parseInt(getParameterByName('page'));
if(isNaN(qstring)) {qstring = 1;}
qstring++
updateQueryString('page',qstring);
var url = $(".infinite-scroll").data("update-url")
var q_string = window.location.search
if(url.indexOf("?") != -1) {
q_string = q_string.replace("?","&")
}
url = url + q_string
$.ajax({
url: url,
type: 'get',
dataType: 'script',
success: function() {
$(window).sausage('draw');
loading=false;
}
});
}
});
$(window).sausage();
});
The updateQuerystring function replaces the state like so:
window.history.replaceState({turbolinks: true, position: Date.now()}, document.title, new_url);
This is a hack to try to get something that worked in rails 3 to work in rails 4...
It seems to work but it is not clean and has some issues.
The main issue is the fact that the scroll position is not reminded. When clicking the back button, I come back to the top of the page.
Is there a way to do this cleaner. Ideally, instead to do window.history.replaceState I'd like to do Turbolinks.replaceState(newUrl) or something like that.
But if I could find a way to remember the scroll position, It would be great already.
Thank you!
Triggering a Turbolinks visit manually
You can use Turbolinks.visit(path) to go to a URL through Turbolinks.
https://github.com/rails/turbolinks#triggering-a-turbolinks-visit-manually

Cached autocomplete with Solr

I'm using jQuery-ui and Solr to make a neat search box with auto-complete. The query seems to work well but the results aren't actually displayed in my search box. Here is the code I'm using:
var cache = {};
$("#Keyword").autocomplete({
minLength: 3,
source: function(request, response) {
var term = request.term;
if(term in cache) {
response(cache[term]);
return;
}
$.getJSON("http://127.0.0.1:8080/solr/terms/?terms=true&terms.fl=ctnt_val&wt=json&indent=on&terms.prefix=" + $("#Keyword").val(),
request,
function(data, status, xhr) {
cache[term] = data;
response(data);
});
}
});
So my best guess is that I'm not treating the returned values correctly. How could I make them appear properly underneath my search box?
I was able to determine what was wrong in my return function : I wasn't looping properly through the results. Best way is to use the map function to iterate through them.
$("#Keyword").autocomplete({
minLength: 3,
source: function(request, response) {
$query = "http://127.0.0.1:8080/solr/terms/?jsoncallback=?&terms=true&terms.prefix=" + $("#Keyword").val();
$.getJSON($query,
request,
function(data) {
response($.map(data.terms.ctnt_val, function(item) {
return item;
}));
}
);
}
});

Calling controller method from JQuery calls occurs twice and also returning error?

Hi guys i have posted a similar post before, but that is for another, now i face a strange and odd issue with my Jquery code. Here i was calling a controller method using Jquery but it is calling twice , so that may cause two entries in my db. Here is what i have written in my JQuery
<script type="text/javascript">
$('#btnSubmit').click(function () {
var instructorUrl = '#Url.Action("ApplyToBecomeInstructor", "InstructorApplication")';
var currentUser = '#Model.CurrentUserId';
var user = [];
var educationList = [];
var experience = $('#Experience').val();
var isWilling = $('#WillingToTravel').is(":checked");
$('#editorRows .editorRow').each(function () {
var education = {
UniversityOrCollege: $(this).find('.university').val(),
AreaOfStudy: $(this).find('.area').val(),
Degree: $(this).find('.degree').val(),
YearReceived: $(this).find('.year').val()
}
educationList.push(education);
});
var applicationFromView = {
EducationalBackgrounds: educationList,
CurrentUserId: currentUser,
Experience: experience,
WillingToTravel: isWilling
}
$.ajax({
type: 'POST',
url: instructorUrl,
dataType: 'JSON',
async: false,
data: JSON.stringify(applicationFromView),
contentType: 'application/json; charset=utf-8',
success: function (data) {
return false;
},
error: function (data) {
alert(xhr.status);
alert(thrownError);
alert(xhr.responseText);
return false;
}
});
});
</script>
and my controller action looks like this
[HttpPost]
public ActionResult ApplyToBecomeInstructor(InstructorApplicationViewModel applicationFromView)
{
Student thisStudent = this.db.Students.Where(o => o.StudentID == applicationFromView.CurrentUserId).FirstOrDefault();
List<PaulSchool.Models.EducationalBackground> educationList = new List<EducationalBackground>();
foreach (var educate in applicationFromView.EducationalBackgrounds)
{
var education = new Models.EducationalBackground
{
YearReceived = educate.YearReceived,
Degree = educate.Degree,
AreaOfStudy = educate.AreaOfStudy,
UniversityOrCollege = educate.UniversityOrCollege
};
educationList.Add(education);
}
var instructorApplication = new InstructorApplication
{
BasicInfoGatheredFromProfile = thisStudent,
Experience = applicationFromView.Experience,
EducationalBackground = new List<Models.EducationalBackground>(),
WillingToTravel = applicationFromView.WillingToTravel
};
instructorApplication.EducationalBackground.AddRange(educationList);
this.db.InstructorApplication.Add(instructorApplication);
this.db.SaveChanges();
return this.Redirect("Index");
}
Error message showing is JSON Parsing error.. but it is confusing to me.
I really wondered why this is happening, can anybody please take a look and help me?
This is what your code does:
$('#btnSubmit').click(function () { // attach a click handler for the button.
...
...
// Look for elements inside the button...
UniversityOrCollege: $(this).find('.university').val(),
Change from click to submit:
$('#formId').submit(function (e) {
...
// Now "this" is the form - not the button.
// Look for elements inside the <form>
UniversityOrCollege: $(this).find('.university').val(),
// Prevent the default form submition
return false // Or: e.preventDefault();
Another tip: use jQuery serialize function.
$('#btnSubmit').click() will fire every time the button is pressed. Often users double click buttons even though it only needs a single click or if you don't give any indication that something is happening they get impatient and click it again. You need some way to determine if the request has been made. There's ways to do this client and server side. The easiest client side way is to disable the button to prevent multiple clicks:
$('#btnSubmit').click(function () {
// Disable the button so it can't be clicked twice accidentally
$('#btnSubmit').attr('disabled', 'disabled');
//...
$.ajax({
//...
complete: function() {
// Make sure we re-enable the button on success or failure so it can be used again
$('#btnSubmit').removeAttr('disabled');
}
});
});

Loading script after page fully loaded

I am building a firefox addon that loads javascript at every page load. I'm using progress listener function I found on this page: https://developer.mozilla.org/en/Code_snippets/Progress_Listeners
My problem is that the code seems to execute to early before the page is fully loaded which causes my script to not run. Here is my code.
var PageLoad = {
browser: null,
domain: null,
oldURL: null,
init: function() {
gBrowser.addProgressListener(urlBarListener,Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);
},
uninit: function() {
gBrowser.removeProgressListener(urlBarListener);
},
processNewURL: function(aURI) {
//if (aURI.spec == this.oldURL)
//return;
MyObject.function();
this.oldURL = aURI.spec;
}
};
var urlBarListener = {
locChange: false,
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
},
onLocationChange: function(aProgress, aRequest, aURI) {
PageLoad.processNewURL(aURI);
},
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {},
onProgressChange: function(a, b, c, d, e, f) {},
onStatusChange: function(a, b, c, d) {},
onSecurityChange: function(a, b, c) {}
};
window.addEventListener("load",
function() {
PageLoad.init()
}, false);
var MyObject = {
function : function() {
var script = PageLoad.browser.createElement('script');
script.src = 'url_to_script.js';
PageLoad.browser.getElementsByTagName('head')[0].appendChild(script);
}
};
With this code I get this error message on the console:
PageLoad.browser.getElementByTagName("head")[0] is undefined
If I add a timeout then the script does work intermittently but if the page loads slow I get the same error, here's what works sometimes setTimeout(MyObject.function, 1000);
I need a more reliable way of making sure it's executing the script after the page is loaded.
Unrelated, and it doesn't seem to cause any problems but I also see this error message:
gBrowser.addProgressListener was called with a second argument, which is not supported. See bug 608628.
If you want to load javascript at every page load - the best way is subscribing to DOMContentLoaded event:
var MyObject = {
processDOMContentLoaded: function(doc) {
var script = doc.createElement('script');
script.src = 'url_to_script.js';
script.type = 'text/javascript';
doc.getElementsByTagName('head')[0].appendChild(script);
}
};
window.addEventListener('load', function() {
var appcontent = document.getElementById('appcontent');
if(appcontent != null) {
appcontent.addEventListener('DOMContentLoaded', function(event) {
var doc = event.originalTarget;
if(doc instanceof HTMLDocument) {
MyObject.processDOMContentLoaded(doc);
}
}, true);
}
}, false);
Have not tested, but should work.
You are using onLocationChange method - but if you look at how the browser behaves, the location in the address bar changes as soon as a connection with the server is established. You should look at state changes instead:
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus)
{
if ((aFlag & Components.interfaces.nsIWebProgressListener.STATE_STOP) &&
(aFlag & Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW))
{
// A window finished loading
PageLoad.windowLoaded(aWebProgress.DOMWindow);
}
},
Note that the window that finished loading is explicitly passed to PageLoad.windowLoaded() - you will be receiving notifications from different tabs and you cannot assume that the notification comes from the foreground tab.
As to the warning you are getting, just leave out the second parameter in the call to gBrowser.addProgressListener():
gBrowser.addProgressListener(urlBarListener);
tabbrowser.addProgressListener() only accepts one parameter, unlike nsIWebProgress.addProgressListener() which has a second parameter.
Actually its a great question.
You should use event listener, but carefully, because if you trigger for every page load its can trigger you more than one time (in the worst case about dozens of times).
So how you can do that?
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
myExtension.init();
},false);
var myExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if(appcontent){
appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
}
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
if (doc.nodeName != "#document") return;
if (win != win.top) return;
if (win.frameElement) return;
alert("the main page has been loaded");
},
};
get notice that we check for the type of the trigger every pageload triggering to prevent multi load.
The answers that were provided were acceptable but I found yet another solution that works perfectly.
var PageLoad = {
init: function() {
if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
if (doc.nodeName != "#document") return;
if (win != win.top) return;
if (win.frameElement) return;
MyAddon.function();
}
}
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
PageLoad.init();
},false);

Resources