Event fires second only, after sequence of user actions

Asked

Viewed 672 times

5

I have a form where there’s a table. At the bottom of this, there are buttons to manipulate the table rows, and only the selected ones will be affected.

inserir a descrição da imagem aqui

Steps to play problem

jsfiddle to check the problem

        fiddle result for testing in IE 8

  1. click on any box so that it turns orange
  2. click on one of the command buttons
  3. click again on the box to deselect the line

    Won’t work!

  4. click again to deselect the line

    Now it works!

This fiddle is already with javascript code very well isolated, not even scroll in the fiddle (in the part of the script, which is where I think the problem is)... but still could not solve the problem.

Question

How to make the box deselect on first click?

Please, if you know the solution, explain to me... do not just put code... I would very much like to know why this is not working.

Browsers I tested that present the problem: Chrome 34, Firefox 28, IE 8

To tell you the truth, I care a lot about solving for Chrome, a little less for FF, and not a little bit for IE 8... I only mentioned IE 8 to show that the problem is consistent between browsers.

Notes:

I found that by removing the lines below, it works the way I want it... almost... Are two lines equal to this:

.bind("blur mouseout", restore)

However, this way I lose the mouse-out, which serves to clear the icon that is placed inside the orange box indicating which lines are affected, because not always a selected line can be affected by a command.

  • Do you have any code for when the button is clicked? i.e.: want to use Event Handler clickto run code when the button is clicked? Or only uses the mousehover and mouseout?

2 answers

4


Most likely your problem is in blur. Follow the following steps:

  1. click on any box so that it turns orange
  2. click on one of the command buttons

    2.1. transfer focus to another place (click another window, use Tab several times, etc)

  3. click again on the box to deselect the line

    Now it works!

Explanation

When you nay transfer focus, the following things happen:

  1. When you click, focus is still on the rotary pushbutton;
  2. The first thing to happen, therefore, is the event blur on that button;
  3. This event causes a restore, that changes the html of the element being clicked;
  4. As that element has just changed, he probably is not yet subject to live;
  5. The click actually happens; as the element is not yet subject to the live it does not record the click.

Proposal for a solution (imperfect):

If the event that caused the Restore is not a blur, force him:

var restore = function(e) {
    if ( e.type != "blur" )
        $(this).blur();
    $("#columns .selected .selector").get(0).innerHTML
        = "<i>&nbsp;</i>";
};

Example in jsFiddle. This is not the ideal solution (e.g.: if the user transferred the focus to the button, passed the mouse over unintentionally, then pressed "space" it will be surprised the button has lost focus), but serves as a basis for a better solution. Another scenario that may surprise the user is whether he used the keyboard to trigger the command button (i.e. he has the focus, and never received a mouseout) and the mouse to try to de-select the line (i.e. the blur command button will be enabled) - in this case, the bug will remain.

I can’t think of a better solution, so the ideal would be do not change the html of the element being clicked, in order to avoid this Glitch. I’m afraid I have nothing to suggest about it, but if I can think of anything better, I’ll post it here.


Updating

I set up an example without touching the Markup or CSS, which works correctly except for a small visual detail. It is based on the above proposal - not to touch html during a blur:

var showIcon = function() {
    // Esconde o elemento presente
    $("#columns .selected .selector i").hide();

    // Obtém o ícone; se ele não existe, cria-o
    var icone = $("#columns .selected .selector .icone");
    if ( icone.length == 0 )
        icone = $('<span class="icone"></span>').appendTo($("#columns .selected .selector"));

    // Atualiza-o para ficar igual ao botão de comando
    icone.html($(this).html()).show();
}

var restore = function() {
    // Mostra de novo o elemento vazio e esconde o ícone
    $("#columns .selected .selector i").show();
    $("#columns .selected .selector .icone").hide();
};

Example in jsFiddle. As we are not changing the html of the element (which I confirmed is enough for clicking to fail - be using live or jQuery 1.7+ using on) Glitch does not occur. Only missing position the element with CSS to be inside the square.

  • Man, thank you so much for the help... that’s right: I won’t be able to change the HTML of the element during Blur. I had already tested with other ways of listening to the click event, including assigning a function directly to the property onclick... the click event is simply not called.

  • I solved as follows: I used a setTimeout with 0 milliseconds to set html, and within the method restore I had to make an adaptation for the event mouseout not be called with the child element of the button itself. jsfiddle... but it’s not yet perfect. = I’ll keep trying in this line to see what gives.

  • I think I finally made it: jsfiddle... thanks to your answer! = D

2

When you click on button it also fires an event focus (http://jsfiddle.net/Xqfnu/).

One option, similar to the idea of @mgibsonbr would be to fire a blur at the moment of clicking. This solves the problem for me in Chrome: http://jsfiddle.net/Xqfnu/1/

var clic = function () {
   $(this).blur();
}

//...

// UP
$("#move-column-up")
    .bind("click", clic)
    .bind("focus mouseover", showIcon)
    .bind("blur mouseout", restore)

// DOWN
$("#move-column-down")
    .bind("click", clic)
    .bind("focus mouseover", showIcon)
    .bind("blur mouseout", restore)

By the way, and not sure why e.preventDefault(), put type="button" on the button it stops doing Ubmit to form every time you click.

  • Thanks for the tip... I ended up solving with a setTimeout to change HTML asynchronously: http://jsfiddle.net/7pEPK/7/ I’m not sure if this is completely recommended... but it worked. What do you think, will I have problems with this my solution?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.