I've got 4 shared EditorTemplates: Tab, Group, Line & Item.
Tab.cshtml:
#model AWMCCRM.Web.ViewModels.Tab
#Html.HiddenFor(vm => vm.Name)
<div id="tab-#Model.Name.Replace(" ", string.Empty)" class="tab-content">
#Html.EditorFor(vm => vm.Groups)
</div>
Group.cshtml:
#model AWMCCRM.Web.ViewModels.Group
#Html.HiddenFor(vm => vm.Name)
<fieldset>
<legend>#Model.Name</legend>
#Html.EditorFor(vm => vm.Lines)
</fieldset>
Line.cshtml:
#model AWMCCRM.Web.ViewModels.Line
#Html.HiddenFor(vm => vm.Name)
#Html.EditorFor(vm => vm.Items)
Item.cshtml:
#model AWMCCRM.Web.ViewModels.Item
<div class="#Model.DivClass">
<p class="#Model.PClass">
Html.LabelFor(vm => vm.ValueString, Model.Name);
Html.TextBoxFor(vm => vm.ValueString);
</p>
</div>
Corresponding ViewModels:
public class Tab
{
public string Name { get; set; }
public List<Group> Groups { get; set; }
}
public class Group
{
public string Name { get; set; }
public List<Line> Lines { get; set; }
}
public class Line
{
public string Name { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public string Name { get; set; }
public string Description { get; set; }
public string ValueString { get; set; }
public string DivClass { get; set; }
public string PClass { get; set; }
}
In my main View I have this:
#Html.EditorFor(vm => vm.Tabs)
The code that gets generated looks like this:
<div id="tab-Tab-1" class="tab-content">
<input id="Tabs_0__group_Name" name="Tabs[0].group.Name" type="hidden" value="Group0" />
<fieldset>
<legend>Group0</legend>
<input id="Tabs_0__group_line_Name" name="Tabs[0].group.line.Name" type="hidden" value="Line0" />
<div class="_20">
<p class="">
</p>
</div>
</fieldset>
</div>
As you can see, the div and the p gets generated, but there is no textbox or label.
I have also tried this in the item template instead, but it didn't work either:
Html.TextBoxFor(vm => Model.ValueString);
Any ideas why or what I need to do?
Thanks
Ok, I'm almost too embarrassed to post the solution but here it is...
I was missing the '#' in the beginning of the lines;
in my item.cshtml
Html.LabelFor(vm => vm.ValueString, Model.Name);
Html.TextBoxFor(vm => vm.ValueString);
should be
#Html.LabelFor(vm => vm.ValueString, Model.Name);
#Html.TextBoxFor(vm => vm.ValueString);
Related
I am trying to create an entity that has subitems and am having issues with passing the model back and forth.
I have an entity RiskAssessnent that contains a list of Risk entities.
public class RiskAssessment
{
public int Id { get; set; }
public DateTime Date { get; set; }
public ICollection<Risk> Risks { get; set; }
public int ResidentId { get; set; }
public Resident Resident { get; set; }
public int EmployeeId { get; set; }
public Employee Employee { get; set; }
}
public class Risk
{
public int Id { get; set; }
public string Description { get; set; }
public int RiskAssessmentId { get; set; }
public RiskAssessment RiskAssessment { get; set; }
}
here is my view for creating a RiskAssessment:
#model CareHomeMvc6.Models.RiskAssessmentViewModels.RiskAssessmentViewModel
#{
ViewData["Title"] = "Create";
}
<a class="btn btn-default" asp-action="Index" asp-route-residentId="#Model.ResidentId">Back to List</a>
<div class="page-header">
<h1>Create a Risk Assessment</h1>
</div>
<form asp-action="Create">
<div class="form-horizontal">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#Html.HiddenFor(m => m.EmployeeId)
#Html.HiddenFor(m => m.ResidentId)
<div class="form-group">
<label asp-for="Date" class="col-md-2 control-label"></label>
<div class="col-md-10">
#Html.EditorFor(m => m.Date, new { #class = "form-control" })
<span asp-validation-for="Date" class="text-danger" />
</div>
</div>
#foreach(var risk in Model.Risks)
{
<h3>#risk.Description</h3>
}
<p>
<a class="btn btn-success" asp-action="CreateRisk">Create</a>
</p>
<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>
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
and here is the controller:
public IActionResult CreateRisk(RiskAssessmentViewModel riskAssessmentViewModel)
{
var vm = new CreateRiskViewModel
{
RiskAssessment = riskAssessmentViewModel,
Risk = new Risk()
};
return View(vm);
}
and the ViewModel:
public class RiskAssessmentViewModel
{
public RiskAssessmentViewModel()
{
this.Risks = new List<Risk>();
this.Risks.Add(new Risk
{
Id = 1,
Description = "blah",
PotentialRisk = "blah"
});
}
public int Id { get; set; }
[Display(Name = "Date")]
[DataType(DataType.Date)]
[Required]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime Date { get; set; }
public ICollection<Risk> Risks { get; set; }
public int ResidentId { get; set; }
public int EmployeeId { get; set; }
}
Sorry for all the code so far!
I was attempting to keep passing the ViewModel back and forth until all items have been created but within the CreateRisk action the ResidentId and EmployeeId are 0 therefore not being set, although I do get the collection of risks. If I click submit on the form which encapsulates everything then they are set. Is there any reason the hidden items are being sent to the form submit but not the link action?
I realise there are JS solutions to doing dynamic lists but I wanted to stay away from it as the page navigation is acceptable, the form will when finished require a lot of data entry for a Risk.
Any help with this would be greatly appreciated.
Thanks
I have in model having the questions and answer list. In some of the questions having 4 options and some of the questions having the 2 options.
I am getting the options from the back end and i'm binding from model class into the razor view.
Now if the answer value null means radio button is showing but i don't want to radio button if the radio button option value nulls.
#for (int j = 0; j < Model.Count; j++)
{
i++;
<div class="panel-heading online-test" role="tab" id="">
<h5 class="panel-title">
#Html.HiddenFor(m => m[j].ID)
#Html.HiddenFor(m => m[j].SkillId)
#i) #Html.DisplayFor(m => m[j].QuestionText)
</h5>
</div>
foreach (var k in Model[j].Options)
{
<div class="panel-collapse">
<div class="panel-body online-test-options">
<div class="input-group">
<div class="col-lg-12" id="radiolist">
#Html.RadioButtonFor(m => m[j].SelectedAnswer, "A")
<label for="#k.AnswerId">#k.Option1</label>
</div>
<div class="col-lg-12">
#Html.RadioButtonFor(m => m[j].SelectedAnswer, "B")
<label for="#k.AnswerId">#k.Option2</label>
</div>
<div class="col-lg-12">
#Html.RadioButtonFor(m => m[j].SelectedAnswer, "C")
<label for="#k.AnswerId">#k.Option3</label>
</div>
<div class="col-lg-12">
#Html.RadioButtonFor(m => m[j].SelectedAnswer, "D")
<label for="#k.AnswerId">#k.Option4</label>
</div>
</div>
</div>
</div>
}
}
public class QuestionsModel
{
public decimal ID { set; get; }
public decimal SkillId { get; set; }
public string QuestionText { set; get; }
public List<Answer> Options { set; get; }
public string SelectedAnswer { set; get; }
public QuestionsModel()
{
Options = new List<Answer>();
}
}
public class Answer
{
public int AnswerId { get; set; }
public string Option1 { set; get; }
public string Option2 { set; get; }
public string Option3 { set; get; }
public string Option4 { set; get; }
}
public class Evaluation
{
public List<QuestionsModel> Questions { set; get; }
public Evaluation()
{
Questions = new List<QuestionsModel>();
}
}
Please help to solve..
Thanks in Advance.
I'm working on a form that has a main model being passed to the view. The model has sub-models within it, with partial views to render that content. The problem is that when I fill out the form, only those parameters on the main form get bound back to the model when the form is submitted.
I tried changing the Html.RenderPartial to a Html.EditorFor, and while it fixed my model binding problem, it removed all of my html formatting from the partial view.
Is there a way I can either bind my partial view elements to the main form model, or keep the html structure of my partial view using EditorFor?
Below is my code (I chopped out a bunch of stuff - especially from my main view - to try to simplify what I'm looking for).
This is my model:
public class ShipJobs
{
public String Job { get; set; }
public String Quote { get; set; }
public String PartName { get; set; }
public String Rev { get; set; }
public String Customer { get; set; }
public String CustomerName { get; set; }
public String TrackingNumber { get; set; }
public Int32 ShippedQuantity { get; set; }
public Boolean Certs { get; set; }
public Double ShippingCharges { get; set; }
public DateTime ShipDate { get; set; }
public String SelectedFreightTerms { get; set; }
public IEnumerable<SelectListItem> FreightTerms { get; set; }
public String SelectedContact { get; set; }
public IEnumerable<SelectListItem> Contacts { get; set; }
public String SelectedShipVia { get; set; }
public IEnumerable<SelectListItem> ShipVia { get; set; }
public Models.GreenFolders.Address Address { get; set; }
}
public class Address
{
public AddressType Type { get; set; }
public String ShipToId { get; set; }
public String ContactName { get; set; }
public String AddressName { get; set; }
public String Line1 { get; set; }
public String Line2 { get; set; }
public String City { get; set; }
public String State { get; set; }
public String Zip { get; set; }
public String Phone { get; set; }
public SelectList ShipToAttnDropDown { get; set; }
public IEnumerable<SelectListItem> ShipToDropDown { get; set; }
}
Controller:
public ActionResult ShipJobs(String Job, Models.Shipping.ShippingModel.ShipJobs Packlist, Models.GreenFolders.Address ShipAddress, String Submit = "")
{
var Model = new Models.Shipping.ShippingModel.ShipJobs();
if (Submit == "loadjob")
{
var shippingHelper = new BLL.Shipping.ShippingMethods(_company);
Model = shippingHelper.GetShipJobModel(Job);
Model.Address = shippingHelper.GetShipAddress(Job);
}
else if (Submit == "createpacklist")
{
}
ViewBag.Company = _company.ToString();
return View(Model);
}
Main View:
#model Models.Shipping.ShippingModel.ShipJobs
#{
ViewBag.Title = "ShipJobs";
String Company = ViewBag.Company.ToString();
}
#using (Html.BeginForm("ShipJobs", "Shipping", FormMethod.Post, new { Class = "form-horizontal" }))
{
<div class="row">
<div class="col-md-6">
<!-- Basic Form Elements Block -->
<div class="block">
<!-- Basic Form Elements Title -->
<div class="block-title">
<h2>Load <strong>Job</strong></h2>
</div>
<!-- END Form Elements Title -->
<!-- Basic Form Elements Content -->
#using (Html.BeginForm("ShipJobs", "Shipping", FormMethod.Post, new { Class = "form-horizontal form-bordered" }))
{
<div class="form-group">
<label class="col-md-3 control-label" for="example-text-input">Job Number</label>
<div class="col-md-9">
#Html.TextBoxFor(model => model.Job, new { id = "example-text-input", Name = "Job", Class = "form-control" })
</div>
</div>
<div class="form-group form-actions">
<div class="col-md-9 col-md-offset-3">
<button type="submit" class="btn btn-sm btn-primary" name="submit" value="loadjob"><i class="fa fa-angle-right"></i> Load Job Info</button>
<button type="reset" class="btn btn-sm btn-warning"><i class="fa fa-repeat"></i> Reset</button>
</div>
</div>
}
</div>
</div>
<div class="col-md-6">
#if (Model.Address != null && Model.Address != null)
{
#Html.EditorFor(model => model.Address)
//Html.RenderPartial("../Shared/_Address", Model.ShipInfo);
}
</div>
#Html.HiddenFor(model => model.Quote)
#Html.HiddenFor(model => Company)
</div>
}
Partial view:
#model Models.GreenFolders.Address
<!-- Block -->
<div class="block">
<div class="block-title">
#if(Model.Type == Models.GreenFolders.AddressType.Shipping)
{
<h2 style="float: right; margin-top: -9px; margin-right: -10px;">
<div class="dropdown shiptoddl">
<button class="btn btn-default dropdown-toggle" type="button" id="shiptoddl" data-toggle="dropdown" aria-expanded="true">
#Model.ShipToDropDown.Where(x => x.Selected).FirstOrDefault().Text
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
#foreach (SelectListItem selectlistitem in Model.ShipToDropDown)
{
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" data-value="#selectlistitem.Value" data-selected="#selectlistitem.Selected">#selectlistitem.Text</a></li>
}
</ul>
</div>
#*#Html.DropDownList("shiptoddl", (SelectList)Model.ShipToDropDown, new { #class = "shiptoddl", id = "shiptoddl" })*#
</h2>
}
<h4><strong>#Model.Type.ToString()</strong> Address</h4>
</div>
#{ Html.RenderPartial("../Shared/_AddressDetails", Model); }
</div>
<!-- END Block -->
Im trying to implement a way how to enter recipes correctly, so far I have the following:
Recipe.cs
public class Recipe
{
[Key]
public int RecipeId { get; set; }
[Required]
public string Name { get; set; }
public string Subtitle { get; set; }
public int Serving { get; set; }
public string Instructions { get; set; }
public virtual ICollection<Ingredient> Ingredients
}
Ingredient.cs
public class Ingredient
{
[Key]
public int IngredientId { get; set; }
public string Name { get; set; }
public string Amount { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}
In my Form, I want to Add the Ingredients Inline, with JavaScript Rendering a new pair of fields if needed.
(The ViewModel is nothing else than a class holding an instance of Recipe)
Create.cshtml
#model Vineyard.WebUI.Areas.Admin.Models.RecipeViewModel
<div class="span9">
<h2>Create a new Recipe</h2>
#using (#Html.BeginForm("Create", "Recipes", FormMethod.Post))
{
<fieldset>
#Html.LabelFor(r => r.Recipe.Name)
#Html.TextBoxFor(r => r.Recipe.Name)
</fieldset>
<fieldset>
#Html.LabelFor(r => r.Recipe.Subtitle)
#Html.TextBoxFor(r => r.Recipe.Subtitle)
</fieldset>
<div id="ingredients">
#Html.EditorFor(r => r.Recipe.Ingredients, "Ingredient")
</div>
Add Ingredient
<fieldset>
#Html.LabelFor(r => r.Recipe.Serving)
#Html.TextBoxFor(r => r.Recipe.Serving)
</fieldset>
<fieldset>
#Html.LabelFor(r => r.Recipe.Instructions)
#Html.TextAreaFor(r => r.Recipe.Instructions)
</fieldset>
<input type="submit" value="Save Recipe" />
}
</div>
Shared/EditorTemplates/Ingredient.cshtml
#model Vineyard.Core.Entities.Ingredient
<div class="ingredient form-inline">
#Html.LabelFor(r => r.Amount)
#Html.TextBoxFor(r => r.Amount)
#Html.LabelFor(r => r.Name)
#Html.TextBoxFor(r => r.Name)
</div>
In the rendered HTML tough, I see the following:
<input id="Recipe_Ingredients_Amount" name="Recipe.Ingredients.Amount" type="text" value="">
Which leads my to believe, that it does not Add the Ingredient as a Member of the Collection, but as a full blown Object by itself. Shouldnt it have an index referencing to it? (Based of this http://jarrettmeyer.com/post/2995732471/nested-collection-models-in-asp-net-mvc-3)
When I look at the Model, that is being passed back to the controller, the Ingredients Part is null
So, Im wondering - what am I missing here or doing wrong, that can be changed to actually populate the Collection correctly? From there, I can handle it in the controller to be saved in the right format.
Change
public virtual ICollection<Ingredient> Ingredients
to
public IEnumerable<Ingredient> Ingredients { get; set; }
(lose the virtual and change ICollection to IEnumerable).
Also, in your controller, pre-populate the list of ingredients with a single item (for testing) otherwise nothing will appear in your HTML.
This answer was converted from my comment
I have a list of comments under my detail page in MVC. I want the user to be able to add comments in the same page and save to the database. How do I pass data to the controller action and save this using dbcontext that holds my comment class.
I have this follow code in my CommentController:
public ActionResult Create(int MovieId)
{
var moviecomment = _db.Moviecomment.Where(r => r.MovieID == MovieId);
return View(moviecomment);
}
[HttpPost]
public ActionResult Create(MovieComment Moviecomment)
{
var MovieComment = _db.Moviecomment.Add(Moviecomment);
_db.SaveChanges();
return RedirectToAction("Details");
}
And has a partial View:
#model MvcMovie.Models.MovieComment
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="addcommentbox">
<h2> Add Comment </h2>
#Html.TextAreaFor(model => model.comment)
<div class="ErrorMessage">
#Html.ValidationMessageFor(model => model.comment)
</div>
<input id="addComment" type="button" onclick="" value="Add" />
</div>
}
and in my Detail page i have this:
#model MvcMovie.Models.Movie
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
Movie
Title
#Html.DisplayFor(model => model.Title)
Genre
#Html.DisplayFor(model => model.Genre)
PostDate
#Html.DisplayFor(model => model.PostDate)
Staring
#Html.DisplayFor(model => model.Staring)
Description
#Html.DisplayFor(model => model.Description)
Trailer
#Html.DisplayFor(model => model.Trailer)
<fieldset>
#Html.Partial("Comments",Model.MovieComment)
</fieldset>
<p>
</p>
<p>
#Html.ActionLink("Edit", "Edit", new { id=Model.MovieID }) |
#Html.ActionLink("Back to List", "Index")
</p>
#Html.RenderAction("Create","Comment" new { id = Model.MovieID })
i want user to able to add comment when they are in detail page: other thing seem to been fine but this line
#Html.RenderAction("Create","Comment" new { id = Model.MovieID })
give me the following error. cannot implicitly convert type void to object. Please any help will be appreciated.
The model code:
public class Movie
{
public int MovieID { get; set; }
public string Title { get; set; }
public String Genre { get; set; }
public DateTime PostDate { get; set; }
public string Staring { get; set; }
public string Description { get; set; }
public string Picture { get; set; }
public string Trailer { get; set; }
public virtual ICollection< MovieComment> MovieComment { get; set; }
}
For comment
public class MovieComment
{
// public MovieComment()
//{
// Movie = new HashSet<Movie>();
//}
public int MovieCommentID { get; set; }
public string comment_title { get; set; }
public String comment { get; set; }
public int MovieID { get; set; }
// [ForeignKey("ID")]
public virtual Movie Movie { get; set; }
//[ForeignKey("ProfileID")]
public virtual Profile Profile { get; set; }
public String ProfileID { get; set; }
//public string MovieUserID { get; set; }
}
Not sure if this is your only error, but the syntax is wrong for the line that's giving you an error. You are missing a comma. Try:
#Html.RenderAction("Create","Comment", new { id = Model.MovieID })
If this doesn't fix your problem, can you also post the code for your model?