I have an element (a checkbox), with this HTML:
<button type="button" class="_f_V1 noMargin o365button" aria-labelledby="_ariaId_28" role="checkbox" aria-checked="false">
<span class="_fc_3 owaimg checkboxImage wf-size-checkboxMultiselectSize ms-bg-color-white ms-border-color-neutralSecondaryAlt"> </span>
<span class="_fc_4 o365buttonLabel _fc_2" id="_ariaId_28" style="display: none;"></span>
</button>
Note it's a button element even though it behaves like an <input [type="checkbox"]>.
I aim to select and click on this element with the click() method. The selection is correct, but the click() method fails.
What I did:
document.querySelector('._f_V1.noMargin.o365button').click();
Yet nothing happens - the checkbox won't be checked.
Given this (first) element is but one of a list of similar elements, I've also tried:
(()=>{
document.querySelectorAll('button span').forEach((e)=>{
e.click()
});
})();
Again, neither the first, nor any other checkbox is selected.
From running querySelector() and querySelectorAll() (with their relevant selectors) in console, I get the elements I want (I don't get undefined), so it means my selections are correct.
Given the selections are correct, why would the click() method have no effect?
When I click with the mouse --- the checkbox is checked but when I use click() on the same element, it doesn't.
If you want to try to reproduce online, you need to have an Hotmail email account with messages that you've already deleted. If this is the case:
Go to "Deleted items".
Go to "recover deleted items".
a window will be opened with deleted conversations.
Near to each conversation there will be a checkbox (after mouseover). This is the element I'm having the trouble with.
Note: The mouseover just changes opacity of the checkboxes.
If the question is:
What can cause click() method to fail?
Then the Answer is: Kinda NOTHING! If the click-method is available for an HTMLElement then calling HTMLElement.click() can not "fail" (in that sense). What could happen is that calling click on this element will not have the desired effect/impact - which is the case for the questions author! "just for the sake of completeness..."
After deeper investigation, here is my conclusion.
The actual event handlers that are responsible for checking and unchecking (and all that is related to it) are callbacks "listen to" mousedown-events on these button._f_V1.noMargin.o365button-elements (boot.worldwide.0.mouse.js:37); so you will not get anywhere triggering click-events. One may ask: "how can you say so?". I can say so because I removed ALL other event listeners first traversing up two parents and then from there on all the way down with each and every child element except for the button where I left the mousedown-eventListener. And the functionality was still intact. After removing also this last event listener the functionality was gone. So I guess: yep I can say so :)
My next step was to trigger a mousedown-event on the button like this:
$('._f_V1.noMargin.o365button').each(function() {
$(this).mousedown();
})
But NO this doesn't work.
So what about hysterically triggering events on every maybe-relevant element like this:
var $El = $('._f_V1.noMargin.o365button').parent().parent();
$El.add( $El.find('*') ).each(function() {
$(this).mousedown().mouseup().click();
// may be one event is cancelling the result of another one out
// so I also tried $(this).mousedown()
});
NO - this also doesn't work.
So I came up with my last approach which didn't work either. Let’s mimic the attributes and properties from selected button. BTW the element that is actually responsible for making the "pseudo checkbox" look like checked/unchecked is the first span-childNode of the button-element. So if you type in the following code in the console of your browsers devtool everything will look exactly as it was properly clicked (or mousedowned so to say):
$('._f_V1.noMargin.o365button').each(function() {
$(this).trigger('mousedown').addClass('_f_V1 noMargin o365button _f_W1').attr('aria-checked', 'true').prop('aria-checked', true)
.children(':first').trigger('mousedown').addClass('_fc_3 owaimg ms-Icon--check wf-size-checkboxMultiselectSize ms-bgc-w ms-fcl-nsa-b ms-fcl-ns-b ms-border-color-neutralSecondaryAlt')
.parent().parent().parent().trigger('mousedown').attr('aria-selected', 'true').prop('aria-selected', true)
})
See the screen capture below where I pastet the above snippet straight into devtools console and the "pseudo checkbox" appear as they where clicked.
So what to do now? Ask another question! One that is much more specific. Something like: "How to [recover|deepDelete] all deleted messages in hotmail.com" Because this is what the intent of the question actually is - not sure about it but I guess.
Just want to emphasize this once more: In general the code from OP and also the code in this answer works. It does right, so to say. But it’s not able to achieve what the author wants to achieve.
Additionally here is a proof that the OPs code is actually working:
document.querySelector('._f_V1.noMargin.o365button').addEventListener(
'click', function() { console.log('jepp') }
);
document.querySelector('._f_V1.noMargin.o365button').click();
// BTW: yep HTMLElement.click() returns undefined
console.log(
'yep HTMLElement.click() returns: ',
document.querySelector('._f_V1.noMargin.o365button').click()
)
button {width: 100%; height: 100%; position: fixed}
<button type="button" class="_f_V1 noMargin o365button" aria-labelledby="_ariaId_28" role="checkbox" aria-checked="false">
<span class="_fc_3 owaimg checkboxImage wf-size-checkboxMultiselectSize ms-bg-color-white ms-border-color-neutralSecondaryAlt"> </span>
<span class="_fc_4 o365buttonLabel _fc_2" id="_ariaId_28" style="display: none;"></span>
</button>
function handelClick(){
if(this.getAttribute("aria-checked")=="true"){
this.setAttribute("aria-checked", "false");
}else{
this.setAttribute("aria-checked", "true");
}
}
var button=document.getElementsByTagName('button');
for (var i = 0; i < button.length; i++) {
button[i].addEventListener('click', handelClick);}
goto https://jsfiddle.net/7xnwpgbk/5/
it may help you
You can try it with jQuery
click method which will only work on jQuery collections created like:
jQuery( 'your whatever selector(s) here' ) // form here on you can call .click() now
So for your specific approach you can do:
jQuery('._f_V1.noMargin.o365button').click();
as well as:
jQuery('button span').click();
Since jQuery click method does only trigger an on click event on the first DOM element of a jQuery collection you can combine it with jQuery method each as follows:
jQuery('._f_V1.noMargin.o365button').each(function() {
$(this).click();
});
as well as:
jQuery('button span').each(function() {
$(this).click();
});
Related
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>
I have to test an application that has some buttons with no text, only graphics (these are < and > buttons on a datepicker, for instance, not in my control).
If I try to find these by:
elm = element.all(by.buttonText(''));
backButton = elm.get(1);
I get no immediate error, but if I say backButton.click() I get:
Error: Index out of bound. Trying to access element at index: 1, but there are only 0 elements that match locator by.buttonText("").
On the other hand if I say
element.all(by.tagName("BUTTON")).filter(function (elem) {
return elem.getText().then(function (text) {
//find the empties
return !(text);
//
});
}).then(function (EmptyButtons) {
EmptyButtons[1].click()
I get a fun error suggesting I found one that I clicked did not pop up yet:
JavascriptError: Element is not currently visible and may not be manipulated (status: 11)
but that is on me to figure out. If I track the text as it comes through the filter, I find there are multiple text-less buttons placed in the array.
I am sorry I do not yet have the skills to generate and test a small example, but I hope perhaps some helpful reader does.
Anyway, I suppose it is possible I am missing something subtle about promise resolution or that the desired behavior is you cannot find a textless button by looking for empty text. I have a workaround, too (actually multiple ones - see my comment below). But I would welcome some clarification here if someone can give it.
Best,
Jeremy Kahan
p.s. I do not see this as a duplicate of "How to click a button with no text in protractor" inasmuch as that wrestles with distinguishing textless buttons, and my question is not how to find and distinguish them, but why searching for text '' does not find them. [My code even suggests how that could have been or could still be implemented, I think.]
From what I understand, you have good workarounds and ways to solve the problem without using by.buttonText and only need an explanation why by.buttonText('') does not work.
If we look into how the by.buttonText is implemented, we would see it first finds only the following "button" variations:
button, input[type="button"], input[type="submit"]
Which means that if the element you are looking for is not the button or appropriate input element, you would not get it matched by the locator.
And, judging by the workaround, the desired elements in your case are actually span elements.
Aside, from that, matching by the empty "button text" should work.
Tested on the datepicker used in our internal application under test - worked for me. Here is how the "<" button looks in our case:
<button type="button" class="btn btn-default btn-sm pull-left" ng-click="move(-1)" tabindex="-1" ap-tab-nav-idx="1.2" ap-tab-nav-child="true">
<i class="glyphicon glyphicon-chevron-left"></i>
</button>
And, if I mimic the "by.buttonText" client side script logic in the console, I would get this element passing all the conditions which determine whether to pick an element or not:
> var element = $("button[ng-click='move(-1)']")[0]
> elementText = element.textContent || element.innerText || '';
> elementText.trim() === ""
true
I can't figure this out. I'm trying to create an onclick handler purely in Javascript.
What I plan to do here is inside this DIV, have a collection of items that I can click on. For now, these items will be numbers from 0 to 9 inclusive. When a number is clicked on, a system message consisting solely of that number should pop-up on the screen. I narrowed my problem down to just the onclick handler definition.
If I use this format:
item[n].onclick=function(n){
handler(n);
}
The handler will fire only when click a number which is correct, but the message that appears is something about mouse event.
If I use this format:
item[n].onclick=function(){
handler(n);
}
The handler will pass a value of -1 which in turn is printed as a message. I think it means "false".
How do I modify this:
item[n].onclick=function(){
handler(n);
}
so that 'n' being used as the handler parameter is the same as the number I click on the screen?
My code is the following:
<div ID="Itemset"></div>
function handler(n){
alert(n);
}
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
collections.appendChild(item[n]);
item[n].onclick=function(n){
handler(n);
}
}
What I'm effectively trying to do if you want to understand it HTML wise is this:
<div ID="Itemset">
<div onclick="handler(0);">0</div>
<div onclick="handler(1);">1</div>
<div onclick="handler(2);">2</div>
<div onclick="handler(3);">3</div>
<div onclick="handler(4);">4</div>
<div onclick="handler(5);">5</div>
<div onclick="handler(6);">6</div>
<div onclick="handler(7);">7</div>
<div onclick="handler(8);">8</div>
<div onclick="handler(9);">9</div>
</div>
Except that I don't want to write out onclick="handler(n);" a million times.
Any advice? and feel free to point to another resource that has the answer I need if there is one.
UPDATE
I'm looking for something compatible with older browsers as well. I'm going to have to not go for the bind function because according to mozilla docs, it works for IE 9+. I'm looking for something that works for IE 7+ as well as other browsers. I might have to go for event listeners if there is no other alternative.
You have a closure issue here (see JavaScript closure inside loops – simple practical example), a simple solution is to use bind to use the current value of n to be a parameter of the handler function
item[n].onclick=handler.bind(item[n],n);
U can use addEventListener and ID for find clicked element...
document.getElementById("Itemset").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
var value_data = parseInt(e.target.textContent);
if(e.target && value_data > -1) {
alert("Malai test:: "+value_data);
//handler(value_data);
}
});
https://jsfiddle.net/malai/tydfx0az/
I found my answer here: https://bytes.com/topic/javascript/answers/652914-how-pass-parameter-using-dom-onclick-function-event
Instead of:
item[n].onclick=function(n){
handler(n);
}
I have to do:
item[n].onclick=new Function('handler('+n+')');
Funny thing is, the word function needs to be capitalized when making a new instance. It's awkward I have to go this route but it works in IE 7+
One alternative is :
function handler(){
alert(this.id);
}
function myFunction() {
var item=[];
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
item[n].setAttribute("id","itemset"+n);
collections.appendChild(item[n]);
item[n].onclick=handler;
}
}
Insert dynamic ids to the elements and when you click on any element retrieve its id using this.id and do whatever you want to do with that value.
That's all.
Hope this helps.
I am trying to make an independently working div which has a form inside of it.
I use jquery to calculate the price of a product depending of the user's selections in the form. However the user is able to add multiple items in his 'cart' so the form is duplicated to another div. The problem is that the calculation pattern can't separate these two divs and the calculation will be incorrect. The form is also interactive so it will be generated by the user's input. This is really complex set and renaming every variable by the 'product number' doesn't sound really efficient to me.
I'm kind of stuck here and i don't really know how to solve this problem. I had an idea that what if I put an iframe inside of the div and load my form and its calculation script inside of it, and then use post command to transfer the price of the product to the 'main page' to calculate the total price of all of the products the user wanted.
However it seems that jQuery scripts doesn't work independently inside of these iframes, they still have connection so they broke each other.
i will appreciate any kind of suggestions and help to solve this matter, thank you!
here's the code so far
Heres the body
var productNumber = 1;
<div id="div_structure">
</div>
<button id="newProduct" >Add new product</button><br \>
add new item
<!-- language: lang-javascript -->
$('#newProduct').click(function ()
{
$('<div id="productNo'+productNumber+'">')
.appendTo('#div_structure')
.html('<label onclick="$(\'#div_productNo'+productNumber+'\').slideToggle()">Product '+productNumber +' </label>'+
'<button onclick="$(\'#product'+productNumber+'\').remove()">Remove</button>');
$('<div id="div_product'+productNumber+'" style="display: none;">').appendTo('#product'+productNumber+'');
$('<iframe src="productform.html" seamless frameborder="0" crolling="no" height="600" width="1000">').appendTo('#div_product'+productNumber+'');
productNumber++;
});
it also has a function that allows the user to remove the inserted div.
Here's just few lines from the productform
$(document).ready(function()
{
$('#productCalculation').change(function ()
{
shape = $('input[name=productShape]:checked', '#productCalculation').val();
alert(shape);
});
});
<form id="productCalculation">
<div id="div_productShape" class="product1">
<h1>Select the shape of the product</h1>
<input type="radio" name="productShape" value="r1">R1</input><br \>
<input type="radio" name="productShape" value="r2">R2</input><br \>
<input type="radio" name="productShape" value="r3">R3</input><br \>
</div>
.
.
.
</form>
I translated all of the variables so they may not function correctly since i didn't test the translated version. So the problem is, if i try to make selections in the second generated div it wont even alert() the selected variable
There are two problems with this code: You say somewhere "I translated all of the variables so they may not function correctly since i didn't test the translated version. So the problem is, if i try to make selections in the second generated div it wont even alert() the selected variable". This is because event handlers are attached to elements that are in the DOM at that specific moment. To get it to work for all elements, use event delegation:
$(document).ready(function()
{
$(document).on( 'change', '#productCalculation', function ()
{
shape = $('input[name=productShape]:checked', '#productCalculation').val();
alert(shape);
});
});
Your other question is "My question in a nutshell: Is there a way to restrict jquery to function only in certain div even though i use the same variable names in the second div ". You can use the this variable to access the element the click was invoked on. From this element you can traverse the DOM if needed, for example with .parent().
$('div').on( 'change', function( e ) {
console.log( $(this).val() );
} );
I'm a webdesigner that's trying to get the hang of JavaScript and jQuery, and I want to learn how to write shorter, more concise code - to avoid being ridiculed by the developers at work ;)
I have this snippet:
// toggle divs when checkbox is checked
$('.product-optional-checkbox1').click(function () {
$('.product-optional-toggle1').toggle('fast');
});
$('.product-optional-checkbox2').click(function () {
$('.product-optional-toggle2').toggle('fast');
});
$('.product-optional-checkbox3').click(function () {
$('.product-optional-toggle3').toggle('fast');
});
// hide divs
$('.product-optional-toggle1').hide();
$('.product-optional-toggle2').hide();
$('.product-optional-toggle3').hide();
...that I want to reduce using a for-loop, like this:
for( var i = 1; i < 4; ++i ) {
$('.product-optional-checkbox' + i).click(function () {
$(this).parent('div').find('div').toggle('fast');
});
$('.product-optional-toggle' + i).css({ display: 'none'});
};
It works fine in FF, however in IE7 it toggles twice. Anyone know who to solve a problem like this?
It's hard to say without seeing the HTML structure but maybe going to the parent then descendants is finding multiple divs?
In your example, you could replace:
$(this).parent('div').find('div').toggle('fast');
With code more similar to the original examples:
$('.product-optional-toggle' + i).toggle('fast');
However, it would be much better to ditch all the numbers and just use a class of .product-optional-checkbox. This way you can add a click function to all elements of that class in one go and avoid the loop:
$('.product-optional-checkbox').click(function () {
// do stuff using $(this)
});
Given that your click events seem to be tied to checkboxes (based on the class names you have in your example), why not actually provide code to handle click events for those checkboxes? For example:
<div id='my_group_of_checkboxes'>
<input type="checkbox" id="checkbox1">
<input type="checkbox" id="checkbox2">
...
</div>
And your jQuery code is then stripped down to three lines:
$('#my_group_of_checkboxes :checkbox').click(function(){
$(this).parent('div').hide('fast');
});
You also seem to need to hide the <div> elements related to each checkbox:
$('div[class^="product-optional"]').hide();
Although ID selectors would be a better option here and, depending on their position within your page, you may even be able to get away with something like:
$('#my_container_div_id div').hide();
If you can post some of your HTML, that might help provide more accurate answers as well.