3

I'm new to MVC and I'm struggling deeply with this behaviour:

When I want to save with the Edit method (POST) I make some validations and when an error occurs I call again the view and I send the same object. However in the view all the inner objects are null.

Here is an example:

public class Product 
{
  public int Id { get; set; }
  public string Name { get; set; }
  public DateTime ExpirationDate { get; set; }
  public int CategoryId { get; set; }
  public virtual Category Category { get; set; }
}

public class Category 
{
  public int CategoryId { get; set; }
  public string Name { get; set; }
}

My controller is this:

[HttpPost]
public ActionResult Edit(Product product, string submitButton)
{
  if(submitButton == "Save")
  {
    if (ModelState.IsValid)
    {
        db.Entry(product).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
  }
  else // Validate
  {
    if(product.Expiration <= DateTime.Now)
    {
      ViewBag.Message "Product is expired";
      return View(product); // In the view the object property 'Category' is null. Why?
    }
  }
}

Update. Here's the view.

@model sgt.Models.Product

@{
    ViewBag.Title = "Edit Product";
}

<h2>Edit</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Product</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
                <input type="submit" value="Validate" class="btn btn-default" />
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ExpirationDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ExpirationDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ExpirationDate, "", new { @class = "text-danger" })
                <input type="submit" value="Validate" class="btn btn-default" />
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DisplayFor(model => model.Category.Name, new { htmlAttributes = new { @class = "form-control" } })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Return", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Thanks in advance

6
  • You have if(product.Expiration <= DateTime.Now), but I don't see an Expiration property in your Product class. Commented Apr 4, 2015 at 0:34
  • What is the value of product.Category when the Edit action is invoked? Commented Apr 4, 2015 at 0:43
  • @J.Henderson product.Category in this case is null. Commented Apr 4, 2015 at 0:49
  • If product.Category is null upon entry of Edit, and no further changes are made, why would you expect it to not be null within the View? Commented Apr 4, 2015 at 0:51
  • @J.Henderson if product.Category is null then when I send it to the view then the category name is blank. Commented Apr 4, 2015 at 1:10

1 Answer 1

1

YOu have a logical Error in your code.

You are not returning the View if(ModelState.IsValid) Fails

[HttpPost]
public ActionResult Edit(Product product, string submitButton)
{
    if(submitButton == "Save")
    {
        if (ModelState.IsValid)
        {
            db.Entry(product).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        // Here RETURN VIEW and MODEL

        return View(product);
    }
    else // Validate
    {
        if(product.Expiration <= DateTime.Now)
        {
        ViewBag.Message "Product is expired";
        return View(product); // In the view the object property 'Category' is null. Why?
        }

        // ALSO HERE YOU ARE NOT RETURNING A VIEW AND MODEL

        return View(product);
    }
}

Just wondering, but I think you want to check if Model is Valid AND product.Expiration <= DateTime.Now

[HttpPost]
public ActionResult Edit(Product product, string submitButton)
{
      if(product.Expiration <= DateTime.Now && submitButton != "Save"){
         ModelState.AddModelError("Expiration", "Product is expired");
       }


       if (ModelState.IsValid)
       {
           db.Entry(product).State = EntityState.Modified;
           db.SaveChanges();
           return RedirectToAction("Index");
        }
        return View(product);
}

EDIT: TRY THIS:

   [HttpPost]
   public ActionResult Edit(Product product, string submitButton)
   {
    if(submitButton == "Save")
    {
            if (ModelState.IsValid)
            {
                db.Entry(product).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(product);
    }
       if(product.Expiration <= DateTime.Now)
       {
           ViewBag.Message "Product is expired";
       }
       return View(product);
   }

EDIT YOUR VIEW:

<div class="form-group">
    @Html.HiddenFor(m => m.Category.CategoryId)
    @Html.HiddenFor(m => m.Category.Name )

    @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DisplayFor(model => model.Category.Name, new { htmlAttributes = new { @class = "form-control" } })
    </div>
</div>      
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the response. I updated the code however my problem is not there; is when submitButton is not "Save" is when the expiration date is validated. The product.Category is null. That's my problem.
POST the Code of you View
Thanks for your response. ModelState.IsValid is false, that's ok, but when I return View(product) then Category is blank in my view.
How does your Category Object have value when you dont' Post it back from the view? If you add this line to your view it will work @Html.HiddenFor(model => model.Category.Name)
@nmiranda Check my Edit. MVC doesn't POST back data that is in DisplayFor stackoverflow.com/questions/12314849/…
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.