Is using THIS more efficent than using the selector? - javascript

I have a simple form so user send his vote.
There I need to know what radio button user select.
The version I found to solve it was this. How can I get which radio is selected via jQuery?
value = $('input[name=vote]:checked', '#frmSurvey').val();
This work ok. Even when I dont understand how that work, because in Jquery selector documentation there is only 2 example with item separated by coma. And neither match my example where each element is inside a quote and then a coma
.class , .class ---> $(".intro,.demo") All elements with the class "intro" or "demo"
el1 , el2 , el3 ---> $("h1,div,p") All < h1>, < div> and < p> elements
Both looks like OR selector instead of find A and then find B inside A.
So if anyone can tell me what kind of selector is that I would love to take a look into the documentation
Now the optimization I was thinking. If I already inside a function for #frmSurvey won't be faster if I use the this element
$('#frmSurvey').ajaxForm(function () {
value = $('input[name=vote]:checked', '#frmSurvey').val();
console.log('working way ' + value);
value = $(this).find('input[name=vote]:checked').val();
console.log('testing way ' + value);
But I couldn't make the second version to work. Second value get me undefined.
So how I fix second version?
And would be second version better than first one as my instinct suggest or I'm worrying too much?

Your first example shows a selector operating from a context selector, whereas the documentation you've shown shows a "multiple selectors" selector.
You seem to have partially grasped this as
value = $('input[name=vote]:checked', '#frmSurvey').val();
is essentially the same as
value = $('#frmSurvey').find('input[name=vote]:checked').val();
However, the context of "this" inside your function is not clear as it depends upon how the ajaxForm plugin is coded. It isn't necessarily the result of your initial selector. After a short play with the plugin, it would appear that this in the context of ajaxForm is the jQuery ajax request object.

Related

Rails/Rspec/Capybara: Interpreting quotes for javascript string for execute script

Given that I need to set an element's selected index with javascript in capybara by the input name...
var element = document.querySelector("select[name='user[user_locations_attributes][0][location_attributes][state]']").selectedIndex = '50';
What is the proper way to interpret this as a string so it can be executed in Capybara with execute_script(function_name_string)? Because I keep getting syntax errors, unsure how to nest the " and ' quotations.
Easiest solution to your question is to use a heredoc
page.execute_script <<~JS
var element = document.querySelector("select[name='user[user_locations_attributes][0][location_attributes][state]']").selectedIndex = '50';
JS
Although if you have need for the element for anything else it's probably nicer to find the element in ruby and then just call execute_script on the element
el = find("select[name='user[user_locations_attributes][0][location_attributes][state]']")
el.execute_script('this.selectedIndex = 50;')
As a related question - is there a reason you're doing this via JS rather than just clicking on the correct option? If you're just scraping a page there's no issue, but if you're actually testing something this basically makes your test invalid since you could potentially be doing things a user couldn't
Since you commented that you are testing, you really shouldn't be doing this via JS, but should instead be using select or select_option. select takes the options string (which you should have - otherwise why have a select element in the first place)
select('the text of option', from: 'user[user_locations_attributes][0][location_attributes][state]')
select_option is called on the option element directly, which can be found in a number of ways, such as
find("select[name='user[user_locations_attributes][0][location_attributes][state]'] option:nth-child(50)").select_option

How to find a value of an attribute of an element

Here is a piece of code
<span class="balance themecolor" data-balance="2800">
I'm looking for a way to extract the value of data-balance and set it as variable x, but I have absolutely no idea how to do it. I know of the existence of .val() but I don't know if I can apply it to this code. I'm looking a for a one line long solution.
If you're using jQuery (as you've mentioned .val()):
var x = $("[data-balance]").attr("data-balance");
Or if you aren't:
var x = document.querySelector("[data-balance]").getAttribute("data-balance");
In both cases, the [data-balance] is a CSS selector for the element; adjust as needed. For instance, with that element, and assuming no other elements with either of its classes, you could use .balance, .themecolor, or even .balance.themecolor.
jQuery will find all elements matching the selector (you can change that if it's an issue, usually it isn't), but then only give you the attribute value for the first one.
querySelector will stop with the first one. If you want to find them all and get a list, use querySelectorAll (and then index into it to get the individual ones).

Create a bookmarklet that clicks multiple buttons on one page without jQuery

Last year I asked a question similar to the question I am asking here-
Create a Bookmarklet that clicks multiple buttons on one page
The accepted answer works perfectly on a page that uses jQuery. However I need to get something similar working on a page that doesn't load jQuery. I tried to insert jQuery into the page in the bookmarklet but it refuses to load (the website doesn't allow it).
How do I convert the following to pure Javascript so that I can click multiple buttons on the page?
(function(){
var UserFollowButton = $('button.UserFollowButton');
var index = UserFollowButton.length-1;
follow();
function follow(){
if(index >= 0){
$(UserFollowButton[index--]).click();
setTimeout(follow, 500);
}
}
})();
To get a list of UserFollowButton equivalent to the query you just ran, you should use getElementsByClassName("UserFollowButton") which gives you an HTMLCollection of elements with a particular class name. Then, you can filter that collection to elements with the tagName equal to BUTTON.
Then, to click it, simply apply the method DOMElement.click to each element in the array. You can do that using forEach.
Array.prototype.slice.call( // convert HTMLCollection to Array
document.getElementsByClassName("UserFollowButton")
).filter(function(element) {
return element.tagName === "BUTTON";
}).forEach(function(element){
element.click();
});
If you want the timeout, then you can simply set UserFollowButton to Array.prototype.slice.call(document.getElementsByClassName("UserFollowButton")).filter(function(element) { return element.tagName === "BUTTON"; });, then do what you are currently doing, using UserFollowButton[i].click() instead of implicit jQuery conversions.
Instead of having a global variable you are indexing from, though, try keeping the array local, passing it as an argument, using pop to take the first element, and keep passing it to subsequent callbacks.

