Selenium with Python -- finding element without proper identifiers - javascript

I am using selenium with python to write the code. I am looking to pull the information from a text box. The box auto fills as other information is being filled out. Inspecting the box gives the following code:
<input type="tel" autocomplete="off" name="amount" step="any" class="form-
control ng-pristine ng-untouched ng-valid ng-isolate-scope ng-not-empty"
placeholder="" tw-focusable="" show-decimals="$ctrl.showDecimals" tw-number-
input-formatter="" ng-change="$ctrl.changedAmount()" ng-
model="$ctrl.ngModel" ng-disabled="$ctrl.ngDisabled" disabled="disabled"
style="">
The issue is that there is already another input box that has the name "amount", so I can't do a simple selection by name. I am thinking this would require me to use a CSS selector but everything I have tried so far has not worked. Please let me know what I can try.

Looks like you need to use CSS or XPath locators.
Its hard to tell how exactly you can find that element since you haven't provided a source of the entire page but here are some tips.
In the worst case when you cant find any combination of attributes that will uniquely identify the element you need to rely on dom nodes hierarchy, i.e. in order to find first input on the following page:
<!DOCTYPE html>
<html>
<head>
<title>Dummy page</title>
</head>
<body>
<div>
<div>
<input type="text">
</div>
<p>
<input type="text">
</p>
<input type="text">
</div>
</body>
</html>
You can use XPath locator that might look similar to this one:
//div/div/input
But that's the worst case, usually you can use more flexible locators based on element attributes that less likely to be affected by page structure modifications. Let's say each of our inputs from the page above has "name" and "disabled" attributes.
<div>
<div>
<input name="input1" disabled="" type="text">
</div>
<p>
<input name="input1" disabled="disabled" type="text">
</p>
<input name="input2" disabled="" type="text">
</div>
Then we can find first input using the following locator:
//input[#name="input1" and #disabled=""]
Hope that helps.

Related

Multiple datepickers in same page

I'm using kendo UI datepicker, I'm trying to put more than one datepicker in the same page using one function with the same ID i don't want to be changed, the first input already exists in my page but the others are added dynamically, any suggestions on how to fix that?
$("#datepicker").kendoDatePicker();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="datepicker">
<br>
<br>
<input id="datepicker">
<br>
<br>
<input id="datepicker">
$("#datepicker").kendoDatePicker();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="datepicker1">
<br>
<br>
<input id="datepicker2">
<br>
<br>
<input id="datepicker3">
The problem is that you are using the same id on more than one instance and this is not a good choice. The page it self is not going to give any error but when you call a tag referring it by id, it will stop on the first assuming by default the id is a unique name.
As suggested by the op on the other solution yes, you can use a class name on multiple tags and can refer all the tags by a single class
$(".datepicker_class").kendoDatePicker();
but i suggest you, in your case, as you have to deal with dates, to not create conflicts, is better to use unique id.
Simple, change id and call kendo lib as.
$("#datepicker1").kendoDatePicker();
$("#datepicker2").kendoDatePicker();
$("#datepicker3").kendoDatePicker();
You are using the same id and the selector stops when the first match is found. Since you want to collect items, change the inputs to have a mydatepicker class:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input class="mydatepicker">
<br>
<br>
<input class="mydatepicker">
<br>
<br>
<input class="mydatepicker">
Now, I think
$(".mydatepicker").kendoDatePicker();
should work.

Identical ID's in the same HTML page

I have a page that has two different inputs that contain same ID but each one in different form. and I'm actually setting values to inputs from javascript using get element by ID. I know this is not valid. but the thing is if i change one of the input id's I'm gonna need to re write a bunch of code in 'shopping cart ' cuz these input's pass value to cart. I'm actually not planning to touch that for now. So, is there any trick that can target one input instead of the other even if they have the same id's??
ex:
<input type="hidden" name="cart_1_ID_Add2" id="cart_1_ID_Add2" value=""/>
<input type="hidden" name=cart_1_ID_Add2" id="cart_1_ID_Add2" value=""/>
thanks in advance!!
Although it is a wrong practice, and you should use different id's, you could add a different class attribute to each one.
<input class="input1" type="hidden" name="cart_1_ID_Add2" id="cart_1_ID_Add2" value=""/>
<input class="input2" type="hidden" name=cart_1_ID_Add2" id="cart_1_ID_Add2" value=""/>
var x = document.getElementsByClassName("input1")[0];
Again: I strongly recommend you to find time to change the logic of your program to use unique id's.
If they are in different forms you can target them by selecting IDs where they are inside a certain class. You can also change the name attribute and select that instead.
HTML
<div class="form1">
<input type="hidden" name="rename1" id="cart_1_ID_Add2" value="">
</div>
<div class="form2">
<input type="hidden" name="rename2" id="cart_1_ID_Add2" value="">
</div>
JS
$(".form1 #cart_1_id_add2")
//Or
$("input[name*='rename1']")
However you shouldn't really have the same id twice on one page otherwise it makes it hard to maintain and debug. If it's not a huge job to change your approach I'd recommend you do that.
Add another attribute to one or both tags.
For example, you can make them
<input type="hidden"name="cart_1_ID_Add2" id="cart_1_ID_Add2" data-id="add100" class="myInput" value=""/>
<input type="hidden" name=cart_1_ID_Add2" id="cart_1_ID_Add2" data-id="add101" class="myInput" value=""/>
Then get their values with jQuery
var myInput = $('[data-id=add100]').val();
console.log(myInput);
OR use plain javascript by adding a class and getting the value
var myVal = document.getElementsByClassName("myInput")[0];
console.log(myVal.value);
Hope this helps
Yes.
That code shouldn't have duplicate id properties in Dom btw.
You can use a custom HTML element property:
<input type="hidden" name="cart_1_ID_Add2" id="cart_1_ID_Add2" value="" my-property="some_identifier"/>
<input type="hidden" name=cart_1_ID_Add2" id="cart_1_ID_Add2" value="" my-property="some_identifier2"/>

