MVC with TextBoxFor having same id within loop - asp.net-mvc-4

I would like to have a table within a form, with an update button. Ideally each row would be a form, but that doesn't fit html spec.
my view looks like this
#model IEnumerable<DabTrial.Models.ManageFilesModel>
#foreach(var item in Model) {
<tr>
<td>
#Html.TextBoxFor(modelItem=>item.Name)
....
when I look at the markup, the inputs within each row for the same property have the same id
<input id="item_Name" type="text" value="ParentGuardianPMH.pdf" name="item.Name">
...
<input id="item_Name" type="text" value="ParentGuardianMMH.pdf" name="item.Name">
which is obviously invalid - how should I be doing this. Thank you

you need such thing
#for(int i=0; i< Model.Count(); i++)
{
#Html.TextBoxFor(item => item[i].Name)
}
read this post about model binding to a list
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

use a for loop, not a foreach, and you'll have distinct id.

Related

Laravel 8 - Show database results using for loop (not foreach)

Using Laravel 8: I need to display my data (images saved as image names in the db) in 8 columns on the blade page. So if I have a db row count of 18, I would equally distribute the 18 in 8 columns (+remainder if any but that is irrelevant to this q - so, 18 images/8 cols = 2 (+2 remainder)). I can do this using two for loops so:
#for ($col=1; $col<=8; $col++)
#for ($img=1; $img<=$image_percolumn; $img++)
<img src="images/{{$featuredbrands->brandLogo'}}">
#endfor
#endfor
$featuredbrands is being passed from the controller as an array:
class HomeController extends Controller{
public function index(){
$fbrands = brands::join('subscriptions', 'brands.id','=','subscriptions.brandID')
->where('subscriptions.packageID','=',2)
->get(['brands.id','brands.brandLogo','brands.logoLink']);
return view('home',[
'featuredbrands'=>$fbrands
]);
} // end function
} // end class
I am getting the following error for the <img src...> line in my blade page:
Property [brandLogo] does not exist on this collection instance.
To test if I'm passing the data correctly to the blade page, I have tried using foreach to display the images. With foreach, I get the output in one column (so I know that data passed from controller is not the issue).
What is the correct way to reference the image field using the for loop? If that indeed is the problem?
This seems to be much harder than it should be, I am sure I am missing something.
One option - convert your collection to an array, and simply reference elements by key. Something like this:
In your Controller method:
return view('home', [
'featuredbrands' => $fbrands->toArray()
]);
And in your view:
#for ($col = 0; $col <= 16; $col += 2)
<img src="images/{{ $featuredbrands[$col]->brandLogo }}">
<img src="images/{{ $featuredbrands[$col+1]->brandLogo }}">
#endfor
You could also try to do it more the Laravel way, by using the Collection chunk() method, though this also seems very clunky here. Maybe something like:
#foreach ($featuredbrands->chunk(8) as $row)
#foreach ($row->chunk(2) as $col)
#foreach ($col as $brand)
<img src="images/{{ $brand->brandLogo }}">
#endforeach
#endforeach
#endforeach

SelectList dropdown list showing multiple = "multiple" for current viewmodel

This kind of a bizarre issue and I can't figure out a solution how I want.
I'm using .net core 2.1. I have a orders view model like this:
public class OrdersFilterViewModel
{
[Display(Name = "Account Numbers:")]
public IEnumerable<SelectListItem> AccountNumbers { get; set; }
}
My viewmodel and SelectList in my orders controller is called like this:
var vm = new OrdersFilterViewModel
{
AccountNumbers = new SelectList(_context.Account.Where(m => m.UserID == userId), "AccountNumber", "AccountNumber", account)
};
return PartialView("_FilterOrders", vm);
The problem lies when trying to get a dropdown list in the view which looks like this:
<form asp-action="FilterOrders" asp-controller="Order" id="ordersFilterForm" method="post">
<div class="form-group">
<label asp-for="AccountNumbers" class="control-label"></label>
<select asp-for="AccountNumbers" class="form-control" asp-items="#Model.AccountNumbers">
</select>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-default" />
</div>
</form>
This somewhat works but gives me a textarea type display where multiple = "multiple" is always tacked on in the browser. I've discovered that if I add something like the following to my viewmodel:
public int? AccountId { get; set; }
Then change my view to:
<select asp-for="AccountId" class="form-control" asp-items="#Model.AccountNumbers">
I can then have my dropdown list. However, I don't need that property for anything as far as I know. I tried a million things so it's possible I made some other slight changes I'm forgetting to get that to work, but that's the gist of it.
Is there any way around adding that extra property? Or do I need it for something I'm not aware of? Or is there any way to set multiple = "false" or something to that effect so I can get my dropdown list with my original viewmodel and such?
I haven't dealt with the post back to the controller yet, so maybe that will reveal the gotchas. I'm basically trying to create a modal type query filter that doesn't really do much other than modify some parameters and send them back to my query to update it. Thanks.
Is there any way around adding that extra property? Or do I need it
for something I'm not aware of?
Yes, you need this extra property, because in your select there are many items, and the user will select one or multiple items, and on the server side you'll need to know what the user selected, this is the purpose of the select tag.
And the multiple = "multiple" depends on what you put in the asp-for in the case of asp-for="AccountId" it is a single int value, so it won't use multiple, is you have an array in the asp-for then it will use the multiple.
Here is a pretty detailed description about the select tag helper:
Select Tag Helper in ASP.NET Core MVC