Error:Error response status: 13 when calling waitForCondition

I am trying to write a browser test using selenium-webdriverjs. When I call the following code snippet, I get Error:Error response: 13.
browser.waitForCondition('var element = document.querySelector(".selector"); var style = document.defaultView.getComputedStyle(element,null); style =' + btnColor ,timeout);
I am waiting for a condition which I would like to get a computed css style from an element obtained from a css selector. Then the computed css style is compared to a variable called btnColor. (I know that it is also possible to do the same thing using a Webdriver JS API method called getComputedCss. However, I am interested in using waitForCondition to achieve the same purpose.)
I would like to know how to properly use waitForCondition to achieve what I want to do as said above and why the code snippet is throwing the error.
Thanks in advance!
I have found my answer to this question.I have made several javascript mistakes in the expression. The following is the code snippet I have used to solve my problem.
browser.waitForCondition('var element = window.document.querySelector(".selector"); var style = window.document.defaultView.getComputedStyle(element,null).getPropertyValue("background-color"); style ="' + btnColor + '"',timeout);
1) In order to use document, you need to call the window object first.
2) In order to get the computed background-color, I need to use the method .getPropertyValue().
3) btnColor contains a string. Therefore I need to put a double-quotation around it for the interpreter to recognize it as a string.

Adding Javascript variables to HTML elements