Is there a better way to "link" text inputs?

I want to have the input boxes linked so that when you type something in one, it shows up in the other (and vice versa). Here's a "codepen" that shows how I'm doing it currently.
http://codepen.io/anon/pen/yEAbk/
It's pretty simple, but I feel like there should be an easier way to accomplish this. There is also a problem with this method that I illustrated in the codepen. You'll notice the button that fills one of the boxes with a string. Even though the content has been changed, the "onchange" event doesn't run, and so the other input box is not updated.
Is there an easier way to do this that will fix the problems I've been having?
This is exactly the kind of problem databinding is meant to solve. There are lots of libraries out there, but the most popular currently is AngularJS (by google). http://angularjs.org/
See demo: http://jsfiddle.net/34ZCs/2/ both inputs are bound to variable yourName:
<div ng-app>
<div>
<input type="text" ng-model="yourName" placeholder="A">
<input type="text" ng-model="yourName" placeholder="B">
</div>
</div>
Use "onkeyup" instead of "onchange". Then the next textbox will be updated instantly.
Do something like this
<input type="text" name="a" id="a" onkeyup="fillBoth('a','b')" onfocus="fillBoth('a','b')" />
<input type="text" name="b" id="b" onkeyup="fillBoth('b','a')"
onfocus="fillBoth('a','b')"/>
<button type="button" id="clicky" onclick="fillWithX()">click here for xxx</button>
And you JavaScript should be updated like this.
function fillWithX() {
document.getElementById('a').value = 'xxx';
document.getElementById('a').focus();
}
Slight change in your event handler might do the trick. Take a look: http://codepen.io/anon/pen/budnp/
<input type="text" name="a" id="a" onchange="fillBoth('b', 'a');" />
<input type="text" name="b" id="b" onchange="fillBoth('a', 'b');" />
<button type="button" id="clicky" onclick="fillWithX()">click here for xxx</button>
and the script:
function fillBoth(copyTo, copyFrom) {
document.getElementById(copyTo).value = document.getElementById(copyFrom).value;
}

Can I make the <span> looks like a read-only and fixed size 's <input type="text" > using css or javascript?

I have a <span> which encloses a very long message
<span>A very long message..........</span>
Can I make the span 's behavior look like a read-only and fixed sized <input type="text"> using CSS or java script ? I want the displayed message will has the fixed length displayed and user can scroll to see the whole message if the message is so long, just like the input control of the following code:
<input type="text" value="A very long message.........." readonly="readonly" size="40" >
Something like this?
<div style="height:200px;overflow:auto;">text</div>
Tadaa!
<input type="text" value="A very long message.........." readonly="readonly" size="40" >

In javascript how do I refer to this.form.checkbox[5].checked?

I have a series of checkboxes and input type="text" areas, wherein I need to have the state of the checkbox set to true when the value in the text area changes. Simple enough. I've done this successfully:
<input name="fixed" type="checkbox">
<input name="stuff" type="text" onchange="this.form.fixed.checked=true">
Which works fine. You have to edit the field then click out of it, but that is fine for my needs:
...but when I switch to this:
<input name="fixed[0]" type="checkbox">
<input name="stuff" type="text" onchange="this.form.fixed[0].checked=true">
<input name="fixed[1]" type="checkbox">
<input name="stuff" type="text" onchange="this.form.fixed[1].checked=true">
I get no change to my checkboxes when I edit:
My only javascript know-how comes from googling this sort of thing, I'm afraid. Anyone have any better info on this than the Oracle of Google on The Mountain has in store?
thanks...
Switch from dot notation to bracket notation!
this.form['fixed[0]'].checked
It might be that you're mixing some shady practices in HTML, and when you do it in javascript, they're breaking.
So this.form.fixed[1] in javascript really says "The second item in the array this.form.fixed. So I think that's the problem. try naming your elements fixed0 and fixed1 and see if that works.
Edit: You could also use bracket notation, as illustrated by Peter, which should solve the problem without editing the names of the inputs.
Make life easier on yourself.
Create unique ID's for the elements you are trying to reference and refer to them from the elements to which you bind your events:
<input name="fixed[0]" type="checkbox" id="fixed_0">
<input name="stuff" type="text" onchange="document.getElementById('fixed_0').checked=true">
<input name="fixed[1]" type="checkbox" id="fixed_1">
<input name="stuff" type="text" onchange="document.getElementById('fixed_1').checked=true">

Categories