I'm having some trouble understanding how #Razor works in a view. The code below is my view where a user can create a new post (I'm creating a forum)
What I want to do is remove the <Fieldset>
My problem is that I can't change the code I've marked.
#model Forum3.Models.Posts
<h2>CreatePost</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
//--- CAN'T EDITED ----
<fieldset>
<legend>Post</legend>
#*SET TopicID*#
#{
Html.HiddenFor(model => model.TopicId);
#Html.Hidden("TopicId",ViewData["currentTopicId"]);
}
//----END----
<div class="editor-label">
#Html.LabelFor(model => model.Text)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Text)
#Html.ValidationMessageFor(model => model.Text)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
If I remove the <Fieldset> and <Legend> I get this error on my HiddenFor code:
Parser Error Message: Unexpected "{" after "#" character. Once inside the body of a code block (#if {}, #{}, etc.) you do not need to use "#{" to switch to code.
If I then remove the #{...} to look like this:
#Html.HiddenFor(model => model.TopicId);
#Html.Hidden("TopicId",ViewData["currentTopicId"]);
I'll get an error when I click Create because the TopicId is not being set to my currentTopicId (This also happens if I leave the <fieldset> in)
I have no idea what going on here. Any ideas?
I'm not having any errors with that once you remove the surrounding block and use the # on both fields. However, one thing you do have that's probably messing up your post - you have both a Hidden and a HiddenFor for the same property. So if you look at the rendered markup, you'll see it there twice, so it gets posted twice (I'm not sure which one it assigns to the posted model).
The HiddenFor is all you need - just make sure your model contains the TopicId value, and you don't need it in ViewData at all, so you can get rid of that second one.
Related
I have two ASP.NET MVC EF entities sharing an association:
When I am editing or creating the User, I'd like to be able to attach one or more UserRoles. So, my User Create view looks like this:
#model MyModels.UserViewModel
#{ ViewBag.Title = "Create"; }
#using (Html.BeginForm())
{
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Username)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Username)
#Html.ValidationMessageFor(model => model.Username)
</div>
<!-- how to create an editor to add/remove roles -->
<div class="editor-label">
#Html.LabelFor(model => model.UserRoles)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserRoles)
#Html.ValidationMessageFor(model => model.UserRoles)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Since Model.UserRoles is initially empty, I get nothing in this line #Html.EditorFor(model => model.UserRoles). I tried adding a drop-down where I can select existing roles using JavaScript (I guess retrieved as partial view?), but I don't know how to append a selected role to the fieldset so that it gets submitted.
How is this usually done in ASP.NET? I have been searching SO for a while but cannot find the appropriate solution.
To clarify, what I don't understand is how to add/append a new role to the client side, so that the submit button actually sends this inside the UserRoles list.
(edit) Ok, I've found this: How to add an item to a list in a ViewModel using Razor and .NET Core. It says that I should fetch a partial view which is written to look like the inputs which would be generated by #Html.EditorFor (with the next array index), and then append it using JavaScript.
That looks quite weird, is that really the correct approach?
I'm still a bit novice to the ASP.NET MVC architecture. I have an Edit page for data, which includes a hidden input. After testing my page, the 'Save' button wasn't doing anything and after some research learned it was a client-side validation issue.
After commenting the following line in the page:
#*#Html.HiddenFor(model => model.ID)*#
(where ID is a GUID), the page validated and posted.
From what I recall, the scaffolding put this code into my view. I just need to know how to fix this so that the ID field gets sent back properly to the controller and wanted to know why it wasn't validating.
Here is my View's code:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<div class="object_basics">
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Have you tried to add the validation message for the ID ?
#Html.ValidationMessageFor(model => model.ID)
Client side validation for hidden fields not working, because jQuery validation ignore all hidden tags.
You must define HiddenRequiredValidator class to achieve your goal.
You can read a solution to solve this problem Here
In view, update from:
#using (Html.BeginForm())
To
#using (Html.BeginForm(new{ID = model.ID}))
Remove the hidden element [#Html.HiddenFor(model => model.ID)].
In your controller, update the action properties like below
public ActionResult YourActionName(string ID, string Title)
Hopefully, this answers your question.
Cheers,
Danny
What I'm trying to achieve is essentially have a view that at the top displays a form to enter new post, then below the form it will display a list of posts that already exist. Also I'm trying to make this view somewhat generic so that it can show different type of posts.
To be clear, by post I mean something like a facebook status post and not a Http-Post.
Imagine you have home page that displays all the posts, and then you have a profile page that displays only the posts connected to that profile.
So I have my _Posts partial view which looks like this:
#model IEnumerable<Post>
#Html.Partial("_CreatePost", new Post())
#foreach (var item in Model)
{
<div class="Post">
<h5>#item.Title</h5>
<p>#DateTime.Now.Subtract(item.Date).ToString("mm") minutes ago</p>
<p>#item.Content</p>
</div>
}
The code for the partial view is:
#model MVC_Test_CRUD.Models.Post
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
#using (Html.BeginForm("Create","Post")) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Post</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
And I successfully display a list of posts and I'm able to create new posts as well.
I also have a standard Create Action in my controller, which results in
return RedirectToAction("Index")
if the creation was successful. So my question is how can I send additional parameter to the controller about where to redirect (home/index or profile/index or somewhere else) depending on where
#Html.Partial("_CreatePost", new Post())
was inserted.
I have a little Ajax application where I use Razor views to initially generated HTML form segments that I later read and write from with knockout.js. Although I am doing no non-Ajax action requests, I use Razor to generate the HTML so I enjoy automatic generation of jQuery Validation attributes. E.g. in my single page, I render a hidden form like this:
<section id="person-detail">
#Html.Action("EditPartial", "Person")
</section>
The EditPartial action returns a partial view that looks a lot like this:
#using (Html.BeginForm())
{
<fieldset>
#Html.HiddenFor(model => model.Id, new { data_bind = "value: id" })
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: firstName" })
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<p>
Update
Delete
</p>
</fieldset>
}
Because I'm never actually posting the form, and due to some unknowns, despite all properties on my Person model being marked with the Required attribute, I see no sign of client side validation. What must I do to trigger this validation when my save button is clicked?
suppose your form has a class 'main':
$('form').submit(function() {
var $form = $('form.main');
$form.valid();
});
I would like to use the same partial view for create, edit, and details views, to avoid duplicating the fieldset structure for an entity. Then, depending on which view renders the partial view, I would like to add a class of "read-only" to a div surrounding my fieldset and handle making the actual input fields read-only on the client, using css or jQuery, or whatever. How can I specify from my Razor view that I need this class added to the "item-details" div?
<div class="item-details">
<fieldset>
<legend>Product Details</legend>
#Html.HiddenFor(model => model.DetailItem.ProductId)
<div class="editor-label">
#Html.LabelFor(model => model.DetailItem.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DetailItem.Name)
#Html.ValidationMessageFor(model => model.DetailItem.Name)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</div>
I would generally have a variable on the model that would indicate if your data is editable, and use it like:
<div class="item-details #(Model.IsReadOnly ? "read-only" : "")">
If you don't have it on the model however, you can use the ViewBag. In your parent view:
#{
ViewBag.IsModelReadOnly = true;
}
In your partial view:
<div class="item-details #(ViewBag.IsModelReadOnly ? "read-only" : "")">
Your html output for a readonly view would be
<div class="item-details read-only">
You can then access the div via jQuery and do what you need: $(".read-only")...
Why not just use
#Html.DisplayFor(model => model.[whatEver Property you are trying to show])