invokeMember in nested div - c#

I'm using Windows Forms Apps and webbrowser control and would like to make my code pick a certain value on a websites dropdown list. I have inspected the element on the website (see below):
<div class= "selectize-control">
<div class="selectize-dropdown">
<div class = "selectize-dropdown-content">
<div data-value ="1" data-selectable class ="option">Option1 </div>
<div data-value ="2" data-selectable class ="option"> Option2 </div>
<div data-value ="2" data-selectable class ="option"> Option3 </div>
</div>
</div>
</div>
<span style="display: none;" class= "ValidationMessage" id="ValidationMessage_1"></span>
I thought I could select "Option2" with writing the following code:
HtmlElementCollection theElementCollection = webBrowser1.Document.All;
foreach (HtmlElement curElement in theElementCollection) {
if (curElement.GetAttribute("className") == "selectize-dropdown-content") {
curElement.SetAttribute("value", "2");
}
}
But nothing happens... Could anyone help me out please?

The attribute is called class.
The Javascript property (that you can access directly as a property on the element) is clasName, but the attribute itself is class.

Related

XPath for an element with same class names

Can anyone help me to derive the xpath (from second div the span element label which is GP)
<div class="ohg-patient-banner-suppl-info-section ohg-patient-banner-suppl-info-custom pure-u-1-5">
<div class="ohg-patient-banner-suppl-info-component-container ohg-patient-banner-suppl-info-component-left-bordered ohg-patient-banner-suppl-info-custom" aria-label="Visit Info" role="group"><div class="ohg-patient-banner-suppl-info-section-summary" aria-hidden="false">
</div>
<div class="ohg-patient-banner-suppl-info-section-detail" aria-label="" aria-hidden="true">
<div class="ohg-patient-banner-suppl-info-custom-field">
<span class=" " aria-hidden="true"></span>
<span class=" ohp-metadata-label">Location</span>
<span class="ohg-patient-banner-suppl-info-custom-row-value-icon " aria-hidden="true"></span>
<span class=" ohg-patient-banner-suppl-info-value">Tauranga Hospital - Assmt Plan Unit TAU - </span>
</div>
</div>
</div>
</div>
<div class="ohg-patient-banner-suppl-info-section ohg-patient-banner-suppl-info-custom pure-u-1-5">
<div class="ohg-patient-banner-suppl-info-component-container ohg-patient-banner-suppl-info-component-left-bordered ohg-patient-banner-suppl-info-custom" aria-label="GP Info" role="group"><div class="ohg-patient-banner-suppl-info-section-summary" aria-hidden="false">
</div>
<div class="ohg-patient-banner-suppl-info-section-detail" aria-label="" aria-hidden="true">
<div class="ohg-patient-banner-suppl-info-custom-field">
<span class=" " aria-hidden="true"></span>
<span class=" ohp-metadata-label">GP</span>
<span class="ohg-patient-banner-suppl-info-custom-row-value-icon " aria-hidden="true"></span>
<span class=" ohg-patient-banner-suppl-info-value">-</span>
</div>
</div>
</div>
</div>
My XPath which i wrote it work for the first div and it return the value Location :
.//*[#class='ohg-patient-banner-suppl-info-section-detail']/div[#class='ohg-patient-banner-suppl-info-custom-field']/span[#class=' ohp-metadata-label']
Xpath:
//*[#class='ohg-patient-banner-suppl-info-custom-field']//span[2]
then you can use gettext() to get GP as a text
Try this XPath-1.0 expression:
//*[#class='ohg-patient-banner-suppl-info-section-detail']/div[#class='ohg-patient-banner-suppl-info-custom-field' and span[#class=' ohg-patient-banner-suppl-info-value']='-']/span[#class=' ohp-metadata-label']
Its result is:
GP
programmatic solution:
your xpath actually does return both elements:
in your selenium lib you receive most likely an array and can select the second element of it
select the second element:
if its always the second element adding a [2] to the xpath helps
e.g. "(.//*[#class='ohg-patient-banner-suppl-info-section-detail'])[2]/div[#class='ohg-patient-banner-suppl-info-custom-field']/span[#class=' ohp-metadata-label']"
by a fixed text
If you have some text in the page that is fixed, e.g. Location you can use that as reference and then using ancestor and sibling axes
".//span[.='Location']//ancestor::div[#class='ohg-patient-banner-suppl-info-section-detail']//following-sibling::div[#class='ohg-patient-banner-suppl-info-section-detail']//span[#class=' ohp-metadata-label']"
Since you don't have other unique identifiers, and the class name is used by 2 spans, this is how you can identify that span based on its index, and is the shortest way:
xpath: (//span[#class=' ohp-metadata-label'])[2]
Now you can scrape the text by using selenium getText() method.
Note that we used index 2 to identify your locator, but if html code will change, and new similar spans will be added before this one, you will need to change the index.

jQuery .show() method not working inside .click function

Below is code that is supposed to make a text box appear/disappear based on whether or not a box is checked (the text box is hidden when the page loads). All the alerts are firing properly, however I cannot get the check box to .show() function to work.
Here is the jQuery. This from inside the document.ready function. You can see from what I've commented out the other two methods I've tried (neither worked).
$('#OverrideRegionInd').click(function () {
alert($(this).is(':checked'));
if ($(this).is(':checked')) {
alert("inside if");
$('#Region').show();
//$('#Region').css("display", "inline");
// $('#Region').toggle();
$('#territoryName').html("");
$('#Region').val("");
} else {
alert("inside else");
$('#Region').hide();
//$('#Region').css("display", "none");
// $('#Region').toggle();
}
});
Here is the code from the view
<div class="M-editor-label">
#Html.LabelFor(model => model.Region)
</div>
<div class="M-editor-field" id="territoryName">
#Html.TextBoxFor(model => model.Region, new { style = "display: none;" })
#Html.ValidationMessageFor(model => model.Region)
</div>
Here is the HTML once the page is rendered for this particular set of <div>'s
<div class="M-editor-label">
<label for="Region">Territory</label>
</div>
<div class="M-editor-field" id="territoryName">
<input id="Region" name="Region" style="display: none;" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Region" data-valmsg-replace="true"></span>
</div>
That's because you're setting:
$('#territoryName').html("");
That's the parent of #Region, you're effectively removing the #Region element with that line. Take that out and it'll work fine.
DEMO

Reading, grouping and sorting nodes in an html doc using agility pack

I'm trying to build a class that will read, group and sort an html document based on another web site.
I will display the things I have up to now. Here's a sample of how the web page is constructed (keep in mind that it is just "how" it is built, I've rewrote the whole thing):
<tr>
<td id="ab100_ab100_ab100_Main_Sub_Sub_objComponent" class="compContainer">
<table class="objDetails" style="position: relative; margin: auto;">
<tr>
<div class="smallSetup" style="margin-top: 10px;">
<b class="ft"><b></b></b>
<div id="ab100_ab100_ab100_Main_Sub_Sub_firstProp" class="row">
<div class="label">
First Name:</div>
<div class="value">
Albert Trebla</div>
</div>
<div id="ab100_ab100_ab100_Main_Sub_Sub_secondProp" class="row">
<div class="label" style="line-height:25px;">
Second Year:</div>
<div class="value">
<img src="/Setup/Images.ashx?size=medium&name=5&type=symbol" alt="5" align="absbottom" /><img src="/Setup/Images.ashx?size=medium&name=W&type=symbol" alt="Second" align="absbottom" />
</div>
<div id="ab100_ab100_ab100_Main_Sub_Sub_thirdProp" class="row" style="height:15px; position:relative;">
<div class="label" style="font-size:.7em;">
Classy Stuff:</div>
<div class="value">
7<br /><br /></div>
</div>
<div id="ab100_ab100_ab100_Main_Sub_Sub_fourthProp" class="row">
<div class="label">
Weather:</div>
<div class="value">
Cloudy — Might Rain</div>
</div>
<div id="ab100_ab100_ab100_Main_Sub_Sub_fifthProp" class="row">
<div class="label">
Front Text:</div>
<div class="value">
<div class="frontTextBox">Opened</div><div class="frontTextBox">The shop is opened when the bridges are lowered.</div></div>
</div>
<div id="ab100_ab100_ab100_Main_Sub_Sub_sixthProp" class="row">
<div class="label">
Flavor:</div>
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_FlavorText" class="value">
<div class="frontTextBox"><i>"This taste good!"</i></div></div>
</div>
And so on.
Now here's how I structured my code in my app:
HtmlWeb loader = new HtmlWeb();
HtmlDocument doc = loader.Load(stringUrl);
HtmlNode parentNode = doc.GetElementById(ab100_ab100_ab100_Main_Sub_Sub_objComponent);
HtmlNodeCollection allNodes = parentNode.SelectNodes(".//div[#class='row']");
And I have my collection of divs, but I'm unable to make the next step. The first thing to understand is that the layout of the html code up there will change, so sometimes the firstProp will not show and sometimes it's the sixth prop, and so on.
So I though to check if the node's attributes is "label":
foreach (HtmlNode htmlNode in allNodes)
{
if (htmlNode.Attributes["class"].Value == "label")
{
}
}
But I don't know how to check the value after since the next sibling is an empty div. And I don't know much how HtmlAgilityPack work, so I wonder if there is an easier way to get this.
Can anyone advise me on how to proceed, or if what I'm doing is wrong and how to correct it?
* EDIT *
I have changed the line:
HtmlNodeCollection allNodes = parentNode.SelectNodes(".//div[#class='row']");
so that now my collection is narrowed only to the div I would get. But I still need to read when I get a div with class "label", read what value it is (ex: Front Text), and if that's Front Text, get the following div with class "value".
I suggest you learn a bit of XPATH which is supported by the Html Agility Pack, and allows for concise queries over the HTML DOM. For example, the following code:
HtmlDocument doc = new HtmlDocument();
doc.Load("test.htm");
HtmlNode node = doc.GetElementbyId("ab100_ab100_ab100_Main_Sub_Sub_objComponent");
foreach (HtmlNode row in node.SelectNodes(".//div[#class='row']"))
{
Console.Write(row.SelectSingleNode("div[#class='label']").InnerText.Trim());
Console.WriteLine(row.SelectSingleNode("div[#class='value']").InnerText.Trim());
}
Will output this:
First Name:Albert Trebla
Second Year:
Classy Stuff:7
Weather:Cloudy - Might Rain
Front Text:OpenedThe shop is opened when the bridges are lowered.
Flavor:"This taste good!"
if you need HTML inside the value or label div, then you can again issue XPATH queries from there.

