Scraping cascade selects' text with selenium/c# - c#

This is my first post on stackoverflow, even though i've been lurking in the shadows for past 10 years. :D
So, I have a task to scrape data off of a site which contains 3 cascade select lists / dropdowns, call it what ever you like. As I've played around selenium, I thought of giving a try with it. BUT I keep getting this :
"OpenQA.Selenium.StaleElementReferenceException"
I get the gist of it:
1) I declare a first list "Makes" of IWebElements which load up with all elements from first dropdown. => **works fine**
2) Then I iterate through the list using foreach, something like
foreach (var make in makes)
{
make.click() // step 3
... // step 4
}
3.As seen above I click on the first element so it can fetch data for another dropdown
4.I point to another list "Models" and repeat the process for iterating the second list and console.writeline it's content.
So it gives me first element from the first list "makes", all of members from the second list "Models", as it is supposed to. But as soon as it proceeds to another member of the first list (first foreach), it says that Make is stale "OpenQA.Selenium.StaleElementReferenceException"
Cheers!

Related

Get first item matching condition in large SharePoint list

So I have a SP list with about 100k items (voucher codes) in it.
Each of them has columns for State (Active/Used), Value (10,20,30) Group (Normal, Special) and Code (random alphanumeric). Each of the columns are indexed
I can't use CAML to get the next active code for a certain group and value, because each of the criteria would return > 5k items (list view threshold).
So what would be the most efficient way to retrieve the next code?
As the list is continuously growing, loading all items with SPListItemCollectionPosition is not really an option. Isn't there a better way?
It should work for onprem, as well as spOnline
Thank you
If your Code is a progressive number, increasing at any new entered item, you have 2 options:
Create a service List that you can name something like CodeCounter, here you store the last created Code in a column. Create a workflow in main list, starting at item creation. This workflow will read the last created Code from service list, then update it to Code+1 and in parallel manages the update (optional) of main code in main list
use an event handler (farm solution, here the query surely works better)

Duplicate Values in DropDown C#

In a dropdown I've got a list of country of this type:
Text: "Italy" Value :"IT"
I need a copy of one of the country in the top of the list referred to the current language of the portal I'm working in, so the user can both select the first or the one into the list. Is just a hint we can say.
So I've just added a copy in this way:
cmbNazione.Items.Insert(0, cmbNazione.Items.FindByText(valori.Rows[0]["M_SOAAuthorityCountry"].ToString().ToUpper()));}
This code works fine. I got my duplicate value and I can select it without problem.
I am stuck when I already have a country that I have to set into the dropDown.
I just wrote that:
cmbNazione.Items.Insert(0, cmbNazione.Items.FindByText(valori.Rows[0]["M_SOAAuthorityCountry"].ToString().ToUpper()));
cmbNazione.ClearSelection();
cmbNazione.Items.FindByText(valori.Rows[0]["M_SOAAuthorityCountry"].ToString().ToUpper()).Selected = true;
The problem is that I receive the error: Cannot have multiple items selected in a DropDownList.
In fact if I check I got both the list Items (first, and the identical in the list) with the prop : selected = true. If I try to make one false both change to false. I cannot use them separately.
I can't understand why I can use them correctly when I select manually, as a user, but not when I try to select them through code.
I also tried something like :
cmbNazione.SelectedIndex = cmbNazione.Items.IndexOf(cmbNazione.Items.FindByText(valori.Rows[0]["M_SOAAuthorityCountry"].ToString().ToUpper()));
But nothing. I'll every time have multiple items in the list of the selected
You should not have a duplicate value as it will confuse the user (if the value is on 2-3 position already) and architecture as retrieval may lead to 2 values being selected.
Your use case seem like you are offering the most commonly used value as the first one and then the remaining. If this is the case, follow the approach outlined below.
Find the ListItem required, then remove it from the list and add on the 1st position. Then mark it as selected.
var preferredItem = cmbNazione.Items.FindByText(...);
if (preferredItem != null) {
cmbNazione.Items.Remove(preferredItem);
cmbNazione.Items.Insert(0, preferredItem);
cmbNazione.SelectedItemIndex = 0;
}
This way, there will be single item being selected and preserve the sanctity of the item (underlying value etc) while still allowing user to have the preferred one on top of list. You can chose to have this as 'pre-selected' or let user select it explictly.

Article/news ordering by order id

