how can pass a model to some partial view - asp.net-mvc

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());
}

Related

How to select SelectListItem inside a Razor View

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>

ASP.NET MVC view model binding: how to populate a collection of objects?

Until some days ago it was quite easy to manage model binding in my application. I had a view model, called PersonOfferDTO, containing a collection of PersonProductOfferDTO. (yes, I'm using the DTO as a view model because a view model in this case would be equal to the DTO). Here below a simplified version of PersonOfferDTO
public class PersonOfferDTO
{
[DataMember]
public Guid PersonOfferId { get; private set; }
[DataMember]
public ICollection<PersonProductOfferDTO> Offers { get; set; }
}
And here below a simplified version of PersonProductOfferDTO
public class PersonProductOfferDTO
{
[DataMember]
public Guid PersonProductOfferId { get; private set; }
[DataMember]
public Guid PersonOfferId { get; set; }
[DataMember]
public int Quantity { get; set; }
[DataMember]
public decimal UnitPrice { get; set; }
}
I was able to populate the ICollection thanks to the method shown below (HTML code).
<form method="POST" action="/Offers/AddNewPersonOffer">
<input name="PersonProductOffers.Index" value="myKey1" hidden>
<input name="PersonProductOffers[myKey1].Quantity">
<input name="PersonProductOffers[myKey1].UnitPrice">
<input name="PersonProductOffers.Index" value="myKey2" hidden>
<input name="PersonProductOffers[myKey2].Quantity">
<input name="PersonProductOffers[myKey2].UnitPrice">
</form>
But during the last days I have increased the depth of my objects tree, so now I have the following code.
public class PersonOfferDTO
{
[DataMember]
public Guid PersonOfferId { get; private set; }
[DataMember]
public ICollection<PersonOfferParagraphDTO> Paragraphs { get; set; }
}
[DataContract]
public class PersonOfferParagraphDTO
{
[DataMember]
public Guid PersonOfferParagraphId { get; set; }
[DataMember]
public ICollection<PersonProductOfferDTO> PersonProductOffers { get; set; }
}
As you can see there is now one further level between PersonOfferDTO and PersonProductOfferDTO, and I can't figure out how to perform a "multilevel binding": create a PersonOfferDTO with more PersonOfferParagraphDTO each one containing more PersonProductOfferDTO.
NOTE: I don't want to use an incremental index ([0] , [1], ....)... but a string (["myKey"])
EDIT
By request, I add the controller here below
public ActionResult AddNewPersonOffer(PersonOfferDTO offer)
{
if (!UserHasPermissions())
{
return PartialView("_forbidden");
}
var errors = OffersCRUD.AddNewPersonOffer(offer);
if(errors.Count() == 0)
{
return RedirectToAction("Index");
}
return PartialView("_errors", new ErrorsViewModel(errors));
}
If you want to populate them with your own keys, you can define your collections within your view model as a Dictionary<string, YOURCLASS>it accepts a non-integer index value.
Example view model with Dictionary:
public class ViewModelTest
{
public Dictionary<string, Class1> Values { get; set; }
}
Example class to be used in the dictionary collection:
public class Class1
{
public int MyProperty { get; set; }
public Dictionary <string, Class2> MoreValues { get; set; }
}
public class Class2
{
public int AnotherProperty { get; set; }
}
Here's a form that populates the values:
#using (Html.BeginForm())
{
<input type="text" name="Values[yourkey1].MyProperty" />
<input type="text" name="Values[yourkey1].MoreValues[anotherKey1].AnotherProperty" />
<input type="text" name="Values[yourkey2].MyProperty" />
<input type="text" name="Values[yourkey2].MoreValues[anotherKey2].AnotherProperty" />
<input type="submit" />
}
Instead of writing your input tags yourself, you can use the helper methods and enjoy intellisense, assuming that you have your view model defined within the view with the same structure defined in your action method:
#model ViewModelTest
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Values[yourkey1].MyProperty)
#Html.TextBoxFor(x => x.Values[yourkey1].MoreValues[anotherKey1].AnotherProperty)
#Html.TextBoxFor(x => x.Values[yourkey2].MyProperty)
#Html.TextBoxFor(x => x.Values[yourkey2].MoreValues[anotherKey2].AnotherProperty)
<input type="submit" />
}
You'll have to introduce a view model for this of course and not just get away with using your DTO ;).
PS: A DTO shouldn't be used as a domain model either, it's for transporting information around your layers.

MVC dropdown select (blank) option

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()" )

Pass model to controller

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" />
}

ASP .NET MVC4 Adding new items to view and model binding

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 :)

Resources