jessemiel
jessemiel

Reputation: 373

Problems with combined view and IEnumerable model in asp.Net MVC

I am trying to create a combined view of an Index Page (which has product list using IEnumerable) and with the Create Page (which has the add / save stuff) and i am getting errors with the lambda expressions.

Here's my code:

@model IEnumerable<OIS.Models.Category>

<table class="table">
<thead>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.category_name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.date_created)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.date_updated)
        </th>
        <th></th>
    </tr>
</thead>
<tbody>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.category_name)

            </td>
            <td>
                @Html.DisplayFor(modelItem => item.date_created)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.date_updated)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
                @Html.ActionLink("Details", "Details", new { id = item.ID }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.ID })
            </td>
        </tr>
    }
</tbody>
</table>

//For for Creating new Item
@using (Html.BeginForm()){
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>Category</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        //Im Gettig Error with this line  (model => model.category_name)
        @Html.LabelFor(model => model.category_name, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            //Im Gettig Error with this line (model => model.category_name)
            @Html.EditorFor(model => model.category_name, new { htmlAttributes = new { @class = "form-control" } })
            //Im Gettig Error with this line (model => model.category_name)
            @Html.ValidationMessageFor(model => model.category_name, "", new { @class = "text-danger" })
        </div>
    </div>

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

What shall I do? Edited: Here's my controller

namespace OIS.Controllers{
public class CategoryController : Controller
{
    private DbOnlineIS db = new DbOnlineIS();

    // GET: Category
    public ActionResult Index()
    {
        return View(db.Categories.ToList());
    }

    // Post: Category
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index([Bind(Include = "ID,category_name,date_created,date_updated")] Category category)
    {
        if (ModelState.IsValid)
        {
            category.date_created = DateTime.Now;
            category.date_updated = DateTime.Now;
            db.Categories.Add(category);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(category);
    }
  // GET: Category/Create

    public ActionResult Create()
    {
        return View();
    }

    // POST: Category/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ID,category_name,date_created,date_updated")] Category category)
    {
        if (ModelState.IsValid)
        {
            category.date_created = DateTime.Now;
            category.date_updated = DateTime.Now;
            db.Categories.Add(category);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(category);
    }

Upvotes: 0

Views: 2665

Answers (3)

adricadar
adricadar

Reputation: 10209

To make a combined view you have to do something like below.

Create a ViewModel that have 2 properties

public class CategoryViewModel {
    public IEnumerable<OIS.Models.Category> Categories { get; set; }
    public Category Category { get; set; }
}

After that you move, Create and List, from the View in 2 partial views. Let's say _CategoryCreatePartial.cshtml and _CategoryListPartial.cshtml.

Than the combined view become something like this, Index.cshtml

@model OIS.Models.CategoryViewModel

@Html.Partial("_CategoryListPartial", Model.Categories)

@Html.Partial("_CategoryCreatePartial", Model.Category)

Partial Views:

_CategoryListPartial.cshtml

@model IEnumerable<OIS.Models.Category>

<table class="table">
<thead>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.category_name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.date_created)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.date_updated)
        </th>
        <th></th>
    </tr>
</thead>
<tbody>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.category_name)

            </td>
            <td>
                @Html.DisplayFor(modelItem => item.date_created)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.date_updated)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
                @Html.ActionLink("Details", "Details", new { id = item.ID }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.ID })
            </td>
        </tr>
    }
</tbody>
</table>

_CategoryCreatePartial.cshtml

@model OIS.Models.Category

@using (Html.BeginForm("Create", "Category")){
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Category</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            //Im Gettig Error with this line  (model => model.category_name)
            @Html.LabelFor(model => model.category_name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                //Im Gettig Error with this line (model => model.category_name)
                @Html.EditorFor(model => model.category_name, new { htmlAttributes = new { @class = "form-control" } })
                //Im Gettig Error with this line (model => model.category_name)
                @Html.ValidationMessageFor(model => model.category_name, "", new { @class = "text-danger" })
            </div>
        </div>

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

Controller and Index action

public class CategoryController : Controller
{
    private DbOnlineIS db = new DbOnlineIS();

    public ActionResult Index() {
        var categoryViewModel = new CategoryViewModel();
        categoryViewModel.Categories = db.Categories.ToList();
        categoryViewModel.Category = new Category();
        return View(categoryViewModel); // list + create category
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Category category) // call this action to create category.
    {
        if (ModelState.IsValid)
        {
            category.date_created = DateTime.Now;
            category.date_updated = DateTime.Now;
            db.Categories.Add(category);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(category);
    }
}

Upvotes: 6

Praveen Paulose
Praveen Paulose

Reputation: 5771

You will need to create another ViewModel to cater to this requirement of showing a List as well as the Create screen.

public class CategoryViewModel
{
    public List<OIS.Models.Category> Categories {get;set;}
    public OIS.Models.Category Category {get;set;}
}

In your razor view set the model to this new ViewModel

@model CategoryViewModel

In your enumeration you now access the list from within this new ViewModel

@foreach (var item in Model.Categories)

For your create section access the category from within the ViewModel

@Html.LabelFor(model => model.Category.category_name, htmlAttributes: new { @class = "control-label col-md-2" })    

On the same lines you will need to refactor your View page.

In your controller you must currently passing a List. You will need to change that to pass your new CategoryViewModel

List<Category> categories = "your db call";
CategoryViewModel viewModel = new CategoryViewModel();
viewModel.Categories = categories;
viewModel.Category = new Category();
return View(viewModel);

Upvotes: 2

Franky
Franky

Reputation: 651

Your Problem is in the <thead>. You try to access properties from the Category Model:

@Html.DisplayNameFor(model => model.category_name)

But your Model is an IEnumerable and has no property category_name.

Upvotes: 0

Related Questions