I m having a little trouble coming up with a schema to order and changing order in a article/news management system.
Here goes:
I have News Object Model as follow:
class News {
int id;
string Title;
string Content;
string OrderId;
// trimmed
}
I have CRUD for the object model. and List as follows:
Id Title Order
1. Foo -+
2. Bar -+
3. Glah -+
What i want to do is when user clicks on - for first news, i want to replace 1 and 2 orderid and of course display as well.
well how do i do this on server side? lets say for 1. item order id is 1 , how do i find the first item that has a higher order id then this one?
Or take 2. Bar, when i click on - , how do i find/replace order ids with first one. or i click on + how do i replace order id of this news with 3. Glah ?
is there a better way of doing this?
There are also some UI where user drags and drops ? any pointers on that?
When the user changes the location of an item, the server needs to know which item was changed and what it's new position is. In the code below, I'm using a List to figure out the new positons. In this sample code, newPosition is the new zero-based position and selectedArticle is the article that was moved.
List<Article> articles = LoadSortedArticles()
articles.Remove(selectedArticle);
articles.Insert(newPosition, selectedArticle);
UpdateArticles(articles);
After running, the article's index within the list tells you its new position. That applies to all articles in the list and works the same for a drag/drop UI. I don't know entity framework, but if you can map the orderId field in the database to the index of the article in the list, then you should be good to go.
I hope this is at least able to give you some ideas. Maybe someone else can give a solution specific to entity framework, but I think putting the articles into a sorted list and letting the list do the work might be the easiest way.
I think the best approach here would be to implement a Swap method that takes two News objects and swaps their OrderId, which I am assuming is numeric.
So the idea would be that you would pass this method the object that was clicked on, as well as either the one above (if the user clicked +) or the one below (if they clicked -). If you do it this way then you avoid the task of trying to find the next or previous item.
In the case of drag and drop, the task is a little different. You would first need to retrieve all the items between (and including) the item being dragged and the drop target, ordered by OrderId. From there you swap the dragged item with the next or previous item (depending on direction), and continue doing so until you have swapped it with the drop target.

Disregarding updates on non-checked-in entries in a sharepoint list (SPAudit)

Okay, this is a little hard to explain, as the title might suggest.
I have an event receiver on ItemUpdated and ItemCheckedIn, which both writes custom SPAuditEntries. When CheckedIn occurs though - it comes with two update entries as well (one for added file, and one for a simple update to the list item I suspect).
I'd love to get rid of these entries. At first I thought it would be really simple, just put an if in the itemUpdated event receiver, and stop everything
if(SPListItem.CheckedOut = false) { //... do nothing }
However I couldn't find any way to ascertain the checkout-status of the listitem.
My next thinking was, they hit almost at exactly the same time, so I could just crawl into the auditCollection, filter down to the specific listitem, user, and time (minus a second) and delete the two entries. But, sadly I found out I couldn't delete auditentries.
Anyone got any ideas?
Checked out status is determined via:
if (item.Level == SPFileLevel.Checkout) {
where item is an SPListItem
-Oisin

SharePoint ItemAdded Event Delay

Yet another question.
So now my EventReceiver and its logic is working just fine. Except for one thing.
Basically it queries the whole list through CAML queries, and then passes the result to a DataTable object, and later on to a DataRow object...
Like all, in test environment, it works perfectly, but in production...
What happens is that the column I need updated gets update but not shown immediately. The item column receives the value I want, but it doesn't show at first refresh, you have to refresh the page again, then it appears...
The only difference is that in teste env. my list has like, 200 records, and in production, it has almost 5000 records.
Some questions:
Is there a way to define how many records you want? In CAML or in the DataTable object? Something like "SELECT TOP 100 ... "
If not, is there a way to make the refresh process stop and wait for the code execution?
Some Info:
It's WSS 3.0, and the event I'm intercepting is ItemAdded, which explains the refresh not waiting for my code.
Oh and considering changing to the ItemAdding event would be a little bit of a problem, because I need to capture the ID of the record, which is not yet available in ItemAdding because the list item has not been committed to the database yet.
Thanks in advance.
The problem here was the "GetDataTable()" method. When I ran the CAML query and filled a datatable with the results, it'd lose the order by modifier. But if I get the results with a SPListItemCollection object, it returns the row exactly how I wanted.
As seen in another post... "This is a nasty issue".
Similar question and answer here. You should be able to use the Rowlimit property of SPQuery.
After searching a lot, I ended up moving my code to the ItemAdding event, which is synchronous and will finish executing before SharePoint loads its page.
Even after I limited the result rows to 5, it would still load the page without the value I wanted to show.
Also, if you are considering capturing the value from a field that uses calculated value, and has a formula in it, be careful, because at least in my example, SharePoint didn't resolve the formula by event execution, so the field with the calculated value would always return null.

Categories