C#/VB.net and click on javascript don't work

I have this :
<div id="comments-form-buttons">
<div class="btn" id="comments-form-send"><div>Enregistrer</div></div>
<div class="btn" id="comments-form-cancel" style="display: none;"><div>Annuler</div></div>
<div style="clear: both;"></div>
And i would to click on send button.
I have try this
submit.Document.GetElementById("jcomments-form-send").InvokeMember("click")
but it doesn't work.
Can you help me ?
Have a nice day.
You can use the CssClass to get the element(div) and access it in the JS! Remember this CssClass should be unique
#Oaybi, here in the JS u are using the samething i Said in last answer.
U are using a Class ('myDivClass') in the JavaScript to get the elemente getElementsByClassName!
webBrowser1.Navigate("javascript: document.getElementsByClassName('myDivClass')[0].click();void(0);"); //assuming it's first and/or only div with that class
<div id="comments-form-buttons">
<div class="btn" id="comments-form-send"><div>Enregistrer</div></div>
<div class="btn" id="comments-form-cancel" style="display: none;"><div>Annuler</div></div>
<div style="clear: both;"></div>
Do that in your code:
CODE:
//should be the uniq this class name in this case!!
Enregistrer
Annuler
JAVA SCRIPT:
webBrowser1.Navigate("javascript: document.getElementsByClassName('_MyDiv_Test1')[0].click();void(0);");
In this case, u get the DIV BY THE CSS CLASS. Just like i said last answer.
try this and tell me if it worked.
<div id="comments-form-buttons">
<div class="BTN" id="comments-form-send"><div>Enregistrer</div></div>
<div class="btn" id="comments-form-cancel" style="display: none;"><div>Annuler</div></div>
<div style="clear: both;"></div>
$(document).ready(function() {
$(".BTN").click(function(e) { // do some thing here });
});
</script>
I have found this
webBrowser1.Navigate("javascript: document.getElementsByClassName('myDivClass')[0].click();void(0);"); //assuming it's first and/or only div with that class
But i don't know javascript, somebody can translate for me please ?
My div :
<div id="comments-form-buttons">
<div class="btn" id="comments-form-send"><div>Enregistrer</div></div>
<div class="btn" id="comments-form-cancel" style="display: none;"><div>Annuler</div></div>
<div style="clear: both;"></div>
Thank you and have a nice day.

Dynamically Add Elements to jQuery Sortable

This should be my last question on Jquery Sortable...for a while :)
I have a list that I'm able to remove elements from dynamically. when users click the X close box on the element, I get the parent (the element itself) and remove it:
function DeleteLink() {
var jItem = $(this).parent();
var LinkId = jItem[0].childNodes[1].innerText || jItem[0].childNodes[3].textContent;
var LinkTitle = jItem[0].childNodes[2].innerText || jItem[0].childNodes[5].textContent;
if (!confirm(String.format("Are you sure you want to delete link #{0}?\n\nTitle: {1}", LinkId, LinkTitle)))
return;
jItem.remove();
$.post("/Home/DeleteLink/" + LinkId);
showStatus("Link deleted...", 5000);
}
If you are interested, unordered list is created like this:
<ul id="sortable1" class="connectedSortable">
<% foreach (Link l in Model)
{
if (l.Visible == true)
{%>
<li class="photolistitem" style="min-height:50px;">
<div class="imagecontainer"><img src="/Content/images/link.jpg" style="float:left; padding-right:5px;" class="thumbnailimage" alt="" /></div>
<div id='<%=l.Id%>Id'><%=l.Id%></div>
<div id='<%=l.Id%>Description'><%=l.Title%></div>
<div id='<%=l.Id%>Description'><%=l.Description%></div>
<div id='<%=l.Id%>Description'><%=l.Url%></div>
<div class='deletethumbnail'>X</div>
</li>
<%}%>
<%}%>
</ul>
What I want to do is to have a form on the bottom of the page so that a user can add an element dynamically - They will only need to insert a description, a title, and a url (I will use another jquery plugin to validate the input).
I think the biggest challenge will be dynamically creating an object that can be appended to the list. Can anyone point me in the right direction for this?
jQuery
thisDependant = $('.DependantTemplate').clone();
$(thisDependant).removeClass("DependantTemplate");
$(thisDependant).addClass("Dependant" + dependantNum);
$('.DependantList').append(thisDependant);
HTML
<div class="DependantTemplate hidden">
<div style="float:left;" class="DependantNumber spacerRight10"></div>
<div style="float:left;" class="DependantFirstName spacerRight10"></div>
<div style="float:left;" class="DependantLastName spacerRight10"></div>
<div style="float:left;" class="DependantDateOfBirth spacerRight10"></div>
<div style="float:left;" class="DependantGender spacerRight10"></div>
<div style="float:left;" class="DependantType"></div>
<div class="clearFloats"></div>
</div>
<div class="DependantList"></div>
The above is what I use to do the same as you're looking for.

Categories