Loop list in jquery and use the looped values - c#

In my last question I was having problems looping through a list with jQuery. Then we figured this out and it worked perfectly:
public List<Sale> AllSales { get; set; }
for (var i = 0; i < <%= AllSales.Count %>; i++) {
}
I now need to use the values inside the loop so I thought it would be as simple as this :
for (var i = 0; i < <%= AllSales.Count %>; i++) {
var date = <%= AllSales[i].Date %>;
alert(date);
}
When I first tried this, it said "The name 'i' does not exist in the current context
", so I just put 0 instead of i instead of AllSales[0]. Then nothing happens.
What am I missing?

You have javascript loop which you want to iterate on server side list this is not possible. You can use ajax to send data to client side. This is a nice article for using jQuery ajax with csharp.
Assigning the values of your list separated with comma to some hidden field and accessing that hidden field in javascript could be a possible solution. But if you want to use more attributes of your list object then it would be very messy solution. Using ajax is best option.

Related

How to find multiple elements on a page in selenium?

I have multiple input HTML tags on same page having same id and name or class,
Now How should I find 2nd or 3rd.. etc input. I can work with arrays so Do we have some function which will return all the textBox(input tag) from that page.
First you create a list with FindElements, then you can iterate through that list. For example:
var allTextBoxes = driver.FindElements(By.TagName("input"));
foreach(var textBox in allTextBoxes)
{
textBox.DoSomething();
}
You can use a for-loop as well:
for(int i = 0; i < allTextBoxes.Count; i++)
{
allTextBoxes[i].DoSomething();
}
Or if you want a specific Element, in example the 3rd:
allTextBoxes[2].DoSomething();
Expanding on Anaxi's answer,
If you are using the PageObject framework you can do it like this and set the FindsBy attribute on a property:
[FindsBy(How = How.Id, Using = "YourId")]
public IList<IWebElement> ListOfWebElements { get; set; }
i dont know about selenium... but to select element of html page you can use HtmlAgilityPack..
HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(#"http://example.com");
HtmlNode node = doc.DocumentNode.SelectNodes("//div[#class='your_class_name']");
it will return a list of node that contains your_class_name.. then find and use the one you want.
to select all the input tags from that page you can use
foreach (var input in doc.DocumentNode.SelectNodes("//input"))
{
//your logic here
}
hope it helps..
In C# I use FindElements then ElementAt():
var foo= Driver.FindElements(By.XPath("//div[#class='your_class_name']"));
var foo2= foo.ElementAt(1);
If it's 10 elements with the same ID (which is HORRIBLE) and I'd like to grab the 8th element, I just use ElementAt(8); (or index 7 or however you're set up).
It's a tough call. I'd much rather have them fix the code but in some cases that's just not going to happen... at least not in the near future.
Hope this helps.

Using a foreach loop on LINQ query for searching

Hi I have a record called Tags in a table called Knowledgebase (KB) in my DB. The words in Tags are separated by commas. Also in the KB table is a field called Title.
I need to match the tags field to the Title so I have replaced all the commas in the tags with spaces like so string removeCommas = commas.Replace(",", " ");.
I think I now need to loop around every record in the KB table to find records? I would like to store the number of matches it finds in a variable called suggestions.
Question is what is the best way to implement the for each loop for a query like this? Is the for each loop the best method for this task?
One way is to store the space seperated strings in a List. Now, use Foreach loop for the whole table and in turn a foreach loop for each record to find the match of Title.
I will correct my answer if this is going the wrong direction, but would something like this complete the operation you are attempting?
System.Data.DataTable KB = new System.Data.DataTable();
string[] tags = "some,foo,bar".Split(',');
System.Collections.Generic.List<string> suggestions = new System.Collections.Generic.List<string>();
for (int i = 0; i < tags.Length; i++)
{
for (int j = 0; j < KB.Rows.Count; j++)
{
string row = KB.Rows[j]["Title"].ToString();
if ((row.Contains(tags[i]))
{
suggestions.Add(row);
}
}
}
Also, avoid foreach whenever humanly possible. Check out THIS post to see why.
Yes Linq can help you to retreive the data from your database and then replacing it after a foreach loop
Code Added
Let say you are using EDM and you have a context kb:
public void ReplaceCommaInTag(KbContext kb)
{
var tags = from t in kb.Titles
Select t.Tags;
foreach(Tag tag in tags)
{
tag = tag.Replace(","," ");
}
try
{
kb.SubmitChanges();
}
catch(Exception e)
{
//Display the error.
}
}
I hope it will help you

Saving a reordered List item from an MVC View Model

I have a view model which binds to a 'TreasureHuntDetails' object, which contains a list of clues. Here's part of the data model for it.
public TreasureHuntDetails()
{
Clues = new List<Clue>();
}
[Key]
public int TreasureHuntId { get; set; }
public List<Clue> Clues { get; set; }
On the page, I have a table. A foreach loop iterates through the list of clues to add them to the table, e.g.
#for (int i = 0; i < Model.Clues.Count; i++)
The table elements inside the for loop are quite large, but here's an example of one of the table element columns:
<td>#Html.DisplayFor(m => Model.Clues[i].Location)</td>
All well and good so far. Then I'm using JQuery UI to allow the items of the table to be reordered using drag and drop, like this:
<script type="text/javascript">
$(document).ready(function()
{
$("#clueTable tbody").sortable().disableSelection();
});
</script>
All well and good, I can drag and drop the elements.
The problem is that I don't know how to save the new order of elements and save them back to the database.
The first thing I tried was simply passing the list of clues to a controller method, but I found that once the list of clues reached the controller method, it was always null.
For example:
#Url.Action("ViewCluePage", #Model.Clues)
Even if I send the whole #Model, list of clues within is always null. Removing the new list instantiation from the constructor of the data model didn't solve this problem.
Another thing I tried was wrapping the whole table into a HTML form, but still the list of clues remains null.
So basically, this question is really two questions:
1) Why is the list of clues always null after sending the model object to a controller.
2) How to save the new order of the list of items?
UPDATE: As per suggestion by #recursive, I see where I made an error when trying to submit the clue elements to the HTML form.
I used this outside the for loop which iterated over the clue elements:
#Html.HiddenFor(m => m.Clues)
I had to add the HiddenFor lines inside of the for loop (for each clue item), and for EACH property of the clue item, e.g.
#Html.HiddenFor(m => m.Clues[i].Id)
So that would be one step forward to be able to get the list items sent to the controller, but I think I still need code that will reflect the new order of the clue items when sent to the controller. Currently, on rearranging the order of the elements on screen using the JQuery sortable() method, this doesn't change the order of the elements as they are stored in the data model binded to the view (#Model.Clues).
1) As #resursive said in his comment, you need to have hidden elements on the page that map to properties in your Clue class.
2) As for persisting the order of clues, you'll need to add a column to your database that holds the position of each clue in the list and add the position property to your class. So your class would need to include
public int Position {get;set;}
which should pull from the database when the page is created. Then just before rendering the page, you should reorder the clue list based on the Position variable.
Edit: Use jquery's sortable attribute. Check out this thread for reference. In the stop drag event (or right before your submit), loop through each of your draggable objects and set the value of each of the hidden Position properties of your objects.
var positionIndex = 0;
$('.draggableObjectClass).each(function () {
$(this).find('input[id$=_Position]').val(positionIndex++);
});
but I think I still need code that will reflect the new order of the clue items when sent to the controller.
You won't, as you are now iterating over them in a for loop, they will be indexed in the order that you sent them to the view. Your order must already be maintained.
Taking advice from the answers posted here already, I came up with the following solution.
With already having this method in place to implement the drag and drop reordering of the UI elements,
$(document).ready(function()
{
$("#clueTable tbody").sortable().disableSelection();
});
I needed a way to be able read the in the new order of items and send it to the MVC controller. To do this I used the Razor #Html.AttributeEncode method to write the Id's of each item to a column on each row of the table, like this:
<td class="Ids" id="#Html.AttributeEncode(Model.Clues[i].Id)">#{var number = i + 1; #number}</td>
(This is wrapped around a for loop which iterates through the list of items.)
Then, I created the following Javascript function, which is invoked from a 'SaveNewOrder' button I placed above my table of elements (the user presses this once they have finished reordering the items on the table):
function getNewOrder()
{
var positions = new Array();
for (var i = 0; i < $('.Ids').length; i++)
{
positions[i] = $('.Ids')[i].id;
}
$.ajax(
{
type: "POST",
url: "#Url.Action("ReorderClues", "Clues")",
data:{ treasureHuntDetails: $("form").serialize(), ids: JSON.stringify(positions) }
contentType:'application/json'
}).done(function()
{
window.location.href = '#Url.Action("Clues", Model)';
}).
}
What this is does is reads the Id elements from each of the table items, and writes them into the array - so this array contains the NEW order of Id's. The data model containing the items doesn't change after reordering the table elements, hence why this was necessary.
It then uses a JQuery Ajax method to invoke a 'ReOrderClues' method on my 'Clues' MVC controller, passing a serialised version of the data model (containing a list of the clue items in the original order) and an array containing a list of the clue Id's in the new order. When the result is returned from the controller (.done), I invoke a controller which refreshes the page elements.
So rather than having to maintain a position value associated with each clue (which would involve significant refactoring elsewhere in the code), what I'm doing is swapping the contents of the clues around to reflect the new order, but keeping the Id's in the same position.
This is how I achieved that using an MVC Controller:
public ActionResult ReorderClues(TreasureHuntDetails treasureHuntDetails, int[] ids)
{
using (var db = new TreasureHuntDB())
{
var clues = treasureHuntDetails.Clues;
var newClues = NewOrderList(clues, ids);
// Save the changes of each clue
for (var i = 0; i < newClues.Count;i++ )
{
db.Entry(clues[i]).CurrentValues.SetValues(newClues[i]);
db.SaveChanges();
}
treasureHuntDetails.Clues = newClues;
TempData["Success"] = "Clues reordered";
}
return RedirectToAction("Clues", treasureHuntDetails);
}
public List<Clue> NewOrderList(List<Clue> clues, int[] ids)
{
var newClueOrder = new List<Clue>();
// For each ID in the given order
for (var i = 0; i < ids.Length; i++)
{
// Get the original clue that matches the given ID
var clue = clues.First(clue1 => clue1.Id == ids[i]);
var newClue = Clue.Clone(clue);
// Add the clue to the new list.
newClueOrder.Add(newClue);
// Retain the ID of the clue
newClueOrder[i].Id = clues[newClueOrder.Count - 1].Id;
}
return newClueOrder;
}
In the above code snippet, TreasureHuntDB is my Entity Framework database context.

