Im tryin to ceate a very simple blog. In my view i got this:
#using (Html.BeginForm("AddBlogPost", "Home")) <--Probably missing something here
{
foreach (var item in Model.BlogPost)
{
#Html.LabelFor(x=>item.Title)
#Html.TextBoxFor(x=>item.Title)
#Html.LabelFor(x=>item.Text)
#Html.TextBoxFor(x=>item.Text)
}
<input type="submit" value="Create Post" />
}
With the submit-button, im hoping to pass the two values to this controller:
public ActionResult AddBlogPost(BlogPost model)
{
BlogPost post = new BlogPost()
{
Title = model.Title,
Text = model.Text,
};
RavenSession.Store(post);
RavenSession.SaveChanges();
return RedirectToAction("Index");
}
Creating a new blogpost and saving it to the DB.
The problem is that the method receives null. Guess im missing somehting silly?
EDIT:
Im not longer passing a list of blogposts...:
#using (Html.BeginForm("AddBlogPost", "Home"))
{
#Html.LabelFor(Model.Title)
#Html.TextBoxFor(Model.Title)
#Html.LabelFor(Model.Text)
#Html.TextBoxFor(Model.Text)
<input type="submit" value="Create Post" />
}
This does not seem to be the right way...
EDIT 2: These are my two class:
public class ContentPage
{
public ContentPage()
{
Template = new RouteTemplate();
ParentReference = "";
Url = "/";
}
public string ParentReference { get; set; }
public RouteTemplate Template { get; set; }
public string Url { get; set; }
public bool ShowInMenu { get; set; }
public string Title { get; set; }
public string Id { get; set; }
public BlogPost BlogPost { get; set; }
}
Blog-class:
public class BlogPost
{
public string Title { get; set; }
public string Text { get; set; }
}
To the view I pass the COntentPage, which contains an instance of the Blog-post...I cant seem to access the blogpost in the way you are describing? Sorry for not being vlear from the start.
Bind you View with the BlogPost class and don't use foreach loop. See the following code.
#using (Html.BeginForm("AddBlogPost", "Home"))
{
#Html.LabelFor(x=>Model.Title)
#Html.TextBoxFor(x=>Model.Title)
#Html.LabelFor(x=>Model.Text)
#Html.TextBoxFor(x=>Model.Text)
<input type="submit" value="Create Post" />
}
Related
I have a Model which i want to edit (Location).This model has a field called ActivityId.I am sending an array of ActivityId-s via ViewData to the view and transform them to a SelectList.
I want the ActivityId field (long) of the Location to be set with the selected item from the dropdownlist (string) - i need a conversion done somehow from string to long before entering the Post Action of the controller.(EditConfirmed)
Models:
[Table("location")]
public partial class Location
{
public Location()
{
StoryLocation = new HashSet<StoryLocation>();
UserStoryLocation = new HashSet<UserStoryLocation>();
}
[Column("id", TypeName = "bigint(20)")]
public long Id { get; set; }
[Column("description")]
[StringLength(255)]
public string Description { get; set; }
[Column("name")]
[StringLength(255)]
public string Name { get; set; }
[Column("activity_id", TypeName = "bigint(20)")]
public long? ActivityId { get; set; }
[ForeignKey("ActivityId")]
[InverseProperty("Location")]
public Activity Activity { get; set; }
}
}
[Table("activity")]
public partial class Activity
{
public Activity()
{
Location = new HashSet<Location>();
}
[Column("activity_id", TypeName = "bigint(20)")]
public long ActivityId { get; set; }
[Column("description")]
[StringLength(255)]
public string Description { get; set; }
[Column("name")]
[StringLength(255)]
public string Name { get; set; }
[Column("type")]
[StringLength(255)]
public string Type { get; set; }
[InverseProperty("Activity")]
public ICollection<Location> Location { get; set; }
}
Controller:
[HttpGet]
public IActionResult Edit(long id = 0)
{
Location loc = this.context.Locations.Find(id);
if (loc == null)
{
return NotFound();
}
ViewData[Constants.ViewData.TActivities]=this.context.Activities
.Select(elem=>
new SelectListItem
{
Text=elem.Name,
Value=elem.ActivityId.ToString()
}
).ToList();
return View(loc);
}
View
#using AdminMVC.Models
#using AdminMVC.ConfigConstants
#using Newtonsoft.Json
#model AdminMVC.Models.Location
#{
List<SelectListItem> dropActivities=ViewData[Constants.ViewData.TActivities] as List<SelectListItem>;
}
<html>
<head>
</head>
<body>
<div id="form">
</div>
<div id="page">
#using (Html.BeginForm("Edit","Location",FormMethod.Post))
{
<div id="table">
<label>Set Location:</label>
<table border="">
#Html.DisplayFor(x=>x.Id)
<tr>
<td>#Html.DisplayNameFor(x=>x.Name)</td>
<td>#Html.EditorFor(x=>x.Name)</td>
</tr>
<tr>
<td>#Html.DisplayNameFor(x=>x.Description)</td>
<td>#Html.EditorFor(x=>x.Description)</td>
</tr>
<div>
<label >Select Activity:</label>
#Html.DropDownList("Activity",dropActivities) //i need to somehow convert the selected value from the dropdown to long before the form is sent to the controller
</div>
</table>
</div>
<div id="control-panel">
<input type="submit" value="Edit">
</div>
}
</body>
</div>
</html>
Post to Controller
[HttpPost, ActionName("Edit")]
public IActionResult EditConfirmed(Location editLoc)
{
if (ModelState.IsValid)
{
this.context.Entry(editLoc).State = EntityState.Modified;
this.context.SaveChanges();
return RedirectToAction("Index");
}
return View(editLoc);
}
P.S:So far the ActivityId of the Location sent to the Post Action is null.I need it to be long.
I solved this problem using the ViewData component.I would first serialize the SelectList using NewtonSoft then i would add it to the ViewData dictionary.When rendering the view i would use the DropDownList razor Html Helper method.
Model
public class FixedLocation
{
[Column("id", TypeName = "bigint(20)")]
public long Id { get; set; }
[Column("coords")]
[StringLength(255)]
public string Coords { get; set; }
[Column("name")]
[StringLength(255)]
[Required]
public string Name { get; set; }
[Column("google_id")]
[StringLength(255)]
[Required]
public string GoogleId { get; set; }
}
Extension method for getting a List of SelectListItem
public static IEnumerable<SelectListItem> ToSelectList<T,Tkey,Tvalue>(
this IQueryable<T> myenum,
Func<T,(Tkey,Tvalue)>kvpair)
{
return myenum.Select(elem=>kvpair(elem))
.Select(tuple=>new SelectListItem{
Text=tuple.Item1.ToString(),
Value=tuple.Item2.ToString()
});
}
Controller:
public IActionResult Create()
{
Location targetLocation = new Location();
ViewData[Constants.ViewData.TFixedLocations]=
this.context.FixedLocation
.ToSelectList<FixedLocation,string,long>
(elem=>(elem.Name,elem.Id)).ToList();
return View(targetLocation);
}
View:
#using AdminMVC.Models
#model AdminMVC.Models.Location
#using AdminMVC.ConfigConstants
#{
dropFixedLocations=ViewData[Constants.ViewData.TFixedLocations] as List<SelectListItem>;
}
<div>
<label >Select FixedLocation:</label>
#Html.DropDownListFor(x=>Model.Id,dropFixedLocations)
</div>
I am using autogenerated entity model classes and than i used partial class with metadata to put validations on auto genetrated classes like below.
public class tblDepartmentCustom
{
[Key]
public int DepartmentId { get; set; }
[Required(ErrorMessage = "Department name is required")]
public string DepartmentName { get; set; }
}
[MetadataType(typeof(tblDepartmentCustom))]
public partial class tblDepartmentMaster
{
}
The original class that was generated by entity framework is given below.
public partial class tblDepartmentMaster
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public tblDepartmentMaster()
{
this.tblDesignationMasters = new HashSet<tblDesignationMaster>();
}
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<tblDesignationMaster> tblDesignationMasters { get; set; }
}
So the problem here is that whenever i try to validated model state it comes out to be true.below is the code.
#model EmployeeManager.Models.tblDepartmentCustom
#{
ViewBag.Title = "InsertDepartment";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}<div class="col-md-4">
#using (Html.BeginForm("InsertDepartment", "Departments", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<span class="error-class">#ViewBag.FoundError</span>
<br />
<label>Department Name</label>
#Html.TextBoxFor(m => m.DepartmentName, new { #class = "form-control" })
<br />
<input type="submit" class="btn btn-info" value="Add Department" />
}
</div>
And the action below.
[HttpGet]
public ActionResult InsertDepartment()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("InsertDepartment")]
public ActionResult InsertDepartmentPost()
{
using (PMSEntities dc = new PMSEntities())
{
tblDepartmentMaster dm = new tblDepartmentMaster();
TryUpdateModel(dm);
if(ModelState.IsValid)
{
dc.tblDepartmentMasters.Add(dm);
dc.SaveChanges();
return View("_Success");
}
else
{
ViewBag.FoundError = "Department name is required.";
return View();
}
}
}
In order for partial classes to work, both partials must have the same namespace. You don't have to move the actual files around your file structure, just edit the namespace of tblDepartmentCustom to match that of tblDepartmentMaster.
I initially set up my dropdown with submit button which was fine but now I wanted to have it just work without the button (I added onchange). However now I find another difficulty that initially when page is displayed, if I "select" the first option, nothing happens (obviously) so I though to add "please select" option. I found couple of solutions such as writing my custom list of SelectListOptions but this seems like it could be over the top for my case. Could anyone shed some light here and let me know what would be the easiest option here? Sorry if it is simple answer I am really stuck. Here is my code:
Model
public class SurveyDropdownModel
{
public SelectList selectSurveys { get; set; }
public string selectedId { get; set; }
public IEnumerable<RespondentModel> respondents { get; set; }
public SurveyDropdownModel(List<SurveyModel> surveys)
{
selectSurveys = new SelectList(surveys, "SurveyID", "SurveyTitle");
respondents = null;
}
}
public class SurveyModel
{
[Required]
[Display(Name = "Survey ID")]
public int SurveyID { get; set; }
[Display(Name = "Title")]
public string SurveyTitle { get; set; }
[Display(Name = "Updated")]
public DateTime SurveyUpdatedDate { get; set; }
[Display(Name = "Active")]
bool IsActive { get; set; }
}
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
HealthCheckDataLayer.HealthCheckRepository repo = new HealthCheckRepository(connectionString);
List<SurveyModel> surveyList = repo.ReturnSurveys<SurveyModel>();
var model = new SurveyDropdownModel(surveyList);
return View(model);
}
[HttpPost]
public ActionResult Index(SurveyDropdownModel model)
{
//not important here
}
}
View
#model HealthCheckWebApp.Models.SurveyDropdownModel
#{
ViewBag.Title = "Home Page";
}
<div class="row">
<div class="col-md-4">
<h4>Select product:</h4>
#using (Html.BeginForm("Index", "Home"))
{
#Html.DropDownList("selectedId", Model.selectSurveys, new { onchange = "this.form.submit()" })
}
</div>
</div>
<br />
<br />
#if(Model.respondents!=null)
{
#* not relevant here*#
}
I guess now that I didn't include how do I pull my list , I am calling a stored procedure from my repository there (It's required to do it with SP).
Thanks.
Use #Html.DropDownListFor. Here is a description.
Usage:
#Html.DropDownListFor(x=> x.selectedId, Model.selectSurveys, "Select something", new { onchange = "this.form.submit()" )
i have a page that contains 3 partial views.
...
.
.
#Html.Action("one" , "Home")
#Html.Action("two" , "Home")
#Html.Action("three" , "Home")
.
.
.
i have 5 table in data base.and some of them have relation.some fields of these table should be filled in partial ONE,some should be filled in partial TWO,and ...
i make a class of combination this 5 table.
public class ViewModelX
{
public Nullable<long> id_sport { get; set; }
public Nullable<long> id_city { get; set; }
public Nullable<long> id_spend { get; set; }
public Nullable<long> id_profile { get; set; }
public Nullable<int> cost { get; set; }
public Nullable<long> idFactor { get; set; }
public Nullable<long> Idpage { get; set; }
public string username { get; set; }
public string Namestar { get; set; }
public string Lnamestar { get; set; }
public string Tell { get; set; }
public string cell { get; set; }
public string Address { get; set; }
public string Code { get; set; }
public string username_s { get; set; }
public Nullable<long> id_s { get; set; }
public Nullable<long> id_mark{ get; set; }
}
now i should pass this model to every partial?
and i should pass it to my basic page that contains this 3 partial views too?
You should not Pass the Model(associated with your Business Layer) to you View.
Your opinion might comes simply from a desire to write/maintain less code. So, It is obvious why creating new view models all of the
time will lead to more code.
Reasons to Use a View Model when it makes sense (and this has happened to me), this allows you to validate your view model
differently than your model for attribute-based validation scenarios.
View model objects can be used to help shape and format data. Need a date or money value formatted a particular way? You can do that in
the view, in the controller, or in the view model. If all you are
doing is formatting and such, you can make a case that the view model
is the best place to do it.
By using a view model you have a good mechanism to flatten out and simplify what the view deals with. This will also filter down what can
be seen in intellisense, so if you have different people developing
the models than those working on the views, creating a simple view
model can make it much easier for those just dealing with the UI.
Conslusion : View Model should contain only those properties that are required for it's corresponding View.
Reference
View Models
public class PartialViewModel1
{
[Display(Name = "Name")]
public String Name { get; set; }
}
public class PartialViewModel2
{
[Display(Name = "id")]
public int id { get; set; }
}
public class PartialViewModel3
{
[Display(Name = "DOB")]
public DateTime DOB { get; set; }
}
Controller Action Methods
[HttpGet]
public PartialViewResult PartialView1()
{
return PartialView(new PartialViewModel1());
}
[HttpGet]
public PartialViewResult PartialView2()
{
return PartialView(new PartialViewModel2());
}
[HttpGet]
public PartialViewResult PartialView3()
{
return PartialView(new PartialViewModel3());
}
Partial Views - 1
#model Practise.Controllers.PartialViewModel1
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.EditorForModel();
<input type="submit" name="Submit" value="Submit" />
}
Partial Views - 2
#model Practise.Controllers.PartialViewModel2
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.EditorForModel();
<input type="submit" name="Submit" value="Submit" />
}
Partial Views - 3
#model Practise.Controllers.PartialViewModel3
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.EditorForModel();
<input type="submit" name="Submit" value="Submit" />
}
View
#Html.Action("PartialView1", "Account", new { area = "AreaName" })
#Html.Action("PartialView2", "Account", new { area = "AreaName" })
#Html.Action("PartialView3", "Account", new { area = "AreaName" })
I had your problem before .
If your partial view should get some data use #Html.RenderAction() like below:
Your Partial view (_theLastPost.cshtml) :
#model IEnumerable<test1.Models.Post>
#foreach (var item in Model)
{
<h2>
#item.Title
</h2>
<p>
#item.Content
</p>
}
In your Index.cshtml embed partial view :
#{ Html.RenderAction("_theLastPost"); }
And you should have a controller with same name of partial view like below :
public PartialViewResult _theLastPost()
{
var a = (from c in db.Posts
orderby c.ID_Post descending
select c);
return PartialView(a.ToList());
}
I create a website for my wife. She's a teacher and she would like to have a possibility to create exercises for their students. The case is that she would like to create for instance the following exercise:
Exercise 1: Fill the sentence using a correct word:
My wife is 30 ............. old
I live in this city for 30 .........
I have the following model:
public class Exercise
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ExerciseType Type { get; set; }
public DifficulityLevel DifficulityLevel { get; set; }
public List<ExerciseItem> Items { get; set; }
public DateTime TimeOfCreation { get; set; }
public DateTime TimeOfModification { get; set; }
}
public class ExerciseItem
{
[Key]
public Guid Id { get; set; }
public string Content { get; set; }
public List<ExerciseItemOption> Options { get; set; }
public ExerciseItemOption CorrectSelection { get; set; }
}
I creates a View for my Exercise. I can fill in the basic properties like Name, Description, Difficulity Level and Type. Then I would like to create a button "Add exercise item". When clicked, a partial view (or something else) should be added dynamically where new ExerciseItem can be provided.
I've tried to following:
I've added a button
#Ajax.ActionLink("Add exercise item",
"AddExerciseItem",
"Exercise", new AjaxOptions() { HttpMethod="GET", InsertionMode = InsertionMode.InsertBefore, UpdateTargetId="ExerciseItems"})
and the appropriate div:
<div id="ExerciseItems"></div>
My action method looks as follows:
public ActionResult AddExerciseItem()
{
return PartialView("ExerciseItem", new ExerciseItem());
}
and the partial view:
#model ElangWeb.Models.ExerciseItem
<fieldset>
<legend>ExerciseItem</legend>
#Html.HiddenFor(model => model.Id)
<div class="editor-label">
#Html.DisplayNameFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content, new { style = "width:200px" })
</div>
</fieldset>
It works fine. However when I click button for creating a whole exercise, I do not have ExerciseItem collection in my model:
public ActionResult Create(Exercise exercise)
{
using (PersistanceManager pm = new PersistanceManager())
{
exercise.Id = Guid.NewGuid();
exercise.TimeOfCreation = DateTime.Now;
exercise.TimeOfModification = DateTime.Now;
pm.ExcerciseRepository.Add(exercise);
}
return RedirectToAction("Index");
}
How should I change the code in order to bind my list of added ExerciseItem objects to my model Exercise?
Check out this article about model binding. You basically need to create special names for the exercise items so that they get bound correctly.
e.g. partial:
#model ElangWeb.Models.ExerciseItem
<fieldset>
<legend>ExerciseItem</legend>
<label>content</label>
<input type="hidden" name="ExcersiseItem.Index" value="SomeUniqueValueForThisItem" />
<input type="text" name="ExcersiseItem[SomeUniqueValueForThisItem].Name" value="#Model.Content" />
</fieldset>
You can also look at my answer to this question MVC3 Non-Sequential Indices and DefaultModelBinder. Thanks Yarx for finding it, I was actually trying to find it :)