jQuery: on blur move cursor to textfield - javascript

I am creating a simple todolist function. I have a textfield like so:
<input type="text" class="textbox">
on blur take value and append to:
<div class="outerbox"></div>
as:
<div class="box">value from textbox</div>
This is done in jQuery, now after this event I want to move the cursor back into the .textbox (on blur).
How can this be done ?
I tried $('.textbox').focus(); which did'nt work..
Full code:
$(".textbox").blur(function(){
// 1. values
val = $(this).val();
time = '';
// 2. append
$(".outline").append('<div class="box"><div class="time">'+time+'</div>'+val+"</div>");
// 3. focus
setTimeout(function(){$('.textbox').focus();},0);
});

You probably need to break the callstack since you are trying to set focus on an element from inside it's blur event handler.
try to use
setTimeout(function(){$('.textbox').focus();},0);
it should do the trick for you

Related

How to focus on a range slider using Javascript?

I would like to be able to focus on an input element of the type 'range', in other words, the default slider, so that the slider could be dragged without the user actually clicking on it.
The obvious solution would be to just use sliderelement.focus().
This however doesn't work.
I found here that the reason for this, is that I have to call this method on the handle of the slider. The class of the slider handle should be 'ui-slider-handle'.But for some reason document.querySelector('.ui-slider-handle') returns null.
The weird part is that this does work with JQuery when I use $('.ui-slider-handle').
I made this fiddle to clarify my problem. I would like to solve this using only Javascript.
--- edit ---
Perhaps I wasn't clear enough in my explanation. The class ui-slider-handle is not a custom class I added to the slider handle, since I cannot access the handle. I expected this to be the default class based on the answer I found (which I stated earlier).
In your fiddle, the querySelector is correct.
Your jQuery will always return true like that though.
For example change var handle2 = document.querySelector('.ui-slider-handle'); to a made up class like var handle2 = document.querySelector('.ui-slider-handlesdfsdfsdfsdf'); and it returns true.
If you want to check if an element exists you can use .length.
So just add .length to your selector and they will both return false.
var handle1 = $('.ui-slider-handle').length;
var handle2 = document.querySelector('.ui-slider-handle');
$('#1').html('JQuery, handle found: ' + (handle1 ? 'true' : 'false'))
$('#2').html('Javascript, handle found: ' + (handle2 ? 'true' : 'false'))
To put focus on the range element simply use .focus().
Here is an example. Use the buttons and your arrow keys to see that it is gaining/losing focus on the element.
function getFocus() {
document.getElementById("myRange").focus();
}
function loseFocus() {
document.getElementById("myRange").blur();
}
<input type="range" id="myRange" value="50">
<p>Click the buttons below to give focus and/or remove focus from the slider control.</p>
<button type="button" onclick="getFocus()">Get focus</button>
<button type="button" onclick="loseFocus()">Lose focus</button>

Building a catch-all function for rendering

I am currently trying to render a calendar that uses checkboxes as filtering. I have all the filters working if I do it this way:
//Call my render event on click of a checkbox
$('.filterable-content__criteria').on('change', function(){
$('#calendar').fullCalendar('rerenderEvents');
});
This works so everytime I click a checkbox, it re-renders my calendar - thus showing/hiding events. Right now I am doing this relatively staticly where in my render function I do this:
var eventAcceptedClasses = [];
if ($('input#Event-Type-2').is(':checked')){
eventAcceptedClasses.push(id);
displayEvent = false;
} else if ($('input#Event-Type-2').is(':checked')){
eventAcceptedClasses.push('Event-Type-2');
displayEvent = false;
} else if ($('input#Event-Type-3').is(':checked')){
eventAcceptedClasses.push('Event-Type-3');
displayEvent = false;
} else {
//If none checked, show all.
eventAcceptedClasses.push('fc-event');
displayEvent = true;
};
This function is regrettably, not scalable. I'm looking to make it so on render, it takes the id of the checkbox that was clicked, then plugs it into the function ie: You set the id in the click event like this
var cb_click = event.target.id
Then my render just looks like this:
var eventAcceptedClasses = [];
if ($('input#'+cb_click ).is(':checked')){
eventAcceptedClasses.push(cb_click);
displayEvent = false;
}
But given the way the functions are nested, this doesn't seem to work due to the structure of the code.
Any ideas on how I can do this? I included a JS Fiddle that shows the full structure for clarification.
Edit:
Basic Input Structure
<input class="filterable-content__criteria" type="checkbox" name="categories" value="Event Type 1" id="Event-Type-1">
If you can modify the html, adding an onchange attribute to your input is the way to go.
It is much simpler to understand, and is better for memory usage than an event listener, or a redundant testing if else.
In a short example, with just javascript, to call a function that pass the id of the current clicked element.
//Call my render event on click of a checkbox
function call_render(me){
console.log(me)
/* eventType1 */
// me.fullCalendar('rerenderEvents');
}
Tick: <input onchange="call_render(this.id)" id="eventType1" class="filterable-content__criteria" type="checkbox" name="categories" value="Event Type 1">
Sometimes we just can't modify the html from the source.
The html can also become a bit unreadable when too much attributes are set.
It is also not so good for fixing stuffs and readability when javascript is written inside html attribute, like in the previous example.
Attributes needs to be set at the DOM level. It is better practice. There is alternatives, but it's always better to use html capabilities first.
// DOM now ready
// Set the onchange attribute to the element *eventType1*.
// And give this attribute a function when a change happen
eventType1.setAttribute("onchange","call_render(this.id)")
//Call my render event on click of a checkbox
function call_render(me){
console.log(me)
/* eventType1 */
// me.fullCalendar('rerenderEvents');
}
Tick: <input class="filterable-content__criteria" type="checkbox" name="categories" value="Event Type 1" id="eventType1">
To verify or test the checkbox state:
console.log( (eventType1.checked) )
console.log( !(eventType1.checked) )
Tick: <input id="eventType1" type="checkbox" checked="">
Again, we can also set a global event handler like this:
eventType1.oninput = (function() {
call_render(this.id)
})
Js perf test, to compare the 3 methods.
I removed the querySelector, the inline onchange is stil faster.
https://jsperf.com/global-vs-event-vs-inline