How do I display the number of loops in a foreach loop in an HTML page

I'm currently trying to count the number of search results returned in my ASP.NET MVC view to display how many results the search gave in return.
I've tried counting the number of loops of the foreach that displays the search results.
I've also tried counting the number of items in the Model object returned with the view:
<% Html.Display(Model.Count().ToString());%>
it never really posts anything on my site.
Anybody got an idea how to solve this issue?
The only way to know how many iterations a foreach loop has taken is to include a counter yourself:
int count = 0;
foreach (var thing in things) {
count++;
// Do something useful
}
// count is now the number of iterations
To display in a .aspx view then use:
<%= count %>
or in Razor:
#count
If this isn't working for you, then some other factor is at play. Can you show a short working example where it doesn't work?
Maybe
<span><% Model.Count() %></span>
#foreach (var item in Model.PageInfo.Products.Select((x, i) => new { Data = x, Index = i }))

Trying to create a WebService to return a 3D Array to populate table with javascript

I am trying to create a dynamic table that is being built based on the value of a search text box. The Table will have probably 6 columns of 20(max) rows.
My problem is I can't figure out how to return the data from the web-service to the JS function in a way that will allow me to extract the data that I need.
Here is the web-service method I have currently:
[WebMethod]
public v_EMU_AIR_AIR[] GetCompletionList(string prefixText)
{
NeoDataContext dataContext = new NeoDataContext();
var results = from a in dataContext.GetTable<v_EMU_AIR_AIR>()
where a.Report_Date_ID.StartsWith(prefixText) ||
a.Item_Description.Contains(prefixText) ||
a.Drw_Nbr.StartsWith(prefixText)
select a;
return results.ToArray<v_EMU_AIR_AIR>();
}
This will return an Array my objects, but in my javascript:
populateTable:function(returnList) {
var length = returnList.childNodes[0].childNodes.length
for(var i=0; i<length; i++) {
var textValue = returnList.childNodes[0].childNodes[i].textContent
$("<tr><td>" + textValue + "</td></tr>").insertAfter(this.tblResults[0].childNodes[1]);
}
}
All I can produce is a dump of the entire Object and can't pull out the specific fields that I need.
I would serialize your object using Javascript Object Notation (JSON).
Unfortunately, this feature isn't built in to the .NET framework, so you'll need to write the code yourself.
Fortunately, most of it is already done for you. Check out this link or this link for more information.
In your javascript, you can retreive the JSON object with jquery (documentation) and access the values of your properties like you would in C#
$(document).ready(function() {
$.getJSON("http://url.to.webservice.com/", function(jsonObj) {
alert(jsonObj.property);
});
});

Categories