So, I have some code that should do four things:
remove the ".mp4" extension from every title
change my video category
put the same description in all of the videos
put the same keywords in all of the videos
Note: All of this would be done on the YouTube upload page. I'm using Greasemonkey in Mozilla Firefox.
I wrote this, but my question is: how do I change the HTML title in the actual HTML page to the new title (which is a Javascript variable)?
This is my code:
function remove_mp4()
{
var title = document.getElementsByName("title").value;
var new_title = title.replace(title.match(".mp4"), "");
}
function add_description()
{
var description = document.getElementsByName("description").value;
var new_description = "Subscribe."
}
function add_keywords()
{
var keywords = document.getElementsByName("keywords").value;
var new_keywords = prompt("Enter keywords.", "");
}
function change_category()
{
var category = document.getElementsByName("category").value;
var new_category = "<option value="27">Education</option>"
}
remove_mp4();
add_description();
add_keywords();
change_category();
Note: If you see any mistakes in the JavaScript code, please let me know.
Note 2: If you wonder why I stored the current HTML values in variables, that's because I think I will have to use them in order to replace HTML values (I may be wrong).
A lot of things have been covered already, but still i would like to remind you that if you are looking for cross browser compatibility innerHTML won't be enough, as you may need innerText too or textContent to tackle some old versions of IE or even using some other way to modify the content of an element.
As a side note innerHTML is considered from a great majority of people as deprecated though some others still use it. (i'm not here to debate about is it good or not to use it but this is just a little remark for you to checkabout)
Regarding remarks, i would suggest minimizing the number of functions you create by creating some more generic versions for editing or adding purposes, eg you could do the following :
/*
* #param $affectedElements the collection of elements to be changed
* #param $attribute here means the attribute to be added to each of those elements
* #param $attributeValue the value of that attribute
*/
function add($affectedElements, $attribute, $attributeValue){
for(int i=0; i<$affectedElements.length; i++){
($affectedElements[i]).setAttribute($attribute, $attributeValue);
}
}
If you use a global function to do the work for you, not only your coce is gonna be easier to maintain but also you'll avoid fetching for elements in the DOM many many times, which will considerably make your script run faster. For example, in your previous code you fetch the DOM for a set of specific elements before you can add a value to them, in other words everytime your function is executed you'll have to go through the whole DOM to retrieve your elements, while if you just fetch your elements once then store in a var and just pass them to a function that's focusing on adding or changing only, you're clearly avoiding some repetitive tasks to be done.
Concerning the last function i think code is still incomplete, but i would suggest you use the built in methods for manipulating HTMLOption stuff, if i remember well, using plain JavaScript you'll find yourself typing this :
var category = document.getElem.... . options[put-index-here];
//JavaScript also lets you create <option> elements with the Option() constructor
Anyway, my point is that you would better use JavaScript's available methods to do the work instead of relying on innerHTML fpr anything you may need, i know innerHTML is the simplest and fastest way to get your work done, but if i can say it's like if you built a whole HTML page using and tags only instead of using various semantic tags that would help make everything clearer.
As a last point for future use, if you're interested by jQuery, this will give you a different way to manipulate your DOM through CSS selectors in a much more advanced way than plain JavaScript can do.
you can check out this link too :
replacement for innerHTML
I assume that your question is only about the title changing, and not about the rest; also, I assume you mean changing all elements in the document that have "title" as name attribute, and not the document title.
In that case, you could indeed use document.getElementsByName("title").
To handle the name="title" elements, you could do:
titleElems=document.getElementsByName("title");
for(i=0;i<titleElems.length;i++){
titleInner=titleElems[i].innerHTML;
titleElems[i].innerHTML=titleInner.replace(titleInner.match(".mp4"), "");
}
For the name="description" element, use this: (assuming there's only one name="description" element on the page, or you want the first one)
document.getElementsByName("description")[0].value="Subscribe.";
I wasn't really sure about the keywords (I haven't got a YouTube page in front of me right now), so this assumes it's a text field/area just like the description:
document.getElementsByName("keywords")[0].value=prompt("Please enter keywords:","");
Again, based on your question which just sets the .value of the category thingy:
document.getElementsByName("description")[0].value="<option value='27'>Education</option>";
At the last one, though, note that I changed the "27" into '27': you can't put double quotes inside a double-quoted string assuming they're handled just like any other character :)
Did this help a little more? :)
Sry, but your question is not quite clear. What exactly is your HTML title that you are referring to?
If it's an element that you wish to modify, use this :
element.setAttribute('title', 'new-title-here');
If you want to modify the window title (shown in the browser tab), you can do the following :
document.title = "the new title";
You've reading elements from .value property, so you should write back it too:
document.getElementsByName("title").value = new_title
If you are refering to changing text content in an element called title try using innerHTML
var title = document.getElementsByName("title").value;
document.getElementsByName("title").innerHTML = title.replace(title.match(".mp4"), "");
source: https://developer.mozilla.org/en-US/docs/DOM/element.innerHTML
The <title> element is an invisible one, it is only displayed indirectly - in the window or tab title. This means that you want to change whatever is displayed in the window/tab title and not the HTML code itself. You can do this by changing the document.title property:
function remove_mp4()
{
document.title = document.title.replace(title.match(".mp4"), "");
}

Categories