IndexOutOfRange in while loop and route error - c#

I am using a while loop which gives me an indexoutofrange error. I do not understand why this code would give me this.
This is what I have in my view:
#{
int i = 1;
while(i < 6)
{
<li class="item" id="ti+#i"><img src="Content/images/items/#Model[i].image_name" /></li>
i++;
}
}
Also, when I start the website I get a The resource cannot be found error. The website is pointed to start at Home/Index which is this view page.
Controller for that page:
DBController controller = new DBController();
public ActionResult Index()
{
List<items> items= controller.getItems();
return View(items);
}
I have no clue why this all doesnt work.

Loops in C# usually range from 0 to n-1, so be double-sure that starting at 1 is what you want.
Other than that, the error results probably from the fact that Model only contains 5 or less elements, so accessing Model[5] results in an error, as the elements in Model are indexed from 0 to (at most) 4.

Related

MVC Razor For loop binding to ViewModel problem

I am seeing a confusing issue with my viewmodel posting back to my controller and I am confused as of why it is not working. Though I have an idea as of why it may not be working which I explained near the bottom.
Basically I use a for loop to bind my model to HTML in the razor view
#for (int i = 0; i < Model.CheckBoxTag.Count; i++)
{
#if (Model.CheckBoxTag[i].TagTypeName == "test")
{
....
}
}
When I submit the form, the test CheckBoxTag objects are sent to my controller as expected.
However, when I do the same further down the html page only using the Escalation tags:-
#for (int i = 0; i < Model.CheckBoxTag.Count; i++)
{
#if (Model.CheckBoxTag[i].TagTypeName == "test1")
{
...
}
}
The test1 CheckBoxTag objects are not sent back to the controller. (The count is still 3, whereas it should be 6)
The fact it's the same code I am unsure how to tackle it.
My theory: I believe it is not posting back to my controller because the test for loop are the 1st elements in the collection, therefore it always goes into the IF. Whereas the test1 objects are near the bottom of the collection so therefore the IF is skipped quite a few times in the loop.
Is that correct? If not, what could be the issue?
Thanks
As stated in the comments section, the indexers must be consecutive.
Therefore in the for loops I put
#for (int i = 0; i < Model.CheckBoxTag.Count; i++)
{
#if (Model.CheckBoxTag[i].TagTypeName == "test1")
{
// New!
<input type="hidden" name="CheckBoxTag.Index" value="#i" />
...
}
}
So now the indexers "[i]" are now being incremented on every loop

Testing a x=> value in a HiddenFor line in a C# .NET view?

I have a form in a view in a C# ASP.NET MVC project that due to a bug in an earlier js cropping module occasionally ends off having a minus 1 (-1) in the value of the 'CropY' field.
Rather than trying to debug the cropper I thought I could just check for the -1 and make it a zero in the view, here:
#model UI.Models.PVModel
...
#Html.HiddenFor(x => x.CropY)
However, I don't seem to be able to modify the HiddenFor to set a value or 0 depending on if the value is >-1 or not, say with
#Html.HiddenFor(x => (x.CropY < 0 ? 0 : x.CropY))
As this (and all other combos I tried) gives me an error ( 'Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.').
I tried altering the model value itself before the form on the view with
model.CropY = (model.CropY < 0 ? 0 : model.CropY)
But that doesn't alter the value in the HiddenFor form field (I'm a beginner to C# and .NET so forgive me if this is a fundamental error)
Next I tried altering the model itself to test for this
public int CropY
{
set { CropY = value; }
get { return (CropY < 0 ? 0 : CropY); }
}
But I can't get this to work (System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.'), even if it is a viable method and I confess I don't know the correct format here!
Any idea please? Thanks.
--- edit after discussions below, this is more of what has been tried ---
Thanks. Okay, So very similarly, I have a basic get;set; in my model:
public class ProductViewModel
{
public int CropY { get; set; }
Then in my controller, it's a post as it's x in y number of forms/pages that go one after another:
[HttpPost]
[Route("Edit")]
[ValidateAntiForgeryToken]
public ActionResult Edit(ProductViewModel model, string nav)
{
model.CropY = (model.CropY < 0 ? 0 : model.CropY)
...
return View(view, model);
}
Then in my view I have this:
#model edie.UI.Models.ProductViewModel
#{
ViewBag.Title = "Step 2/";
}
<form action="#Url.Action(null, "MyPages")" method="post" class="form" novalidate="novalidate">
#Html.AntiForgeryToken()
#Html.HiddenFor(x => x.CropY)
And the value, when I view the page, is still coming through as -1. If I set breakpoints and step the code and check I can see the line in the controller is being triggered and setting CropY to 0, and the view is returned. On the view itself I can see the Model.CropY is 0. But the HiddenFor(x => x.CropY) inserts -1!
I suppose I'm missing something...
I would personally avoid implementation of setters and getters in Model/ViewModel objects, of course, it can helps in special cases but let's keep it simple. So, first of all, i would create simple view model object like this:
public class IndexViewModel
{
public int CropY { get; set; }
}
I would move the business logic from the view to the controller. In perfect world it should be moved to some service (SOC). So my get method in the home controller would look like this:
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
var value = -2;
var viewModel = new IndexViewModel();
if(value < 0)
{
viewModel.CropY = 0;
}
else
{
viewModel.CropY = value;
}
return View(viewModel);
}
}
And the Index.cshtml:
#model WebApplication1.Models.Home.IndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.HiddenFor(x => x.CropY)
value = -2; it's a variable which stores value that you receives (I suppose) from some data source like repository.
After some help from #stephen-muecke I found an answer. The issue is with with the modelstate. See TextBoxFor displaying initial value, not the value updated from code and TextBoxFor displaying initial value, not the value updated from code
So two of the methods I tried above did actually work (in a way) - altering the get; set; to handle the negative value and adding a check and update of the value in the controller before I return the view.
In the view itself the Model.CropY contained the correct 0 value then but the #Html.HiddenFor(x => x.CropY) still had the bad -1 value, and so added it to the form.
So the helper HiddenFor helper gets its value from the ModelState value, and not the model I was trying to alter and edit on the view.
Confused? I still am, but adding this in my POST controller fixed it:
ModelState.Clear();
You can also do a ModelState.Remove("SomeText"), so I'm advised this might be a better option that clearing the entire modelstate.

