0

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...

Ralpharama
  • 441
  • 4
  • 20
  • You cannot use a calculation in an expression. Where are your using `model.CropY = (model.CropY < 0 ? 0 : model.CropY)`? If its in the GET method it will work fine. –  Feb 14 '18 at 11:08
  • @mjwills ah yes: System.InvalidOperationException: 'Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.' – Ralpharama Feb 14 '18 at 11:12
  • @stephen-muecke in the model, I tried putting it in the set method but I guess I don't know the correct format/syntax to get the get and set working with that test in there! Hang on, in the get...? I was trying to alter it in the set? – Ralpharama Feb 14 '18 at 11:14
  • You need to give us a bit more info that that. Show you GET method. Using `model.CropY = (model.CropY < 0 ? 0 : model.CropY)` will work fine assuming your have not added a value for `CropY` to `ModelState` –  Feb 14 '18 at 11:17
  • @stephen-muecke. Thanks. Edited to put in what I tried in the model and the error I got. – Ralpharama Feb 14 '18 at 11:20
  • @stephen-muecke also, the model.CropY = (model.CropY < 0 ? 0 : model.CropY); was tried in the view, on the same page as the form, at the top of the page under the model declaration. – Ralpharama Feb 14 '18 at 11:22
  • You cannot use the property you have shown in the last snippet (unless you use a backing field in the geter/setter). But I meant to show the code in your GET method –  Feb 14 '18 at 11:24
  • @stephen-muecke I'm sorry, I'm not sure what GET method you mean? I tried the `model.CropY = (model.CropY < 0 ? 0 : model.CropY)` on the MyPage.cshtm right before the form where the HiddenFor form field appears. – Ralpharama Feb 14 '18 at 11:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165139/discussion-between-stephen-muecke-and-ralpharama). –  Feb 14 '18 at 11:30

2 Answers2

0

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.

0

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.

Ralpharama
  • 441
  • 4
  • 20