I am facing an issue in retrieving all the list items using selenium webdriver

Problem : I have a list of items inside a div class msb-container.
.There are 162 items in the list .I want to click the 150th item from the list .There also a scroll bar through which we can go doen to other elemenst and select it
How the html looks like :
<div class="mCSB_container" style="position:relative; top:0;">
<ul id="ul-countries">
<li>
<input id="country-3" type="checkbox" name="c:3">
<label for="country-3">Afghanistan</label>
</li>
<li>
<input id="country-6" type="checkbox" name="c:6">
<label for="country-6">Albania</label>
</li>
---other countries
</li>
</ul>
</div>
How my code looks like :
IList<IWebElement> countryList = driver.FindElements(By.XPath("//*[#id='ul-countries']/li"));
for (int i = 0; i <= countryList.Count; i++)
{
string temp = countryList.ElementAt(i).Text;
if (countryList.ElementAt(i).Text == "Brazil")
{
//do something
}
}
I am getting a correct count of 162 countries but i think they are not filled correctly .As when I try to retrieve the text from even the 15th country it gives me empty result .It only fills the text for those list item which can be seen on the screen .Although when I inspect element I can see all the required data in list item through html but not through my code .I tried to put the sleep to but no luck .
Please provide your inputs to solve the above issue.
|
Kindest Regards
IList<IWebElement> countryList = driver.FindElements(By.XPath("//*[#id='ul-countries']/li"));
for (int i = 0; i <= countryList.Count; i++)
{
string temp = countryList.ElementAt(i).findElement(By.CSS("label")).getText();
if (temp.equals("Brazil"))
{
//do something
}
}

not able to generate different id of html radio button

#for(int i = 0; i < item.Options.Count ; i++)
{
<input id="RdOpt +#i" type="radio" value="#item.Options" name="StudAns" />#item.Options[i]
}
id="RdOpt +(#i+1)"
m not able to generate different id of radio button.i want to use htm control only.
can any one please help me with this syntax as i have search a lot on internet.
i want to generate different id of radio button like RdOpt1,RdOpt2..means till the loop
m not geeting error but id is not generating
Try this;
<input id="RdOpt#(i+1)" type="radio" value="#item.Options" name="StudAns" />

How can I select checkboxes using the Selenium Java WebDriver?

