Given the following html:
<ul id="search-results">
<li>
<h3>Result 1</h3>
<span class="some-info">Tag line</span>
</li>
<li>
<h3>Result 2</h3>
<span class="some-info">Another bit</span>
</li>
<li>
<h3>Result 2</h3>
<span class="some-info">Another bit</span>
</li>
</ul>
I can get the ul element with:
Element ul = ie.Element(Find.ById("search-results"));
How do I iterate over the children of the search-results?
I've managed to get as far as:
var allListItems = ie.Elements.Filter(e => e.Parent != null && e.Parent.Id == "search-results");
But this doesn't help me assert things about the H3 or span contained within the li's.
*Option1:*Based on your code, you can try something like:
ie.Spans.Filter(Find.ByClass("some-info"))[0...2].PreviousSibling;
you will need to loop over each span.
*Option2:*Based on some suggestions from the Watin mail list (similar to your own answer as well):
IElementContainer elem = (IElementContainer)ie.Element(Find.ById("search-results"));
Then you parse through elem.Element
Current best hack I can think of is:
public static class WatinExtensions
{
public static ElementCollection Children(this Element self)
{
return self.DomContainer.Elements.Filter(e => self.Equals(e.Parent));
}
}
ElementCollection results = ie.Element(Find.ById("search-results")).Children();
// and
foreach(Element li in results)
{
Element info = li.Children().First(e => e.ClassName.Contains("some-info"));
}
It works but surely there is a proper why to do this?
And there is a correct way to do this from the watin mailing list:
In my example:
var searchResults = (IElementContainer) ie.Element(Find.ById("search-results"));
foreach (Element element in searchResults.Elements) {
// can do more here
}
Related
Basic example link - following link is what I am trying to build. But this is only for single value.
Issue Detail After I select multi colors in <select>, Then i click <a> tag, I want to pass the value of what i select in <select>. Currently after clicking on <a> tag, it wont keep values selcted inside <select>
Step#1 Here I am creating Form with 2 filters. 1 search text box and 2 selectlist
<form asp-page="./index" method="get">
<input type="text" asp-for="SearchString" />
<select asp-for="Colors" asp-items="#Model.Colors_SELECT" class="MultiSelect" multiple>...</select>
...
</form>
Step#2 Display data in table grid. <a> is passing filters to url
<table>
....
<a asp-page="./My_Training"
asp-route-SearchString="#Model.SearchString"
asp-route-Colors="#Model.Colors"
asp-route-SortOrder="#Model.Colors_Sort">
#Html.DisplayNameFor(model => model.MyListData[0].Colors)
</a>
.. // more `<a>` tags. 1 for each column
</table>
Step#3 Back-end code: - mainly bind filter values
[BindProperty(SupportsGet = true)]
public string? SearchString { get; set; }
[BindProperty(SupportsGet = true)]
public List<string>? Colors { get; set; }
public SelectList? Colors_SELECT { get; set; }
public async Task OnGetAsync()
{
// everything is auto bind to properties
}
What I tried: according to google, they recommended using asp-all-route-data with Dictionary. I have tried this code and it doesnt work for multi values. Dictionary doesnt allow same key. for example: if I use asp-all-route-data and pass URL like Colors[0]=Red&Colors[1]=Green than it wont keep values selected inside <select>
I also Tried to do this. This works but the code is a mess and hard to maintain if you have too many filters & columns in data grid
<input type="hidden" asp-for="URL_String" />
...
<a href="/Index? #Model.URL_String&SortOrder=#Model.Colors_Sort">
#Html.DisplayNameFor(model => model.CourseTakenList[0].Colors)
</a>
public string? URL_String { get; set; } = "";
public async Task<IActionResult> OnPostAsync()
{
string? createURL = "?";
createURL += $"SearchString={SearchString}&";
foreach (var p in Colors)
{
createURL += $"Colors={p}&";
}
if (createURL.EndsWith("?") || createURL.EndsWith("&"))
{
createURL = createURL.TrimEnd(createURL[createURL.Length - 1]); //remove last '&'
}
string url = $"{HttpContext.Request.Path}{createURL}";
return Redirect(url);
}
public async Task OnGetAsync()
{
URL_String = Request.QueryString.ToString().Replace("??", "?");
CurrentSort = Request.Query["SortOrder"];
}
Because asp-all-route-data can't pass value with the same key, So you need to add index by yourself, Please refer to this simple demo:
#{
var colors = new Dictionary<string, string>();
var i = 0;
foreach (var item in Model.colors)
{
colors.Add($"colors[{i}]", item);
i++;
}
}
<a asp-page="index" asp-all-route-data="colors">Test</a>
It will pass data like:
?colors[0]=red&colors[1]=green&colors[2]=black
Demo:
=========================Update================
<select multiple id="selectone">
<option value="red">red</option>
<option value="black">black</option>
<option value="white">white</option>
<option value="yellow">yellow</option>
</select>
<button onclick="MySelect()">Select color</button>
<a asp-page="index" asp-route-SearchString="Test" id="color">Test</a>
<script>
function MySelect(){
var result = document.getElementById("selectone").selectedOptions;
var arr=[];
for(let i=0,len = result.length;i<len;i++){
if(result[i].selected){
arr.push("colors["+i+"]=" + result[i].value)
}
}
var str=arr.join("&");
var a = document.getElementById("color").getAttribute('href');
var url = a+ "&" + str;
document.getElementById("color").href = url;
}
</script>
Demo:
I have the following problem: I am making an MVC intranet website for the corporation I'm working for. One part of the job is to make a phonebook - I need a tree like structure of the departments (with depth).
I have a view with two div elements - left (containing the departments, the structure follows below), and a right div which should show all the employees that are working in the selected (clicked) department.
#helper GetTree(List<PhonesClasses.Department> department, int parentID){
foreach(var i in department.Where(a=>a.headDepartmentID.Equals(parentID)))
{
{var childDepartments = department.Where(a => a.headDepartmentID.Equals(i.departmentID)).Count();
if(childDepartments > 0)
{
<li class="haschlid" id="#i.departmentID">
#i.departmentName
<ul class="sub-dep">
#GetTree(department, #i.departmentID)
</ul>
</li>
}
else
{
<li id="#i.departmentID">
#i.departmentName
</li>
}
}
}
The following is the above-mentioned view. As you can see, I had the idea to make a partial view but I'm not sure I'm headed in the right direction.
<div class ="containerStructure">
<div class="leftDivStructure">
#if (Model != null && Model.Count() > 0)
{
<ul class="list" id="deplist">
#Treeview.GetTree(Model, Model.FirstOrDefault().headDepartmentID)
</ul>
}
</div>
<div class="rightDivStructure">
Employee
#*#Html.Partial("_PeopleInDepartment", new {depID = Model.departmentID()})*#
</div>
</div>
My employee and department classes both have DepartmentID fields, so when a department is clicked on in my tree view, a parameter () should be passed to the partial view, or whatever needs to be there to handle the parameter and show the employees. Below is the controller that I think has to fetch the result.
public ActionResult PeopleInDepartment(int depID)
{
List<Person> peopleList = new List<Person>();
peopleList = Persons.GetPersons(depID);
return View(peopleList);
}
For further clarifications please comment!
I'm trying to make a Price Range filter as you can see live here.
It's made in Umbraco 7.
I would like to hide a price range IF there is NO products in the range.
My code looks like this:
string selectedpriceRange = queryString.Get("priceRange");
<ul id="priceFilter" class="section sidebarList">
<li #(String.IsNullOrEmpty(selectedpriceRange) ? currentClass : "")>
All prices
</li>
#{ var priceRanges = new Dictionary<int, int>();
priceRanges.Add(0, 4999);
priceRanges.Add(5000, 9999);
priceRanges.Add(10000, 14999);
priceRanges.Add(15000, 24999);
priceRanges.Add(25000, 34999);
priceRanges.Add(35000, 44999);
priceRanges.Add(45000, 54999);
priceRanges.Add(55000, 95000);
}
#foreach (KeyValuePair<int, int> range in priceRanges)
{
<li>
<a href="#CurrentPage.Url#queryStringBuilder("priceRange", string.Format("{0}-{1}", range.Key, range.Value))">
#string.Format("{0} - {1}", range.Key, range.Value)
</a>
</li>
}
</ul>
I would like to think it's possible to add a .where or Count in the new Dictionary to see IF there is anything in that price range, but I'm not sure.
I am trying to achieve something like the following with MVC4 Razor Syntax. Here is the Code I am trying to write:
#{
int counter = 1;
#foreach (var item in Model)
{
#if (counter == 1)
{
<div class="section show">
}
else
{
<div class="section">
}
<span>#counter <text> .</text> #Html.DisplayFor(ab => item.Title)</span>
<div class="section-content">
#Html.DisplayFor(ab => item.Description)
</div>
</div>
counter++;
}
}
The above Code doesn't give any Compilation Error. But it causes Run time error. It says the Closing Tag is missing. Is it somehow possible to make the C# Code and HTML Code work together to achieve the result that I am trying to achieve here?
I am trying to get the C# Code and make them work based on Condition. For example, in the if Statement, if Counter is 1, the first div class will be selected and in rest of the times, the second div class will be selected.
Thanks. (I have updated the Question)
Don't use the if to create the div. Use it to determine the value of the class attribute:
#{
int counter = 1;
foreach (var item in Model)
{
result = "section";
if (counter == 1)
{
result = "section show";
}
<div class="#result">
<span>#counter <text> .</text> #Html.DisplayFor(ab => item.Title)</span>
<div class="section-content">
#Html.DisplayFor(ab => item.Description)
</div>
</div>
counter++;
}
}
I have a situation I'm trying to handle. I am using webdriver, C#. when I tried using the CSSSelector it is just reading the parameter as a string. Kindly look into it.This is the HTML.
<div class="select2-container select2" id="s2id_UserRole" style="width: 100%;">
<a href="javascript:void(0)" class="select2-choice" tabindex="-1">
***<span class="select2-chosen" id="select2-chosen-7"> </span>***
<abbr class="select2-search-choice-close"></abbr>
<span class="select2-arrow" role="presentation">
<b role="presentation"></b></span></a><label for="s2id_autogen7" class="select2-offscreen"></label>
<input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-7" id="s2id_autogen7">
<div class="select2-drop select2-display-none select2-with-searchbox">
<div class="select2-search">
<label for="s2id_autogen7_search" class="select2-offscreen"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-7" id="s2id_autogen7_search" placeholder="">
</div>
<ul class="select2-results" role="listbox" id="select2-results-7"> </ul></div>
</div>
The element I'm trying to get the ID is a dropdown with this kind of ID: id="select2-chosen-7". The "select-chosen-" is static and numeric part is dynamic. After reading forums, all suggestion does not seem to have the answer. At the end this is the code I'm using which is still not working -
IWebElement DropDownPath = driver.FindElement(By.CssSelector("*[id^='select2-chosen-'][id*='select2-chosen-']"));
SelectElement DropDown = new SelectElement(DropDownPath);
DropDown.SelectByText(UserConstants.UserRoleText);
If it isn't a requirement to keep the ValuesAddX separated, you could have an array of arrays, and foreach over that:
public static string[][] ValuesAdd =
{
new [] { "a", "b", "c" },
new [] { "1", "2", "3" },
new [] { "x", "y", "z" },
};
public void NestedForeach()
{
// Note that count isn't required anymore as we're using
// ValuesAdd.Length as the count
NestedForeachRecursive(string.Empty, 0);
}
public void NestedForeachRecursive(string prefix, int depth)
{
foreach (var item in ValuesAdd[depth])
{
var nextDepth = depth + 1;
var nextPrefix = prefix + item;
if (nextDepth < ValuesAdd.Length)
NestedForeachRecursive(nextPrefix, nextDepth);
else
Console.WriteLine(nextPrefix);
}
}
Note that because you're iterating over every item for every other item, the performance of this will scale very poorly.
The output of this example is:
a1x
a1y
a1z
a2x
a2y
a2z
a3x
a3y
a3z
b1x
b1y
b1z
b2x
... and so on
You should use recursion:
public void ConutNumber(int count)
{
...
GoThroughElements(count);
...
}
public void GoThroughElements(int count, List<String> recurseValues = new List<String>())
{
foreach(String value in ValuesAdd1)
{
recurseValues.Add(value);
if(count == 1)
{
// In deepest recursion iterate through the line of values
foreach(String i in recurseValues)
Console.WriteLine(i);
}
else if(count > 1)
{
GoThroughElements(--count, recurseValues);
}
else
{
throw new Exception("Wrong count!");
}
}
}
Don't forget to check your count for invalid values. Use recursion with great care, it may easily cause memory issues if a wrong case goes unnoticed.