Selected column in For Loop ASP.NET MVC3

I have a following function in a controller. It is called from index.cshtml. var relays works fine and I got the replays.count(). PRESETDETAILS has some columns from which I want to access specific columns in a loop (like I have mentioned in response.write).
Kindly tell me how I can get the specific columns in the for loop.
#region "Apply Preset Handlers"
public ActionResult btnApply_Click(int? id)
{
var relays = db.PRESETDETAILS.ToList().Where(t => (t.PRESETID).Equals(id));
for (int k = 0; k < relays.Count(); k++)
{
Response.Write(relays.Select(s => new relays{PRESETDETAILID = s.PRESETDETAILID }).ToString());
}
return View("Index");
}
#endregion
you need to loop through them, you're simply select the same things over and over...
var relays = db.PRESETDETAILS.Where(t => t.PRESETID == id).ToList();
foreach (var replay in replays)
{
Response.Write(string.Format("{0}", relay.ID));
}
NOW... looking at your code:
always use ToList() at the end of the query;
ToList() actually makes the call to the database, until then, it's just a promise
Don't use Response.Write in your Controller, send the data to the View instead
your code should be:
public ActionResult btnApply_Click(int? id)
{
var model = db.PRESETDETAILS.Where(t => t.PRESETID == id).ToList();
return View(model);
}
in your View you can loop through the records
#model List<YOUR_CLASS>
<ul>
#foreach(var replay in Model)
{
<li>#replay.ID</li>
}
</ul>
I can see that some MVC conventions are not yet in place with you, and I know it can be somewhat overwhelm from someone that comes from WebForms or a linear code approach, but why don't you take some time and check the FREE available course about ASP.MVC in the ASP.NET Website?
See the videos in the right side of this page: http://www.asp.net/mvc

ASP.Net MVC MVCPaging error trying to filter results while using pager

I installed MVCPaging from NuGet (https://github.com/martijnboland/MvcPaging)
I want to enable a search/filter on my recordset, as well as paging, so this is what I've come up with:
public ActionResult Index(string str, int? page)
{
int pageSize = page.HasValue ? page.Value - 1 : 0;
// Get initial recordset
var items = db.Customers.OrderByDescending(a => a.OfferCreatedOn).Include(a => a.Offers);
// check if searchstring has any value, and filter if so
if (!string.IsNullOrWhiteSpace(str))
{
items = items.Where(t => (t.CustomerName.ToLower().IndexOf(str.ToLower()) > -1)
|| (t.OfferReference.ToLower().IndexOf(str.ToLower()) > -1)
|| (t.EmailAddress.ToLower().IndexOf(str.ToLower()) > -1)
);
}
// Pass remaining list to the pager
//
// Error on the next line
//
items = items.OrderByDescending(a => a.OfferCreatedOn)
.ToPagedList(page ?? 0, pageSize);
return View(items);
}
However, I'm getting an error on the last line:
Cannot implicitly convert type 'MvcPaging.IPagedList<FGBS.Models.Customer>' to 'System.Linq.IQueryable<FGBS.Models.Customer>'. An explicit conversion exists (are you missing a cast?)
Can anyone see what I'm doing wrong please?
Thank you, Mark
You need to change the model in the view, as you do not get the IEnumerable, rather you get IPagedList, that, along with the customer list, exposes properties such as HasPreviousPage, PageNumber, PageCount etc..., which is what you use to implement the page navigation logic.
example:
#model PagedList.IPagedList<Customer>
#foreach (var item in Model)
{
#Html.DisplayForModel()
}
#if (Model.HasPreviousPage)
{
<li>#Html.ActionLink("<", null, new { page = Model.PageNumber - 1})</li>
}
Update
sorry, didn't understand the error at first sight.
the error there is that you define the items variable as a var, that means that it gets its type resolved at compile time, when it gets the first value. as you pass it a result of a query, it becomes of type IQueryable<FGBS.Models.Customer>, after that, you try to pass the result of ToPagedList, that is an IPagedList, and the runtime can not convert it implicitly, as you may get some data lost. try to use a different variable for that. or you could just:
return View(items.OrderByDescending(a => a.OfferCreatedOn).ToPagedList(page ?? 0, pageSize));

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 }))

Categories