jquery autocomplete, multiple values, minLength ignored - javascript

I'm trying to make this: http://jsfiddle.net/F9tMx/ work in a way that i can propose to the user who is typing separate suggestions from the availableTags Array.
Basically I'd like to add the same function that is present here on SO when someone is adding a comment to a questions and types the '#' character (a list of user appears if the first character[s] match someone who made activity on the page).
Anyway, I've seen that the minLength parameter is ignored. While the plugin is indeed able to separate words and match against the last word typed, once that the last word is actually empty (last == '') the plugin will propose ALL the elements in the availableTags Array, even if minLength is setted to a number greater than 1.
is there a way I could fix this on your opinion?
here's how I'd like it to behave, but of course it's raising an error
http://jsfiddle.net/F9tMx/3/

Hiya cool using # working demo here: http://jsfiddle.net/67dxH/
so: here is the answer which I replied and helped to someone else: jquery autocomplete #mention
Code segment
this statement will do the trick if (request.term.indexOf("#") >= 0) { rest code is in jdfiddle
.autocomplete({
source: function(request, response) {
if (request.term.indexOf("#") >= 0) {
$("#loading").show();
getTags(extractLast(request.term), function(data) {
response($.map(data.tags, function(el) {
return {
value: el.name,
count: el.count
}
}));
$("#loading").hide();
});
}
},
Have a nice one!
cheers!

Related

jQuery Autocomplete Substring Matching

I'm attempting to do jQuery autocomplete such that I can search for multiple words.
For example, if I have smart, very smart, and super smart in a list I'd like to be able to start typing smar and have all three options show up.
This code will work in the sense that if I start typing from the very beginning like over it will suggest over smart which is correct. But it wouldn't suggest it if I type just smart which is the desired output.
Any idea how I can adjust the code so that I could search and suggest say a substring within the list?
http://jsfiddle.net/UKgD6/390/
var acList = ['smart',
'over smart',
'smart land',
'under smart',
'very smart'
];
$('#ac').autocomplete({
source: function( request, response ) {
var matches = $.map( acList, function(acItem) {
if ( acItem.toUpperCase().indexOf(request.term.toUpperCase()) === 0 ) {
return acItem;
}
});
response(matches);
}
});
Your issue can be fixed by changing the indexOf() check. Change === 0 to !== -1. This will return anything that matches, no matter what the index of the search string is within the actual string.
http://jsfiddle.net/UKgD6/391/

Auto-complete with CodeMirrror

I am trying to implement auto-complete using CodeMirror show-hint addon, specifically with sql-hint. I want it auto-complete as I type.
What I am doing right now is,
codemirror_editor.on("change", function(instance) {
CodeMirror.commands.autocomplete(instance);
});
But the problem is, it completes words before I even type a single letter for a word. For example after space, it gives a long list of all possible tokens. I want it to show up only if some characters are typed. Can someone please help with that?
Before firing the autocomplete command, check whether the cursor is actually after 'some' (whatever 'some' means) letter characters. Also, do nothing when instance.state.completionActive is true, since that means there's already a completion popup open. Finally, you probably want to listen for the "inputRead" event instead of "change", so that you don't trigger when a change is made to the document in a way that didn't involve the user typing.
This is how I solved this, after Marijn's answer.
codemirror_editor.on("inputRead", function(instance) {
if (instance.state.completionActive) {
return;
}
var cur = instance.getCursor();
var token = instance.getTokenAt(cur);
var string = '';
if (token.string.match(/^[.`\w#]\w*$/)) {
string = token.string;
}
if (string.length > 0) {
CodeMirror.commands.autocomplete(instance);
}
});
This may be specific to SQL.
I am answering my own question to share the actual solution for the question.

In CodeMirror, bind `%%` to autocomplete and add `%%` after the chosen option

I have a project that want to have CodeMirror implemented. Basically, one of the requirements is that you can type double % (for example: %% keyword %%) to display a list (a hint). I have seen the official example with Ctrl+Space, but I'm wondering how I can make typing the second percent character of the start double percent be a trigger to show the hint list, and how I can display the keyword with the end double percent after choosing an option from the list. I need help or any demo or sample code.
I was having similar problems with CodeMirror, I'll share what I have learned.
type double % (for example: %% keyword %%) to display a list (a hint).
To achieve this, first you need to handle the 'change' event:
var cm = CodeMirror.fromTextArea(document.getElementById('textArea'),
{
mode: 'your_custom_language',
lineNumbers: true,
extraKeys: {'Ctrl-Space': 'autocomplete'}
});
var onChange = function(instance, object)
{
// do stuff...
}
CodeMirror.on(cm, 'change', onChange);
Then, on the onChange function you must do the following:
Check if the last inserted character is %.
Check if the previous character is %.
Summon the hint list.
I did it this way:
var onChange = function(instance, object)
{
// Check if the last inserted character is `%`.
if (object.text[0] === '%' &&
// Check if the previous character is `%`.
instance.getRange({ch: object.to.ch - 1, line: object.to.line}, object.to) === '%')
{
// Summon the hint list.
CodeMirror.showHint(cm, CodeMirror.hint.your_custom_language);
}
}
Note that I use the cm object previously declared, you must change this to meet your requirements. And also, the deduced context for your keyword will not match what you're expecting; in order to fix this you need to modify your own codemirror/addon/hint/your_custom_language-hint.js; in my case, I based my custom language on JavaScript (refactoring the javascript-hint.js) modifying the function called maybeAdd from:
function maybeAdd(str) {
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
}
to:
function maybeAdd(str)
{
if (isValidHint(str))
{
found.push({text: '%%' + str + '%%', displayText: str});
}
}
Note that the array found of getCompletions is no longer storing strings, it is storing objects with this format:
{
// this will be written when the hint is selected.
"text": "%%text%%",
// this will be shown on the hint list.
"displayText": "text",
// You can custom each hint match with a CSS class.
"className": "CSSClass"
}
Please, note that all the things I've writed above are refactoring of my CodeMirror custom language, it is untested on your own custom language but I hope it helps.
BTW; I think that CodeMirror documentation doesn't look clear and lacks on examples of many demanded features.

Javascript taking too long to run

I have a script that is taking too long to run and that is causing me This error on ie : a script on this page is causing internet explorer to run slowly.
I have read other threads concerning this error and have learned that there is a way to by pass it by putting a time out after a certain number of iterations.
Can u help me apply a time out on the following function please ?
Basically each time i find a hidden imput of type submit or radio i want to remove and i have a lot of them . Please do not question why do i have a lots of hidden imputs. I did it bc i needed it just help me put a time out please so i wont have the JS error. Thank you
$('input:hidden').each(function(){
var name = $(this).attr('name');
if($("[name='"+name+"']").length >1){
if($(this).attr('type')!=='radio' && $(this).attr('type')!=='submit'){
$(this).remove();
}
}
});
One of the exemples i found : Bypassing IE's long-running script warning using setTimeout
You may want to add input to your jquery selector to filter out only input tags.
if($("input[name='"+name+"']").length >1){
Here's the same code optimised a bit without (yet) using setTimeout():
var $hidden = $('input:hidden'),
el;
for (var i = 0; i < $hidden.length; i++) {
el = $hidden[i];
if(el.type!=='radio' && el.type!=='submit'
&& $("[name='" + el.name + "']").length >1) {
$(el).remove();
}
}
Notice that now there is a maximum of three function calls per iteration, whereas the original code had up to ten function calls per iteration. There's no need for, say, $(this).attr('type') (two function calls) when you can just say this.type (no function calls).
Also, the .remove() only happens if three conditions are true, the two type tests and check for other elements of the same name. Do the type tests first, because they're quick, and only bother doing the slow check for other elements if the type part passes. (JS's && doesn't evaluate the right-hand operand if the left-hand one is falsy.)
Or with setTimeout():
var $hidden = $('input:hidden'),
i = 0,
el;
function doNext() {
if (i < $hidden.length) {
el = $hidden[i];
if(el.type!=='radio' && el.type!=='submit'
&& $("[name='" + el.name + "']").length >1) {
$(el).remove();
}
i++;
setTimeout(doNext, 0);
}
}
doNext();
You could improve either version by changing $("[name='" + el.name + "']") to specify a specific element type, e.g., if you are only doing inputs use $("input[name='" + el.name + "']"). Also you could limit by some container, e.g., if those inputs are all in a form or something.
It looks like the example you cited is exactly what you need. I think if you take your code and replace the while loop in the example (keep the if statement for checking the batch size), you're basically done. You just need the jQuery version of breaking out of a loop.
To risk stating the obvious; traversing through the DOM looking for matches to these CSS selectors is what's making your code slow. You can cut down the amount of work it's doing with a few simple tricks:
Are these fields inside a specific element? If so you can narrow the search by including that element in the selector.
e.g:
$('#container input:hidden').each(function(){
...
You can also narrow the number of fields that are checked for the name attribute
e.g:
if($("#container input[name='"+name+"']").length >1){
I'm also unclear why you're searching again with $("[name='"+name+"']").length >1once you've found the hidden element. You didn't explain that requirement. If you don't need that then you'll speed this up hugely by taking it out.
$('#container input:hidden').each(function(){
var name = $(this).attr('name');
if($(this).attr('type')!=='radio' && $(this).attr('type')!=='submit'){
$(this).remove();
}
});
If you do need it, and I'd be curious to know why, but the best approach might be to restructure the code so that it only checks the number of inputs for a given name once, and removes them all in one go.
Try this:
$("[type=hidden]").remove(); // at the place of each loop
It will take a short time to delete all hidden fields.
I hope it will help.
JSFiddle example

Formfill in Javascript not working?

var tagMatch;
if (tagMatch = window.location.href.match(/\/questions\/ask\?tags=([^&]+)/)) {
$(function() {
if (!$('#tagnames').val().length) {
$('#tagnames').val(unescape(match[1].replace(/\+/g, ' '));
}
});
}
Hi all, this JS code is supposed to match the latter-part of a URL of the form /questions/ask?tags=some-tag, and then plug the text contained in the part of the URL after tags= into a textbox with the id #tagnames. What am I doing wrong? How can I fix this?
I'm still learning so if you would want to show me how to fix my regex or anything else, please do!
I think the error is with this line
if (!$('#tagnames').val().length)
length will return a number and check that against number.
Something like
if ($('#tagnames').val().length > 0)
I don't think there is a need to place document ready inside the if statement. Isn't this better.
$(function() {
var tagMatch;
if (tagMatch = window.location.href.match(/\/questions\/ask\?tags=([^&]+)/))
{
if ($('#tagnames').val().length > 0)
{
$('#tagnames').val(unescape(match[1].replace(/\+/g, ' '));
}
}
});
Without looking too much into how the string matching works...
You seem to be defining and setting a variable called tagMatch, but then you're using a variable called match to set the value.
Is that the problem?
Update: Apologies - your regex is correct - I misread the intention :)

Categories