Button generated by Javascript unrecognized until right click - javascript

Issue: generated button isn't registered on click ~1/20 times.
I'm generating a button :
var thebutton = document.createElement("BUTTON");
thebutton.setAttribute("id", "mybutton");
thebutton.setAttribute("class", "mybuttonclass");
thebutton.setAttribute("onclick","function()");
thebutton.innerHTML = '<i class="icon info"></i>';
document.getElementById("row").appendChild(thebutton);
Which is appended on top an existing button element as a second z-index layer:
.mybuttonclass {
z-index:9999;
}
I am also using
focusMethod = function getFocus() {
document.getElementById("mybutton").focus();
}
focusMethod();
In order to shift the browser selection from the trigger of the generating code (also a button) to #mybutton which works as it is highlighted.
Still for some reason, arbitrarily, every few times the button is created, any clicks will not registered to the created button, and in order to fix it and be able to trigger it, i need to right click the page -- after which the button starts to work.
Is there any way to have the browser rescan the page for elements after I generate the button? Or is there some other issue causing this that I'm missing?
Seems to happen in chrome more often, bootstrap is also run on CSS for the page.

Related

How to avoid double click on different button?

My problem is not a double click on same button but on 2 buttons.
User make a double click on a button.
The first click is detected by a first button
the controller do the action
the UI is refreshed, another button is display at same position
the second click is catched by the second button
=> user don't want click on the second button
How can I avoid this ?
I have tested :
To disable all UI buttons during action
but if action is really quick, buttons are enable before the second click
To not put 2 buttons on same place in the UI
not always possible and with responsive UI it's not possible to manage all cases
To add a global timestamp on click, and test during the second click if we have 500ms
_click: function(args)
{
// to avoid double click user need wait 500ms between each click
if(window.paperbutton_timestamp)
{
var diff = new Date() - window.paperbutton_timestamp;
if(diff < 500)
{
window.paperbutton_timestamp = new Date();
return;
}
}
window.paperbutton_timestamp = new Date();
if(scope.click)
{
scope.click(args);
}
},
Ok it does the job.
Now my problem is I have many protractor end to end tests, with more 2000 clicks.
Some protractor click are done in less 500ms.
Which solution can I have ?
1. Add a wait after each click
(more 2000 wait to add manually)
2. Set the 500ms in a global variable and override this value to 0ms
how to override on each test and each page refresh ?
3. Override protractor click ?
Seam is the better solution but I don't know how to do this.
Do you have another better idea :) ?
This is usually solved using good old human-computer interaction. Try using a style of button that visually reacts to hover, mousedown and mouseup events. This is usually enough to the user understand that a double click is not necessary. Stackoverflow itself has an awesome example:
Iddle button:
Hover button:
Mousedown button:
Mouseup button:
But if you really wish to prevent undesired clicks, maybe the best approach would be to disable buttons during actions and when you are about to re-enable then, put this action in a timeout, so the disabled buttons will last a little longer.
Another suggestion
You could implement a global function to spawn an invisible div covering the whole screen when required. This would prevent everything onscreen from working.
<div style="position:fixed; top:0; left:0; width:100vw; height:100vh; z-index: 10000"></div>
Put it in your layout file, usually app.component.html, and implement a *ngIf for it show up only when necessary. Also, its z-index should be greater than the z-index of any other element in your whole app.
have you consider Using *NgIf for both the buttons
**
<button *NgIf="oneActive" (click)="oneActive=false;callfunction()">one</button>
<button *NgIf="!oneActive" (click)="oneActive=true;callfunction2()">two</button>
**
It would be better if you write a custom function for protractor click:
protractor.ElementFinder.prototype.waitClick = function(wait){
browser.sleep(wait);
this.click();
};
describe('Tests', function() {
element.all(by.css('#testElements')).get(0).waitClick(1000)
});
Since, overriding the default click function is not recommended.

Clicking a button added by JavaScript clicks through it as well

I'm working on a script that adds a button that floats on top of a Facebook user's profile photo thumbnail.
Here's a screenshot:
This button, when clicked, returns the Facebook ID of the profile that is being viewed in a prompt. That part works fine (but you'd need to be logged in and looking at a profile besides yours, otherwise there'd be a missing element).
Screenshot:
What's bothering me though, is after clicking the button, and pressing Cancel or Okay in the prompt, the click actually goes through the button and clicks the profile picture thumbnail itself. A single click is clicking both items!
Is there any way we can make it so that the area below the button itself is not clickable? But the rest of the profile picture is?
I've tried searching on this topic but couldn't find much results. Even if I try to search for something like "Add padding below/under button JavaScript", I'm getting padding around the button, and not directly below it
in a z-axis point of view.
Here's the script code, you can copy paste it in the console directly. That is, if you have a Facebook account and are logged in. Also this only works on profiles besides yours (otherwise data-profileid would be missing).
// Create the button
var btn = document.createElement("BUTTON");
var t = document.createTextNode("FBID"); // To replace with icon
btn.appendChild(t);
// Add a listener
btn.addEventListener("click", getFBID);
// Styling (positioning)
btn.style.display="block";
btn.style.position="absolute";
btn.style.top="4px";
btn.style.right="4px";
// Function to get Facebook ID
function getFBID() {
prompt("Copy it:", document.querySelectorAll("[data-profileid]")[0].getAttribute("data-profileid"));
}
// Append button to profile picture
document.getElementsByClassName("profilePicThumb")[0].appendChild(btn);
Oh yeah, I feel the reason why this is happening is because I am appending to an anchor link. Just in case this info would be useful.
Any help appreciated, thank you!
Try to prevent the default actions for the click like this:
btn.addEventListener("click", function(event){
event.preventDefault();
event.stopPropagation();
getFBID();
return false;
});
EDIT: use event.stopPropagation();
(compare to this thread How to stop event bubbling on checkbox click)
Try this
// Create the button
var btn = document.createElement("BUTTON");
var t = document.createTextNode("FBID"); // To replace with icon
btn.appendChild(t);
// Add a listener
btn.addEventListener("click", getFBID);
// Styling (positioning)
btn.style.display="block";
btn.style.position="absolute";
btn.style.top="4px";
btn.style.right="4px";
// Function to get Facebook ID
function getFBID() {
prompt("Copy it:", document.querySelectorAll("[data-profileid]")[0].getAttribute("data-profileid"));
return false; // Try returning false here..
}
// Append button to profile picture
document.getElementsByClassName("profilePicThumb")[0].appendChild(btn);
getFBID in this case is a callback for the event that is raised on the click of the button. returning false will make sure that the event is not propagated to its parent and hence will not raise the parent's event or call the eventhandler.

