I'm having some trouble with data being sent through my controller, here's a simplified example:
public ActionResult EditNote(NotesModel model)
{
model.Author = Session["UserName"].ToString();
model.Note = null;
model.Title = null;
return View(model);
}
On my views page the data shown from the model is the exact same as how it was received by the method and all changes are ignored, why?
Bigger picture:
I'm trying to have a user edit an existing note in the database, if they're the one who made it of course. based on whether or not they're the author they will either edit the existing note or create a new note, this is where the problem lies. The controller is supposed to set all the values of the model to null so that on the views page they will be empty. Editing an existing note is no problem however emptying the model so the editing page is blank does not work.
EDIT
This is my view page:
@model WebsiteProject.Models.NotesModel
@{
ViewBag.Title = "";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@section Sidebar
{
<div id="sidebarheadericon" style="background-image: url('../Content/icons/apps.png')"></div>
<div id="headertext"><h1>Welcome</h1></div>
<hr id="seperator" />
<p >test</p>
<p>
@Html.ActionLink("Create New", "EditNote")
</p>
}
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div >
<h1>NotesModel</h1>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<p >Note by @Session["UserName"].ToString()</p>
<div >
@Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
<div >
@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
</div>
</div>
<div >
@Html.LabelFor(model => model.Note, htmlAttributes: new { @class = "control-label col-md-2" })
<div >
@Html.EditorFor(model => model.Note, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Note, "", new { @class = "text-danger" })
</div>
</div>
<div >
<div >
<input type="submit" value="Create" />
</div>
</div>
<p >@ViewBag.NoteViewError</p>
</div>
}
<div>
@Html.ActionLink("Back to List", "NoteApp")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Here you can see the data that is received (dummy data)
Now here you'll see that the data of the model is changed
Yet on the website it is not changed
The biggest problem isn't the Note and Title not being changed because the user can do that, but the Id and Author, which the user cannot, and should not be able to change.
CodePudding user response:
I think you want to tell the incoming notes model is a new one or an existing one, here is some code to try,
public ActionResult EditNote(NotesModel model)
{
if(model.Id > 0) //assuming existing notes has id or any other ways you want to check
{
//save data
return View(model);
}
else //if Id has a value <= 0, return a new model with only Author set, maybe the Id (depending on how you want to generate the Id)
{
var model = new NotesModel();
model.Author = Session["UserName"].ToString();
return Viwe(model);
}
}
CodePudding user response:
This is related to the fact that you are using EditorFor
:
@Html.EditorFor(model => model.Note, new { htmlAttributes = ... })
It so happens that EditorFor
not only uses the Model
object, it also uses ModelState
which keeps a copy of all values for all Model items that were received, parsed and validated, along with any validation errors that this may have produced.
As long as ModelState
has a value for that model item, it will be shown by EditorFor
. The reason is that user input may be invalid, like entering 12X for an int
Model property. EditorFor will show 12X if the form is re-rendered, which is coming from ModelState, and which could never come from Model.
Unwanted values can be removed by calling Remove
, like this:
ModelState.Remove("Note");
On a different note, the ViewModel class that you are using here is not suited to the needs of this action method. It may be better to create a dedicated ViewModel class for it, with fewer properties, which you can then convert to the ViewModel type that the View needs.