views:

178

answers:

1

I have two tables Users and Expenses in the backend. UserId is a foreignKey for the Expenses table. I need to pass the UserId from the Usercontroller to the ExpenseController to save expense info against the user id. But there are two problems.

  1. I am unable to use the id parameter that is passed to the expense controller
  2. Another is for the create expense form, i could not find any userId field in the the form against which i am going to save the expense. So there is always modelstate.isvalid == false.

Please look at the following code. Hope you can help me.

//UserController

public ActionResult Index()
{
    return View(db.Users.ToList());
}

// Inedx View(User)

<%= Html.ActionLink("Expenses", "Index", "Expense", new { id=item.Id}, null)%>

// ExpenseController

public ActionResult Index(int id)
{
    ViewData["id"] = id;
    return View(db.Expenses.Where(x => x.Users.Id == id).ToList());
}

// Index view(Expense)

<%= Html.ActionLink("Create New", "Create", new { id=ViewData["id"]})%>

// Expense Controller(Create)

    public ActionResult Create(int id)
    {
        //ViewData["id"] = id;
        return View();
    }

//Create View

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>

        <p>
            <label for="ExpenseTitle">ExpenseTitle:</label>
            <%= Html.TextBox("ExpenseTitle") %>
            <%= Html.ValidationMessage("ExpenseTitle", "*") %>
        </p>
        <p>
            <label for="ExpenseDescription">ExpenseDescription:</label>
            <%= Html.TextBox("ExpenseDescription") %>
            <%= Html.ValidationMessage("ExpenseDescription", "*") %>
        </p>
        <p>
            <label for="Date">Date:</label>
            <%= Html.TextBox("Date") %>
            <%= Html.ValidationMessage("Date", "*") %>
        </p>
        <p>
            <label for="Expense">Expense:</label>
            <%= Html.TextBox("Expense") %>
            <%= Html.ValidationMessage("Expense", "*") %>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

//Create Post

[AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(FormCollection collection)
    {
        var expense = new Expenses();
        try
        {
            TryUpdateModel(expense, new string[] {"UserId", "ExpenseTitle", "ExpenseDescription", "Date", "Expense" }, collection.ToValueProvider());

                if (ModelState.IsValid)
                {
                    db.AddToExpenses(expense);
                    db.SaveChanges();
                    return RedirectToAction("Index",int.Parse(collection["UserId"]));
                }
                else {
                    return View(expense);
                }


            }
            catch
            {
                return View(expense);
            }
        }
+4  A: 

I believe that the consensus right way to do this is to construct specific models for each view and populate that model with the data necessary for the view, including data that may be necessary for any actions that the view invokes. So, for instance, you'd have an expense model that your Create view would take, one of the things it would contain would be the associated user id for the expense. The Create action that handles the post would take an expense model, instead of a FormCollection, as it's parameter. In your Create View you would store the user id from the model in a hidden field so that it's value gets propagated back with the post.

[AcceptVerbs( HttpVerbs.Get )]
public ActionResult Create(int id)
{
    return View( new ExpenseModel { UserId = id } );
}

[AcceptVerbs( HttpVerbs.Post )]
public ActionResult Create( ExpenseModel expense )
{
  ...
}

View

... Inherits="System.Mvc.ViewPage<ExpenseModel>" %>

<% using (Html.BeginForm()) { %>

    <%= Html.Hidden( "UserId" ) %>

    ...
<% } %>
tvanfosson
Thanks for your answer
Mr. Flint
@ASP MVC -- you're welcome. Since you're new here, I'll just point out that the way the system works is you upvote answers you find helpful using the up/down arrows next to the vote count at the top of each answer (once you have enough points) and accept the question that best answers your question by using the checkmark just below the vote count. Welcome to the site.
tvanfosson