David Cruwys
David Cruwys

Reputation: 6842

MVC Razor - Create / Edit view best practice

I'm working with MVC 3 / Razor for the first time and it seems odd that all the examples and VS scaffolds for create and edit views all have separate HTML views for these concepts.

There is really not much difference between many Create/Edit forms so I was wondering why I can't find examples of people using a single Update form that can be used by both Create and Edit actions.

I have gotten an Update.cshtml view working but was wondering about how it talks to the Edit or Create action method on the controller.

My questions are:

  1. Anyone have a quick answer to talking to the controller, or
  2. Anyone know of a tutorial showing good practice for working this way, or
  3. Is there some good reason for keeping the Create/Edit views separate when the HTML is often the same.

Cheers Dave

Upvotes: 22

Views: 43637

Answers (5)

user1489673
user1489673

Reputation:

Be mindful that answers to your question should also be driven by business need (and roles). The scaffolding does provide separate functionality, which in some cases is the preferred implementation.

CREATE and EDIT functionality is often pretty much identical from a technical (programming) perspective. This can lead a technical person to think that the functionality should be combined in order to implement a more efficient technical solution. However, any technical implementation must be in response to business need, which might require separation (e.g. by business role) of these concerns.

For example, a business may require that the role which CREATEs business objects is not the same one as EDITs them. In this case, the implemented web pages may not be seen by the same roles (and people) at all.

If you implement CREATE and EDIT using common functionality but the business need is for role separation, you must still implement "role checking" before rendering the required view/partial view/etc. In such cases, separate views can be a preferred implementation.

Upvotes: 8

Chtioui Malek
Chtioui Malek

Reputation: 11515

here's how i do it, it's not always the best practice (it depends on the case)

1/ combine the controller actions for create and edit

public PartialViewResult Creedit(string id = null)
{
    if (id == null)
    {
        // Create new record (this is the view in Create mode)
        return PartialView();
    }
    else
    {
        // Edit record (view in Edit mode)
        Client x = db.ClientSet.Find(id);
        if (x == null) { return PartialView("_error"); }
        // ...
        return PartialView(x);
    }
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Creedit(Client x)
{
    if (x.id == null)
    {
        // insert new record
    }
    else
    {
        // update record
    }
}

2/ combine the edit and create views into one view i called Creedit

// if you need to display something unique to a create view
// just check if the Model is null
@if(Model==null){
}

so i have 1 view and 2 actions (1 post and 1 get) instead of 2 views and 4 action.

Upvotes: 0

Ryan Bosinger
Ryan Bosinger

Reputation: 1862

I do this. I don't know if it's best practice but it can be nice. There are some situations where a completely separate add/edit view could be useful though. Also, if you're using ViewModels then as far as I can tell you're stuck using the same ViewModel for both add and edit. In theory they should both have their own ViewModels.

Here's how this looks for me:

AddVideo.cshtml

@model Multimedia.MediaVideoViewModel

@{
    Layout = "~/Views/Shared/LiveSubLayout.cshtml";
}

@section AdditionalHeadContent {

}

<div class="page-header">
    <h1>Add a new video</h1>
</div>

<div id="add-video" class="row-fluid">
    @Html.Partial("_VideoForm", Model, new ViewDataDictionary { { "ActionKeyword", "Add" } })
</div>

EditVideo.cshtml

@model Multimedia.MediaVideoViewModel

@{
    Layout = "~/Views/Shared/LiveSubLayout.cshtml";
}

@section AdditionalHeadContent {

}

@if (ViewBag.Success)
{
    <div class="alert alert-success">
    <button class="close" data-dismiss="alert">×</button>
        <h3><strong>Video saved!</strong></h3><br/>
        <div class="btn-group">
          <a href="#" class="btn">Preview this video</a>
          @Html.ActionLink("Add Another Video", "AddVideo", "Multimedia", new { Model.Id }, new { @class = "btn" })
          @Html.ActionLink("View all media", "Index", "Multimedia", null, new { @class = "btn" })
        </div>
        <p>or continue editing below...</p>
    </div>
}

<div class="page-header">
    <h1>Edit video <small>@Model.Title</small></h1>
</div>

<div id="edit-video" class="row-fluid">
    @Html.Partial("_VideoForm", Model, new ViewDataDictionary { { "ActionKeyword", "Edit" } })
</div>

_VideoForm.cshtml (partial)

@model Multimedia.MediaVideoViewModel

@{
    string actionKeyword = ViewData["ActionKeyword"].ToString();
}

<div class="span6">

    @using (Html.BeginForm("editvideo", "multimedia"))
    {
        <label class="control-label" id="embed-url">Paste video URL here:</label>
        <div class="control-group">
            @Html.TextBoxFor(model => model.EmbedUrl, new { @class = "span12", id = "video-url", placeholder = "ex: http://www.youtube.com/watch?v=PoAGasPLh30" })
            <button class="btn disabled" id="get-video" title="Tooltip">Get Video</button>
        </div>

        <div class="video-meta">

            <h3>Video Information</h3>
            <label class="control-label">Title:</label>

            <div class="control-group">
                @Html.TextBoxFor(model => model.Title, new { @class = "span12", id = "video-title" })
                @Html.ValidationMessageFor(model => model.Title, "A title is required", new { @class = "label label-important" })
            </div>

            <label class="control-label">Description:</label>
            <div class="control-group">
                @Html.TextAreaFor(model => model.Description, new { @class = "span12", id = "video-description" })
            </div>

            <h3>Categories</h3>

            <div id="tag-search" class="well">
                    <label class="control-label">Search tags:</label>
                    <div class="controls"><input type="text" class="typeahead" /></div>
                    @if (Model != null)
                    {
                        foreach (var category in Model.Tags)
                        {
                            @Html.Partial("_TagFragment", category)
                        }
                    }
            </div>

            <hr />

            @Html.HiddenFor(model => model.Id)
            @Html.HiddenFor(model => model.ThumbnailUrl, new { id = "thumb-url" })
            <input type="submit" id="video-submit" name="video-submit" class="btn-large btn-primary" value="@actionKeyword video" />
        </div>
    }

</div>

I edited these down a bit so something might be missing but this should give you the general idea.

Upvotes: 3

Solmead
Solmead

Reputation: 4199

Look into MVC scaffolding in nuget as well, when it generates the view files it does so explicitly creating a creatandedit partial and having the create page and edit page use that partial.

Upvotes: -1

Rhapsody
Rhapsody

Reputation: 6077

This (kind!) of question is asked before: ASP.NET MVC - using the same form to both create and edit

Basically you can create a partial view and include it on your Create and Edit view.

Scott Guthrie has a nice post about Partial Views.

(I've read about this somewhere, but can't find it, I'll update this post when I do find it)

Upvotes: 10

Related Questions