I am new to MVC having developed in WebForms for a long time and I'm following an online course to update an existing WebForms project to an MVC project. Most of the things are working without a hitch but I have found one thing in my course that I just cannot understand.
In my course the presenter does the following:
CreateEdit.cshtml:
<label>Description</label>
#Html.TextAreaFor(x => x.Desc)
</div>
var list = new List<SelectListItem>()
{
new SelectListItem() { Text="Look at me", Value="1" }
}
<div>
#Html.DropDownListFor(x => x.Category, list, new { #class = "form-control" }
</div>
Regardless of what I do the "var list ..." part doesn't work in my Visual Studio.
Does anyone know what I'm doing wrong or why this way of typing doesn't work??
------ Edited with the full page included: ----------
#model CypherMVC.Models.Task
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Create a New Task<br />
<small>These are issues your team members should take care of - ASAP!</span></small>
</h1>
</div>
</div>
<div class="row">
<div class="col-md-12">
#using (Html.BeginForm("CreateEdit", "Task"))
{
<div class="form-group">
#Html.LabelFor(x => x.Title)
#Html.TextBoxFor(x => x.Title, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(x => x.Description)
#Html.TextAreaFor(x => x.Description, new { #class = "form-control", rows = 5 })
</div>
var list = List<SelectListItem>()
{
new SelectListItem() { Text="Look at me", Value="1" }
}
<div class="form-group">
#Html.LabelFor(x => x.CategoryId, "Category")
#Html.DropDownListFor(x => x.CategoryId, list, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(x => x.DueDate, "Due Date")
#Html.TextBoxFor(x => x.DueDate, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(x => x.AssignedToId, "Assigned To")
#Html.TextBoxFor(x => x.AssignedToId, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(x => x.AssociatedMessageId, "Associated Message")
#Html.TextBoxFor(x => x.AssociatedMessageId, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(x => x.Notes)
#Html.TextAreaFor(x => x.Notes, new { #class = "form-control", rows = 5 })
</div>
<div class="form-group">
#Html.LabelFor(x => x.Completed, "Is Complete")
#Html.CheckBoxFor(x => x.Completed)
</div>
<div class="form-group">
<input class="btn btn-primary pull-right" type="submit" text="Submit">
</div>
}
</div>
</div>
Try to wrap it with
#{
var list = new List<SelectListItem>()
{
new SelectListItem() { Text="Look at me", Value="1" }
};
}
All C# code inside a razor template needs to go inside code blocks (#{ ... }). Here are the official docs on this.
Your example should look like this:
<label>Description</label>
#Html.TextAreaFor(x => x.Desc)
</div>
#{
var list = new List<SelectListItem>()
{
new SelectListItem() { Text="Look at me", Value="1" }
};
}
<div>
#Html.DropDownListFor(x => x.Category, list, new { #class = "form-control" }
</div>
UPDATE: Since Mr.Glaurung says that the code from the course he is following is getting this to work without the code block syntax, I suspect the code is already inside a razor control structure.
The code examples below would also work. Since we don't see the whole template in your example, we can't know for sure.
Inside a loop:
#{
var someList = new List<string>() {"1", "2", "3"};
}
#foreach (var s in someList)
{
<h1>Some HTML</h1>
//C# code
var list = new List<int>() {1, 2, 3};
<h2>More HTML</h2>
}
Or inside a if statement:
#if (true)
{
<h1>Some HTML</h1>
//C# code
var list = new List<int>() { 1, 2, 3 };
<h2>More HTML</h2>
}
Related
I want to pass a List of VoedingBindingModel to my controller by using an Editor Template, however I only receive the first entry of the List in the Controller, never all the entries.
The Controller:
public ActionResult Create()
{
ViewBag.fk_customVoedingId = new SelectList(customvoeding.GetAllCustomvoeding(), "customVoedingId", "customVoedingNaam");
ViewBag.fk_standaardVoedingId = new SelectList(standaardvoeding.GetAllStandaardvoeding(), "standaardVoedingId", "standaardVoedingNaam");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Datum,Tijd,VoedingCollection")]AgendaBindingModel agendaBindingModel)
{
//Do something
}
The Model:
public class AgendaBindingModel
{
[Required]
public List<VoedingBindingModel> VoedingCollection { get; set; }
//More properties
}
The View:
#using Website.Models
#model AgendaBindingModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>agenda</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Datum, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Datum, "{0:dd-MM-yyyy}", new { #class = "form-control-datepicker", placeholder = "DD-MM-YYYY", maxlength = "10" })
#Html.ValidationMessageFor(model => model.Datum, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Tijd, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Tijd, "{0:hh:mm}", new { htmlAttributes = new { #class = "form-control-timepicker", placeholder = "hh:mm", maxlength = "5" } })
#Html.ValidationMessageFor(model => model.Tijd, "", new { #class = "text-danger" })
</div>
</div>
<div id="CreateVoedingDiv0">
#Html.EditorFor(x => x.VoedingCollection[0])
</div>
<div id="CreateVoedingDiv1"hidden>
#Html.EditorFor(x => x.VoedingCollection[1])
</div>
<div id="CreateVoedingDiv2"hidden>
#Html.EditorFor(x => x.VoedingCollection[2])
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input value="Add" class="btn btn-default" onclick="ShowVoeding()" /> <input value="Remove" class="btn btn-default" onclick="HideVoeding()" />
</div>
</div>
<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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script>
var count = 1;
function ShowVoeding()
{
if (document.getElementById("CreateVoedingDiv" + count).hidden == true)
{
document.getElementById("CreateVoedingDiv" + count).hidden = false;
count++;
}
}
function HideVoeding()
{
count = count - 1;
if (document.getElementById("CreateVoedingDiv" + count).hidden == false) {
document.getElementById("CreateVoedingDiv" + count).hidden = true;
}
}
</script>
Partial class:
(customvoeding and standaardvoeding do the same thing, only customvoeding returns a collection of customvoeding and standaardvoeding returns a collection of standaardvoeding.
public partial class customvoeding
{
private static foodtrackerEntities1 db = new foodtrackerEntities1();
public static List<customvoeding> GetAllCustomvoeding()
{
db.Configuration.LazyLoadingEnabled = false;
return db.customvoeding.ToList();
}
}
You don't seem to be initializing the model and passing it to the view. In the action methods of your controller try adding:
var viewModel = new AgendaBindingModel();
viewModel.VoedingCollection = // TODO: Fill the list from your data source
return View(viewModel );
Try like this. I could not test, but if you like we can advance is this way:
To show all items:
<div id="group">
#for(int i = 0; i < AgendaBindingModel.VoedingCollection.Count; i++)
{
#Html.EditorFor(x => x.VoedingCollection[i])
}
To add new item:
<button onclick=newItem() >+</button>
</div>
<script>
function newItem(){
var div = document.createElement('div');
div.id = CreateNewItem;
div.innerHTML = '#Html.EditorFor(x => x.VoedingCollection[i])';
document.body.appendChild(div);
}
</script>
Your second and third html are broken.
<div id="CreateVoedingDiv2"hidden>
remove hidden
I found out what was preventing me from receiving more than one result:
You can NOT use #Html.EditorFor template for more than 1 value when you specify a template. It does not matter if you use different models or different templates, it just simply does not work.
To fix it, you have to use 'Html.BeginCollectionItem' library, which can be found here.
I have a form-group where the label is missplaced, the label is too far down compared to the dropdownlist, see image.
This is my code:
<div class="form-group">
<div class="col-lg-2"></div>
#Html.LabelFor(model => model.deviceModel, "OS:", htmlAttributes:
new { #class = "col-lg-2 control-label" })
<div class="col-lg-4">
#Html.DropDownListFor(model => model.deviceModel, new SelectListItem[]{
new SelectListItem{Value = "1", Text="iOS"},
new SelectListItem{Value = "2", Text="Android"}},
new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="col-lg-2"></div>
</div>
What have i done wrong, why is it missplaced?
I am not into C# and Razor but based on my comment and looking at the code the newin front of the htmlAttributes for the Dropdownlist looks not right. It seems like the class is not applied to the Dropdownlist, which then could cause the shifting, probably caused by different margin parameters.
<div class="form-group">
<div class="col-lg-2"></div>
#Html.LabelFor(model => model.deviceModel, "OS:",
htmlAttributes: new { #class = "col-lg-2 control-label" })
<div class="col-lg-4">
#Html.DropDownListFor(model => model.deviceModel, new SelectListItem[]{
new SelectListItem{Value = "1", Text="iOS"},
new SelectListItem{Value = "2", Text="Android"}},
htmlAttributes: new { #class = "form-control" } )
</div>
<div class="col-lg-2"></div>
I have the following view:
#model GRCWebApp.ViewModels.NewClubInterestsViewModel
#{
ViewBag.Title = "Add Club Interests";
}
<div class="col-md-10 col-offset-md-1">
<h2 class ="text-success">Add Club Interests for #Html.DisplayFor(model => model.Name)</h2>
</div>
#using (Html.BeginForm("NewInterests", "Club", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
<div class="row">
<div class="col-md-8">
<div class="well bs-component">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(x => Model.ClubId)
<div class="form-group">
<div class="col-md-10 col-md-offset-1">
<h3>Tick the areas your club is interested/runs events in</h3>
</div>
</div>
<div class="col-md-offset-1">
#for (int i = 0; i < Model.ClubTypeInterests.Count(); i++)
{
<div>
#Html.HiddenFor(x => Model.ClubTypeInterests[i].InterestId)
#Html.CheckBoxFor(x => Model.ClubTypeInterests[i].selected)
#Html.LabelFor(x => Model.ClubTypeInterests[i].InterestName, Model.ClubTypeInterests[i].InterestName)
</div>
}
</div>
<div class="form-group">
<div class="row">
<div class="col-md-offset-1 col-md-12">
<input type="submit" name="Submit" value="Next" class="btn btn-success btn-lg" /> to setup Online membership
<input type="submit" name="Submit" value="Complete" class="btn btn-warning btn-sm" /> to just provide online event entries
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
#using (Html.BeginForm("AddInterest", "Club"))
{
#Html.AntiForgeryToken()
<hr />
<div class="row">
<div class="col-md-8">
<div class="well bs-component">
<div class="form-group">
<div class="col-md-12 col-md-offset-1">
<h3>Not listed? - Add extras here</h3>
</div>
</div>
#Html.HiddenFor(model => model.ClubTypeId)
#Html.HiddenFor(model => model.ClubId)
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-inline">
<div class="form-group">
<div class="row col-md-offset-1 col-md-11">
<div class="col-md-4">
#Html.LabelFor(model => model.InterestName, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.InterestName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.InterestName, "", new { #class = "text-danger" })
</div>
<div class="col-md-5">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
<input type="submit" value="Add" class="btn btn-info" style="margin-top: 22px" />
</div>
</div>
</div>
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Overtime the page loads the Validation message shows for InterestName in the second form AddInterest.
The Get method for the whole form is:
[HttpGet]
public ActionResult NewInterests(NewClubInterestsViewModel model, int id)
{
//Find the Club and then pass its id to the ViewModel
var club = db.Clubs.Find(id);
//model.ClubId = club.ClubId ;
//Interests List
IEnumerable<Interest> allExistingInterests;
//Generate a list of the interests that apply to that type of club
using (ApplicationDbContext context = new ApplicationDbContext())
{
allExistingInterests = context.Interests
.Where(s => s.ClubTypeId == club.ClubTypeId)
.OrderBy(s => s.InterestName)
.ToList();
}
IEnumerable<int> clubInterestIds = club.ClubInterests.Select(x => x.InterestId).ToList();
//Generate the ViewModel with the appropriate Interests
var viewModel = new NewClubInterestsViewModel
{
ClubId = club.ClubId,
Name = club.Name,
ClubTypeId = club.ClubTypeId,
ClubTypeInterests =
allExistingInterests.Select(
x => new ClubInterestsViewModel { InterestId = x.InterestId, InterestName = x.InterestName, selected = clubInterestIds.Contains(x.InterestId) }).ToArray()
};
return View(viewModel);
}
What do I need to do to stop the validation message showing on load?
Remove the NewClubInterestsViewModel model parameter from your GET method. It should be just
public ActionResult NewInterests(int id)
The first step in the model binding process is that instances of your parameters are initialized and then its properties are set based on form values, route values, query string values etc. In your case there are no values to set, so the properties of your model are their defaults, but because you have validation attributes on your properties, validation fails and errors are added to ModelState which are then displayed in the view.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I encountered a null exeception when i tried using this method and i dont know what is wrong.
Your help will be of great assistance thanks.
HttpPost
[HttpPost]
public ActionResult AddConsultation(Consultation _conmodel, int PatientId, int[] courses)
{
DataContext da = new DataContext();
if (courses != null)
{
foreach (var id in courses)
{
Symptoms course = da.Symptoms.Find(id);
_conmodel.Symptomses.Add(course);
}
}
da.Consultations.Add(_conmodel);
da.SaveChanges();
return View("Index");
}
I'm getting null exception on _conmodel.Symptomses.Add(course);
This is my view
<div class="form-group">
#Html.LabelFor(model => model.Symptomses, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.ListBox("courses")
#Html.ValidationMessageFor(model => model.Symptomses, "", new {#class = "text-danger"})
</div>
<br/>
<br/>
<hr/>
</div>
<div class="form-group">
<br/>
<hr/>
#Html.LabelFor(m => m.illness, new {#class = "col-md-2 control-label"})
<div class="col-md-10">
#Html.TextAreaFor(m => m.illness, new {rows = "4", cols = "50", htmlAttributes = new {#class = "form-control"}})
</div>
</div>
</div>
<div class="col-md-6">
<h4 class="x"></h4>
<hr/>
<div class="form-group">
#Html.LabelFor(m => m.PresribedMed, new {#class = "col-md-2 control-label"})
<div class="col-md-10">
#Html.TextAreaFor(m => m.PresribedMed, new {rows = "4", cols = "50", htmlAttributes = new {#class = "form-control"}})
</div>
<br/>
<br/>
<hr/>
</div>
<br/>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-primary" value="Add Consultation"/>
#*<button type="button" class="btn btn-primary" onclick="location.href='#Url.Action("Next", new { id = Model.UserName })';return false;"> Next</button>*#
</div>
</div>
</div>
}
</div>
<script type="text/javascript">
$("#courses").select2({
placeholder: "Please select symptoms",
maximumSelectionSize: 10,
width:300
});
</script>
_conmodel.Symptomses is probably null. Assuming Symptomses is a list, try this instead:
if (courses != null)
{
_conmodel.Symptomses = _conmodel.Symptomses ?? new List<Symptomses>();
foreach (var id in courses)
{
Symptoms course = da.Symptoms.Find(id);
_conmodel.Symptomses.Add(course);
}
}
This way, we can check if _conmodel.Symptomses is null, and if it is, instantiate it.
I am having a issue passing a variable from a controller to a view. I have created an actionresult that allows users to add meals to a restaurant menu. I need the menuID in a html action link to access the menu details page. But when I run the page ViewData["MenuID"] returns as null even though menuID has a value in the controller action result. Is there another way to send data from a controller to a view?
Create action result
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(MealviewModel model, int? menuID)
{
if (menuID == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
else
{
ViewData["MenuID"] = menuID;
if (ModelState.IsValid)
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var currentUser = manager.FindById(User.Identity.GetUserId());
var currentrestaurant = (from r in db.Restaurants
where r.UserID == currentUser.Id
select r).First<Restaurant>().id;
var currentmenu = (from m in db.Menus
where m.Restaurantid == currentrestaurant
select m).First<Menu>().Id;
var meal = new Meal() { Name = model.Name, Description = model.Description, Price = model.Price, MenuID = menuID, Catergory = model.Catergory };
db.Meals.Add(meal);
db.SaveChanges();
return RedirectToAction("Create", new { MenudID = menuID });
}
}
return View();
}
Create CSHTML Page
#model BiteWebsite.Models.MealviewModel
#using BiteWebsite.Models;
#{
ViewBag.Title = "Add Items to Your Menu";
}
<h2>Add Items to Your Menu</h2>
#using (Html.BeginForm())
{
var ID = ViewData["MenuID"];
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Catergory, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Catergory", new SelectList(new[] {"Chef Specials","Deserts","Drinks","Main Courses","Sides",
"Starters" ,"Salads"}))
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description, new { #cols = "80", #rows = "4" })
#Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Price, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Add Item" class="btn btn-default" />
<div class="btn btn-default">
#Html.ActionLink("View Menu", "Menu", "Details", new { Id = ID })
</div>
</div>
</div>
</div>
}
because you are returning a redirecttoaction. you should use tempdata or session variable to save the value in the menuid and that should hold the value when it's a redirecttoaction.
When you do a redirect you lose the contents of ViewData. TempData is preserved though, so you can use that if a redirect is a possibility. I don't know about ViewBag so you might test that.
You already are passing other values through a view model, why not make a new property in that viewmodel and pass it along to the view?