Dynamically created textarea with no .val()

I'm trying to allow users to edit the text of a paragraph in a website. I take a paragraph and replace the <p> tags with <textarea> tags using the .replaceWith() function. When I try to take the value of the textarea, it returns blank. Here's a JSfiddle.
HTML:
<p><a class="edit">Edit</a>I'm going to change this into a textarea field and retrieve the value.</p>
JS:
$(document).ready(function() {
$('.edit').hide();
var object = $('p');
object.on("mouseenter", function() {
$('.edit').show();
object.on('click','.edit',function(){
var oldText = object.text();
oldText = oldText.substr(4); // Exclude the word 'Edit'
object.replaceWith($("<textarea>").val(oldText).css("width",object.css('width')).css('height',object.css('height')));
var value = object.val();
alert("Value: "+value);
});
});
});
I'm a programming beginner, so if you have style or implementation tips, feel free to share. This is just my gut reaction to solving the problem; there may be a simpler way to accomplish the same thing.
EDIT: I should also mention that in my website, each paragraph comes from a database table that I'm displaying using an AJAX function. When the user is done editing, he can click a button, and the website will take the new value of the textarea field and UPDATE *table* SET *text*=newText WHERE *text* LIKE oldText;
Try just using contenteditable='true' instead of changing to a textarea. It will make the <p> editable.
Like this:
<p contenteditable='true'><a class="edit">Edit</a>
I'm going to change this into a textarea field and retrieve the value.</p>
If you want to make your text area editable when someone clicks 'Edit', you can create a function that sets the contenteditable attribute to true and then gives focus to the <p> element.
Your code is not trying to get the value of the <textarea>. Your call:
object.replaceWith( ... )
does not change the value of the variable "object" — it's still the jQuery object for the <p> tag, but after that it's out of the DOM. <p> tags don't have a "value" property.
It's almost always a bad idea to set up event handlers inside another event handler (well, an event handler for interaction events anyway). Event handlers accumulate, so each "mouseenter" event will add another "click" handler.
ckersch is right about an easier method being to use contenteditable, but if you're looking to a solution for your specific problem, change your selector from this:
var value = object.val();
To this:
var value = $("textarea").val();
Full code:
$(document).ready(function() {
$('.edit').hide();
var object = $('p');
object.on("mouseenter", function() {
$('.edit').show();
object.on('click','.edit',function(){
var oldText = object.text();
oldText = oldText.substr(4); // Exclude the word 'Edit'
object.replaceWith($("<textarea>").val(oldText).css("width",object.css('width')).css('height',object.css('height')));
var value = $("textarea").val();
alert("Value: "+value);
});
});
});
Fiddle
There are many ways you could make it more robust, including adding a class or id to your textarea, and then using it to be selected, such as this way:
object.replaceWith($("<textarea class='selectMe'>").val(oldText).css("width",object.css('width')).css('height',object.css('height')));
var value = $(".selectMe").val();
You are using the method replaceWith() wrong. The argument must be a string or a function that returns a string, not a jquery selector. Also, you should place the onclick event outside of the mouseenter event (this is valid for any event, never nest them)
$(document).ready(function() {
function makeTextarea(e) {
e.preventDefault();
var edit = $(e.currentTarget);
var parent = edit.parent();
edit.remove();
parent.replaceWith('<textarea>' + parent.text() + '</textarea>');
}
$('.edit').on('click', makeTextarea);
});
Fiddle: http://jsfiddle.net/U57v2/4/
"When the document is ready listen for clicks on .edit class. When clicked store a reference to the parent element (<p>) and then remove the edit element. Finally replace the parent element (<p>) with a textarea with the contents of the <p> element."
ckersh is absolutely right about the contenteditable, but if you're looking for a specific answer to your code, there are a few things you could improve.
There are a couple of issues with your code. First, you're rebinding the on('click') handler every time you mouse over the paragraph, so if you mouse over 5 times, you're executing the anonymous function 5 times. You only need to bind the on routine once. Second, the variable object never changes, so when you replace it with a textarea, you need a new selector to get the value.
I've updated your fiddle with the enhancements I've mentioned above. I also added a mouseleave event, because I figure you want to hide the "Edit" button when you leave the paragraph. The updated javascript can be seen below:
$(document).ready(function () {
$('.edit').hide();
var object = $('p');
object.on("mouseenter", function () {
$('.edit').show();
}).on("mouseleave", function () {
$('.edit').hide();
}).on("click", '.edit', function () {
var oldText = object.text();
oldText = oldText.substr(4); // Exclude the word 'Edit'
object.replaceWith($("<textarea>").val(oldText).css("width", object.css('width')).css('height', object.css('height')));
var value = $("textarea").val();
alert("Value: " + value);
});
});

