Given the following markup, I want to detect when an editor has lost focus:
<div class="editor">
<input type="text"/>
<input type="text"/>
</div>
<div class="editor">
<input type="text"/>
<input type="text"/>
</div>
<button>GO</button>
EDIT: As the user tabs through the input elements and as each editor div loses focus (meaning they tabbed outside the div) add the loading class to the div that lost focus.
This bit of jquery is what I expected to work, but it does nothing:
$(".editor")
.blur(function(){
$(this).addClass("loading");
});
This seems to work, until you add the console log and realize it is triggering on every focusout of the inputs.
$('div.editor input').focus( function() {
$(this).parent()
.addClass("focused")
.focusout(function() {
console.log('focusout');
$(this).removeClass("focused")
.addClass("loading");
});
});
Here is a jsfiddle of my test case that I have been working on. I know I am missing something fundamental here. Can some one enlighten me?
EDIT: After some of the comments below, I have this almost working the way I want it. The problem now is detecting when focus changes to somewhere outside an editor div. Here is my current implementation:
function loadData() {
console.log('loading data for editor ' + $(this).attr('id'));
var $editor = $(this).removeClass('loaded')
.addClass('loading');
$.post('/echo/json/', {
delay: 2
})
.done(function () {
$editor.removeClass('loading')
.addClass('loaded');
});
}
$('div.editor input').on('focusin', function () {
console.log('focus changed');
$editor = $(this).closest('.editor');
console.log('current editor is ' + $editor.attr('id'));
if (!$editor.hasClass('focused')) {
console.log('switched editors');
$('.editor.focused')
.removeClass('focused')
.each(loadData);
$editor.addClass('focused');
}
})
A bit more complicated, and using classes for state. I have also added in the next bit of complexity which is to make an async call out when an editor loses focus. Here a my jsfiddle of my current work.
If you wish to treat entry and exit of the pairs of inputs as if they were combined into a single control, you need to see if the element gaining focus is in the same editor. You can do this be delaying the check by one cycle using a setTimeout of 0 (which waits until all current tasks have completed).
$('div.editor input').focusout(function () {
var $editor = $(this).closest('.editor');
// wait for the new element to be focused
setTimeout(function () {
// See if the new focused element is in the editor
if ($.contains($editor[0], document.activeElement)) {
$editor.addClass("focused").removeClass("loading");
}
else
{
$editor.removeClass("focused").addClass("loading");
}
}, 1);
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/8s8ayv52/18/
To complete the puzzle (get your initial green state) you will also need to also catch the focusin event and see if it is coming from the same editor or not (save the previous focused element in a global etc).
Side note: I recently had to write a jQuery plugin that did all this for groups of elements. It generates custom groupfocus and groupblur events to make the rest of the code easier to work with.
Update 1: http://jsfiddle.net/TrueBlueAussie/0y2dvxpf/4/
Based on your new example, you can catch the focusin repeatedly without damage, so tracking the previous focus is not necessary after all. Using my previous setTimeout example resolves the problem you have with clicking outside the divs.
$('div.editor input').focusin(function(){
var $editor = $(this).closest('.editor');
$editor.addClass("focused").removeClass("loading");
}).focusout(function () {
var $editor = $(this).closest('.editor');
// wait for the new element to be focused
setTimeout(function () {
// See if the new focused element is in the editor
if (!$.contains($editor[0], document.activeElement)) {
$editor.removeClass("focused").each(loadData);
}
}, 0);
});
Here's what worked for me:
$(".editor").on("focusout", function() {
var $this = $(this);
setTimeout(function() {
$this.toggleClass("loading", !($this.find(":focus").length));
}, 0);
});
Example:
http://jsfiddle.net/Meligy/Lxm6720k/
I think you can do this. this is an exemple I did. Check it out:
http://jsfiddle.net/igoralves1/j9soL21x/
$( "#divTest" ).focusout(function() {
alert("focusout");
});
Related
I want to trigger an event once a DIV is populated from the back, 2 nodes are inserted in my DIV. I'm using this:
$(function () {
var xml = document.querySelector('#XML');
xml.addEventListener("DOMNodeInserted", function (ev) {
doSomething();
}, false);
});
This works when the XML div is populated once the doc is loaded or reloaded.
At some point, the user clicks a button and the div#XML is populated dynamically without a reload and even though a DOM node is inserted into my element, nothing happens.
How can I trigger "doSomething()" when my div changes?
Your code works fine. Like you can see in Mutation events and the relative compatibility HERE:
$(function () {
$('#XML').on("DOMNodeInserted", function (ev) {
console.log('DO SOMETHING');
});
$('#btnAdd').on('click', function(e) {
$('#XML').append($('<p>', {text: 'this is a new paragragh'}));
});
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<div id="XML"></div>
<button id="btnAdd">Add a paragragh to div</button>
Following code might be the one you looking for. It will look for changes in your div every 1000 milliseconds, you can change that according to your requirements. If your div has some text initially then update the oldVal accordingly.
$('#XML').change(function(){
alert("div has changed!");
// replace with your actions
});
var oldVal = "";
function InputChangeListener()
{
if($('#XML').val() != oldVal)
{
oldVal = $('#XML').val();
$('#XML').change();
}
}
setInterval(InputChangeListener, 1000);
I am using ckeditor for text formating and there is default text inside editor which I want to show selected on focus at all time.
Here is my code
HTML:
<textarea id="FirstTextEditor" >Hello</textarea>
Javascript:
$(document).ready(function(){
CKEDITOR.instances.FirstTextEditor.on('focus', function () {
// What is code i want write to select all text on focus?
});
});
You can simply achieve what you want like this:
CKEDITOR.instances.["your instance here"].on( 'focus', function () { this.execCommand( 'selectAll' ); });
If you used JQuery, it would look like:
$(document).ready(function(){
$('textarea').focus(function(e){
var that = this;
setTimeout(
function() {
that.select()
}, 0);
});
});
JSFiddle - http://jsfiddle.net/s6Z82/5/
The only thing you now have to figure out is how do you get the current element from the CKEDITOR.instances.FirstTextEditor.on callback and you are done.
Why the setTimeout(.., 0)?
Cause seems in Chrome e.preventDefault() does not stop it from discarding the select and putting the cursor to the end of the line.
What I am trying to do is to test when an element (a SELECT) loses its focus if the focus has been transfered to another specific element (another SELECT). I want to trigger something when the focus is lost and is not on one of the two.
The problem is I test in the first select when it has lost the focus (with the blur event) if the other select has it, but the DOM is not yet updated.
Here's an exemple of what I did:
$select1.on("blur", function() {
if($select2.is(":focus"))
{
// do something
}
else
{
// do something else
}
});
$select1 and $select2 are just two variables that contain the element. I read that JQuery adds an identifier ":focus" when an element gains the focus, but the way I did it, it doesn't work.
In all cases, it goes into the else "do something else".
Matt is right about the order of events but you can be a little more creative.
For example use a setTimeout to delay the check for blur so you know you already fired your focus. Simple.
$select1.on("blur", function() {
window.setTimeout(function() {
if($select2.is(":focus"))
{
// do something
}
else
{
// do something else
}
},100);
});
Try that one.
Because the blur event is distinctly fired before the focus of the new element is, the only thing you can do is set a variable in one event and detect it in the other.
$select1.on('blur', function (e) {
var $that = $(this);
setTimeout(function () {
if (($that.data('focussed') || 0) > e.timeStamp - 5) {
// Do something
} else {
// Something else
}
}, 1);
});
$select2.on('focus', function (e) {
$select1.data('focussed', e.timeStamp);
});
See it working here; http://jsfiddle.net/uZAMm/
I want to call a function when a certain field gets blurred, but only if a certain element is clicked. I tried
$('form').click(function() {
$('.field').blur(function() {
//stuff
});
});
and
$('.field').blur(function() {
$('form').click(function() {
//stuff
});
});
But neither works, I reckon it's because the events happen simultaneously?
HTML
<form>
<input class="field" type="textarea" />
<input class="field" type="textarea" />
</form>
<div class="click-me-class" id="click-me">Click Me</div>
<div class="click-me-class">Click Me Class</div>
jQuery
$('.field').blur(function() {
$('#click-me').click(function(e) {
foo = $(this).data('events').click;
if(foo.length <= 1) {
// Place code here
console.log("Hello");
}
$(this).unbind(e);
});
});
You can test it out here: http://jsfiddle.net/WfPEW/7/
In most browsers, you can use document.activeElement to achieve this:
$('.field').blur(function(){
if ($(document.activeElement).closest('form').length) {
// an element in your form now has focus
}
});
I have edited my answer because we have to take into account that the event is asigned every time.
It is not 100% satisfactory, and I don't recommend this kind of complicated way of doing things, but it is the more approximate.
You have to use a global variable to take into account the fact that the field was blurred. In the window event, it is automatically reset to 0, but if the click on "click-me" is produced, it is verified before the window event, becase window event is bubbled later, it happens inmediately after the "click-me" click event
Working code
$(window).click(function(e)
{
$("#result").html($("#result").html()+" isBlurred=0<br/>");
isBlurred=0;
});
var isBlurred=0;
$('.field').blur(function() {
$("#result").html($("#result").html()+" isBlurred=1<br/>");
isBlurred=1;
});
$('#click-me').click(function(e) {
if(isBlurred==1)
{
$("#result").html($("#result").html()+" clicked<br/>");
}
});
".field" would be the input and "#click-me" would be the element clicked only just once.
I have a small jQuery script:
$('.field').blur(function() {
$(this).next().children().hide();
});
The children that is hidden contains some links. This makes it impossible to click the links (because they get hidden). What is an appropriate solution to this?
This is as close as I have got:
$('.field').blur(function() {
$('*').not('.adress').click(function(e) {
foo = $(this).data('events').click;
if(foo.length <= 1) {
// $(this).next('.spacer').children().removeClass("visible");
}
$(this).unbind(e);
});
});
The uncommented line is suppose to refer to the field that is blurred, but it doesn't seem to work. Any suggestions?
You can give it a slight delay, like this:
$('.field').blur(function() {
var kids = $(this).next().children();
setTimeout(function() { kids.hide(); }, 10);
});
This gives you time to click before those child links go away.
This is how I ended up doing it:
var curFocus;
$(document).delegate('*','mousedown', function(){
if ((this != curFocus) && // don't bother if this was the previous active element
($(curFocus).is('.field')) && // if it was a .field that was blurred
!($(this).is('.adress'))
) {
$('.' + $(curFocus).attr("id")).removeClass("visible"); // take action based on the blurred element
}
curFocus = this; // log the newly focussed element for the next event
});
I believe you can use .not('a') in this situation:
$('.field').not('a').blur(function() {
$(this).next().children().hide();
});
This isn't tested, so I am not sure if this will work or not.