How can I check the checkboxes using an id or XPath expression? Is there a method similar to select by visibletext for a dropdown?
Going through the examples given for all other related questions, I could not find a proper solution that works in a concise way that by few line or method I can check a chekbox or radio button.
A sample HTML section is below:
<tbody>
<tr>
<td>
<span class="120927">
<input id="ctl00_CM_ctl01_chkOptions_0" type="checkbox" name="ctl00$CM$ctl01$chkOptions$0"/>
<label for="ctl00_CM_ctl01_chkOptions_0">housingmoves</label>
</span>
</td>
</tr>
<tr>
<td>
<span class="120928">
<input id="ctl00_CM_ctl01_chkOptions_1" type="checkbox" name="ctl00$CM$ctl01$chkOptions$1"/>
<label for="ctl00_CM_ctl01_chkOptions_1">Seaside & Country Homes</label>
</span>
</td>
</tr>
</tbody>
Selecting a checkbox is similar to clicking a button.
driver.findElement(By.id("idOfTheElement")).click();
will do.
However, you can also see whether the checkbox is already checked. The following snippet checks whether the checkbox is selected or not. If it is not selected, then it selects.
if ( !driver.findElement(By.id("idOfTheElement")).isSelected() )
{
driver.findElement(By.id("idOfTheElement")).click();
}
It appears that the Internet Explorer driver does not interact with everything in the same way the other drivers do and checkboxes is one of those cases.
The trick with checkboxes is to send the Space key instead of using a click (only needed on Internet Explorer), like so in C#:
if (driver.Capabilities.BrowserName.Equals(“internet explorer"))
driver.findElement(By.id("idOfTheElement").SendKeys(Keys.Space);
else
driver.findElement(By.id("idOfTheElement").Click();
If you want to click on all checkboxes at once, a method like this will do:
private void ClickAllCheckboxes()
{
foreach (IWebElement e in driver.FindElements(By.xpath("//input[#type='checkbox']")))
{
if(!e.Selected)
e.Click();
}
}
Solution for C#
try
{
IWebElement TargetElement = driver.FindElement(By.XPath(xPathVal));
if (!TargetElement.Selected)
{
TargetElement.SendKeys(Keys.Space);
}
}
catch (Exception e)
{
}
You can use the following code:
List<WebElement> checkbox = driver.findElements(By.name("vehicle"));
((WebElement) checkbox.get(0)).click();
My HTML code was as follows:
<.input type="checkbox" name="vehicle" value="Bike">I have a bike<br/>
<.input type="checkbox" name="vehicle" value="Car">I have a car<br/>
To get the checkbox for 'Seaside & Country Homes', use this XPath:
//label[text()='Seaside & Country Homes']/preceding-sibling::input[#type='checkbox']
To get the checkbox for 'housingmoves', use this XPath:
//label[text()='housingmoves']/preceding-sibling::input[#type='checkbox']
The principle here is to get the label with the text you want, then get the checkbox that is before the label, since that seems to be how your HTML is laid out.
To get all checkboxes, you would start a little higher up and then work down, so that is to say get the table, and then get any checkbox within a span:
//table/descendant::span/input[#type='checkbox']
I found that sometimes JavaScript doesn't allow me to click the checkbox because was working with the element by onchange event.
And that sentence helps me to allow the problem:
driver.findElement(By.xpath(".//*[#id='theID']")).sendKeys(Keys.SPACE);
This should help -
IWebElement elementToClick = driver.findElement(By.xpath(""//input[contains(#id, 'lstCategory_0')]"));
elementToClick.Click();
You can also pass an id.
If you want something like visible text you can "find element" by name if they have names.
The below code will first get all the checkboxes present on the page, and then deselect all the checked boxes.
List<WebElement> allCheckbox = driver.findElements(By
.xpath("//input[#type='checkbox']"));
for (WebElement ele : allCheckbox) {
if (ele.isSelected()) {
ele.click();
}
}
A solution using WebDriver and C# is below. The key idea is to get the ID of the checkbox from the labels' 'for' attribute, and use that to identify the checkbox.
The code will also set the checkbox state only if it needs to be changed.
public void SetCheckboxStatus(string value, bool toCheck)
{
// Get the label containing the checkbox state
IWebElement labelElement = this.Driver.FindElement(By.XPath(string.Format("//label[.='{0}']",value)));
string checkboxId = labelElement.GetAttribute("for");
IWebElement checkbox = this.Driver.FindElement(By.Id(checkboxId));
if (toCheck != checkbox.Selected)
{
checkbox.Click();
}
}
Maybe a good starting point:
isChecked = driver.findElement((By.id("idOftheElement"))).getAttribute("name");
if(!isChecked.contains("chkOptions$1"))
{
driver.FindElement(By.Id("idOfTheElement")).Click();
}
Running this approach will in fact toggle the checkbox; .isSelected() in Java/Selenium 2 apparently always returns false (at least with the Java, Selenium, and Firefox versions I tested it with).
The selection of the proper checkbox isn't where the problem lies -- rather, it is in distinguishing correctly the initial state to needlessly avoid reclicking an already-checked box.
To select a checkbox, use the "WebElement" class.
To operate on a drop-down list, use the "Select" class.
Step 1:
The object locator supposed to be used here is XPath. So derive the XPath for those two checkboxes.
String housingmoves="//label[contains(text(),'housingmoves')]/preceding-sibling::input";
String season_country_homes="//label[contains(text(),'Seaside & Country Homes')]/preceding-sibling::input";
Step 2:
Perform a click on the checkboxes
driver.findElement(By.xpath(housingmoves)).click();
driver.findElement(By.xpath(season_country_homes)).click();
For a partial match, do the following:
getDriver().findElement(By.cssSelector("<tag name>[id*='id pattern to look for']")).click();
Here is the C# version of Scott Crowe's answer. I found that both IEDriver and ChromeDriver responded to sending a Key.Space instead of clicking on the checkbox.
if (((RemoteWebDriver)driver).Capabilities.BrowserName == "firefox")
{
// Firefox
driver.FindElement(By.Id("idOfTheElement")).Click();
}
else
{
// Chrome and Internet Explorer
driver.FindElement(By.Id("idOfTheElement")).SendKeys(Keys.Space);
}
I tried with various approaches, but nothing worked. I kept getting "Cannot click element" or ElementNotVisibleException.
I was able to find the input, but I couldn't check it. Now, I'm clicking on the div that contains the checkbox and it works with following HTML (CSS based on Bootstrap).
#foreach (var item in Model)
{
<tr>
<td>
<div id="#item.Id" class="checkbox">
<label><input type="checkbox" class="selectone" value="#item.Id"></label>
</div>
</td>
<td val="#item.Id">
#item.Detail
</td>
<td>
<div>#item.Desc
</div>
</td>
<td>
#Html.ActionLink("Edit", "Create", new { EditId = item.Id })
</td>
</tr>
}
This is the code for WebDriver:
var table = driver.FindElement(By.TagName("table"));
var tds = table.FindElements(By.TagName("td"));
var itemTds = tds.Where(t => t.Text == itemtocheck);
foreach (var td in itemTds)
{
var CheckBoxTd = tds[tds.IndexOf(td) - 1];
var val = td.GetAttribute("val");
CheckBoxTd.FindElement(By.Id(val)).Click();
}
In this approach, I give the item id as id for the div and also add an attribute for td with that id. Once I find the td of the item that needs to be checked, I can find the div before that td and click it. We can also use the XPath query that supports before (here is the example http://learn-automation.com/how-to-write-dynamic-xpath-in-selenium/).