jQuery - Event that captures creation of dynamically created text boxes

Does jQuery have an event that will capture the creation of dynamically created DOM content? Or is there some way of doing this in jQuery?
The web page in which I am injecting jQuery into creates text boxes dynamically. I have no control over that. I would however like to check every 3 seconds whether a new text box has been created and then populate it with a value.
The text boxes look like the following:
<input id="AplEducationTbl:EstName:0" type="text" onchange="return false">
<input id="AplEducationTbl:EstName:1" type="text" onchange="return false">
So there are a couple of problems. The id uses a colon, which I don't know how to escape in jQuery. The onchange returns false, which prevents me from hooking on my events.
Using:
setTimeout(function(){
/* What do I put here? */
}, 3000);
Can you use event delegation and search for IDs starting with AplEducationTbl:EstName?
$(document).on("change", "input[id^=AplEducationTbl\\:EstName]", function() {
console.log("Change");
});
jsFiddle
I would however like to check every 3 seconds whether a new text box has been created
To this you have to use setInterval() method instead:
var len = $('input[id^="AplEducationTbl:EstName"]').length;
setInterval(function () {
if ($('input[id^="AplEducationTbl:EstName"]').length > len) {
console.log('changed.');
len = $('input[id^="AplEducationTbl:EstName"]').length;
} //^^^^----------------------------------------update the value of len
}, 3000);
The id uses a colon, which I don't know how to escape in jQuery.
For this either you can use two forward slashes \\ as suggested by other answer and other way to use a string representation put that id value in quotes like this:
$('input[id^="AplEducationTbl:EstName"]')
//-----------^-----------------------^------put the value in quotes like this
//------------------------------------------and you are good to go.

Span tag inside contentEditable div needs keypress event

I have the following div in my html code:
<div id="expanderInput" tabIndex="1" contentEditable></div>
I'm using a contentEditable div as a simple, cross-browser method of making an auto-expanding textbox. I'm also doing input validation on what the user enters into this div. It is supposed to be a list of email addresses separated by commas. When the user tries to submit incorrect information, my Javascript chunks up the input and highlights in red all the incorrect chunks.
//split the address into the comma-separated chunks
var chunks = splitForward(forwardsTo);
//Grab each bad chunk one at a time and stick it in a span with a red-colored text
for(var i = 0; i < invalids.length; i++)
{
var current = chunks[invalids[i]];
current = '<span class="highlighted">' + current + '</span>';
chunks[invalids[i]] = current;
}
$("#expanderInput").html(chunks.join());
initHighlighted();
The array 'invalids' holds the indexes of all the bad chunks. Everything up to this point works fine. But once the user starts typing inside the red text I need the red to disappear, but just in that span. For example, if there are two bad chunks, each highlighted in red, and the user starts fixing one, the other needs to stay red.
I've tried attaching an event listener to the spans:
initHighlighted = function()
{
$(".highlighted").keypress(function()
{
alert("It works!");
});
};
But the event never happens, even when the user edits the text in red. Using browser's developer's tools, I can see that the event handler is there, it is just never set off. Is it the contentEditable attribute on the div causing the span from receiving the event? I've also tried making the spans themselves contentEditable, but the behavior is still the same.
Unless I'm mistaken, this should solve your problem :
initHighlighted = function()
{
$(".highlighted").live("keypress",function()
{
alert("It works!");
});
};
Because your spans are added after the initial loading of the DOM the keypress event listeners haven't been attached as there was nothing to attach them to. Jquery's live sorts this out for you by attaching those listeners to, in this case, anything with the class 'highlighted' no matter when they are added to the DOM.
Read the documentation on the Jquery site to get a much better explanation than I could give you : http://api.jquery.com/live/
EDIT : My apologies for not reading your question properly and realising that your were attaching the keypress listener after after the 'highlighted' spans were added.
Have you read this though :
Keyboard events for child elements in a contenteditable div?

Categories

Resources