Why is my page refreshing after hiding some elements?

I have a page that "fakes" going to another page by means of conditionally showing/hiding certain elements. When either of the two images that are shown by default are clicked, they are both hidden and, based on which one was clicked, other elements are displayed.
Among the elements then displayed is a "go back" button. When that button is clicked, it hides what is currently being displayed (including itself), and shows the original two images.
It works, except the page, after a brief delay, "blinks" (is refreshed). Why, and how can I avoid this refresh?
Here's the jQuery behind the button click:
$('#backToMain').on( "click", function() {
$('#preTravelImages').addClass('finaff-form-help-hide');
$('#postTravelImages').addClass('finaff-form-help-hide');
$('#preTravel').removeClass('finaff-form-help-hide');
$('#postTravel').removeClass('finaff-form-help-hide');
$('#backToMain').addClass('finaff-form-help-hide');
});
Note: "preTravelImages" is a div that contains several images; the same goes for "postTravelImages". "preTravel" and "postTravel" both contain one image only (clicking the preTravel image makes the images in preTravelImages visible, and likewise clicking the postTravelImage makes the images in postTravelImages visible).
The "hide" class is:
.finaff-form-help-hide {
visibility: hidden;
display: none;
}
Here is the button that is clicked:
<button class="finaff-form-help-hide" id="backToMain" name="backToMain">Back to Form Help</button>
Does the order of these add/remove Class calls matter? Or what do I need to do?
Add a return false to prevent default link action:
$('#backToMain').on("click", function() {
$('#preTravelImages').addClass('finaff-form-help-hide');
$('#postTravelImages').addClass('finaff-form-help-hide');
$('#preTravel').removeClass('finaff-form-help-hide');
$('#postTravel').removeClass('finaff-form-help-hide');
$('#backToMain').addClass('finaff-form-help-hide');
return false;
});

JavaScript Restrict User From Clicking Button Multiple Times

I am trying to restrict the user from clicking on a button multiple times. They can click on the button once when the page loads. If the page is reloaded the same should apply the user can click on the button only once.
I am using the following code however it doesn't seem to work for me
$("#doAccess").click(function() {
$("#doAccess").removeAttr('onclick');
DoSave();
});
Disable the button after it's been clicked
var accessBtn = $('#doAccess');
accessBtn.click(function() {
accessBtn[0].disabled = true;
DoSave();
});
Sounds like what you really need is:
$("#doAccess").one('click', DoSave);
jsFiddle example
.one() - Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
Why not this?
$("#doAccess").once('click', function() {
DoSave();
});
You should probably also gray out or disable #doAccess, whatever it is.

Run a certain behavior if click target is only on one element but not another?

I've got a bit of a jQuery intensive user experience.
I'm having an issue in making sure a certain dialog box opens only when the click target is one item but not another.
Basically, I want the "edit text" dialog to show up only when the user clicks on a div with class .textbox (which happens to be in #content div), but not when the user clicks on a part of the instantiated tinyMCE instance (such as its options etc). I've set up tinyMCE so that when activated, the toolbar appears in #externalToolbarWrapper.
This is my code:
// check if the click's target element is parented by a textbox or mceLayout.
var $etextbox = $(e.target).closest('.textbox');
var $etoolbar = $(e.target).closest('.mceLayout');
if($etextbox.length==1 && $etoolbar.length == 0) // only the text parent and not toolbar is clicked
{
doStuff();
}
However, using this code, doStuff is triggered even when the click was made outside the content box, and on a part of the TinyMCE toolbar (such as to change a font or size).
So I tried adding a few more possibilities:
var $eformat = $(e.target).closest('#externalToolbarWrapper');
var $econtent = $(e.target).closest('#content');
And then I output in the console:
console.log("textbox: " + $etextbox.length);
console.log("etoolbar: " + $etoolbar.length);
console.log("eformat: " + $eformat.length);
console.log("econtent: " + $econtent.length);
But after a click on the TinyMCE toolbar, I get the following results:
etextbox: 0
etoolbar: 0
emenu: 0
eformat: 0
econtent: 1
and I tried an additional check:
if($etextbox.length==1 && $etoolbar.length == 0 && $etoolbar.length==0 && $eformat.length==0)
but even when the click takes place outside the content div and on the toolbar, it's still counted and so doStuff() always triggers. So apparently none of the conditions I tried help to ever detect that the click was made on a TinyMCE toolbar and not on a textbox.
How can I make sure the click only triggers my function when the click is directly on the textbox div, and not otherwise?
In the end I solved this problem simply by checking the e.pageX and e.pageY coordinates and making sure they weren't within the #content div. So if the click was outside the content, it didn't trigger doStuff().

Categories

Resources