How do I display all elements of a ViewModel in a view - c#

I know that you can do #Html.DisplayForModel and ValueForModel, is there anything similar the viewModel? I want to display all the property names and the property values for the elements in my viewmodel
My regualr ValueFor is not working either
Heres what I have so far...although, its not working:
#model BookStore.ViewModels.CheckOutViewModel
#using (Html.BeginForm())
{
<h2>Checkout Summary</h2>
<fieldset>
<legend>Payment Information</legend>
#Html.ValueFor(m => m.CreditCard1)<br />
#Html.ValueFor(m => m.CreditCardType1) <br />
#Html.DisplayNameFor(Model => Model.CreditCard1)
#Html.DisplayFor(Model => Model.CreditCard1)
#Html.
</fieldset>
<fieldset>
<legend>Shipping Information</legend>
#Html.ValueForModel()
</fieldset>
}
Controller Code:
public ActionResult Complete(int? id)
{
return View(id);
}
Edit: I guess my real question is how to get ANY property from my view model to show its value

You're passing an Id of the object (model) to your view instead of the model itself. You should have somthing like this in your controller:
public ActionResult Complete(int? id)
{
CheckOutViewModel model = GetModel(id);
return View(model);
}
Where GetModel is some function where you retrieve the CheckOutViewModel based on the id.

EDIT: Looking at your controller you are just returning an integer not your model
You could do something like this if you really are new to this:
public ActionResult Complete(int? id)
{
if(int != null && int != 0){ //Makes sure int isn't empty or 0
var allModelData = dataContext(); //Get all the data in your dataContext
var myModel = allModelData.FirstOrDefault(x => x.id == id); //This gets the
//model that matches the ID
CheckOutViewModel viewModel = myModel; //Populate it into your viewmodel
return View(viewModel); //Return your viewmodel
}
return View();
}
This isn't the most efficient way of doing things but will get you started with some data.
I would also recommend using Model.PropertyName as ValueFor does a simple render which ignores any templates (Equivalent of calling String.Format)
#Model.CreditCard1<br />
#Model.CreditCardType1 <br />

Related

MVC4 cshtml page function call

I need to display a value in an editable textbox on my mvc page when it first loads if it exists. I've got a function that will take care of getting the value that I need, but I need to pass in parameters from the current model to get what I need from the database.
The problem I'm having is getting this value into the textbox. What I tried was
cshtml:
#Html.TextBoxFor(model => model.AdjustedLiabilityAmount, new { #Value=OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetLatestAdjustedLiabilityAmount(Model.DOTNumber, Model.LiabilityAmount))}
I get a red squiggly that "The name 'Value' does not exist in the current context"
So I tried a different technique I read about which was like this.
Controller:
public ActionResult Index()
{
ViewBag.AdjustedValue = OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetLatestAdjustedLiabilityAmount(Model.DOTNumber, Model.LiabilityAmount);
cshtml:
#Html.TextBoxFor(model => model.AdjustedLiabilityAmount, new { #Value=ViewBag.AdjustedValue)}
This time I'm getting the red squiggly "The name 'Model' does not exist in the current context."
I'm sure I'm just missing something basic here as I'm new to MVC.
Any help is much appreciated.
Entire ActionResult Index:
public ActionResult Index()
{
ViewBag.AdjustedValue = OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetLatestAdjustedLiabilityAmount(Model.DOTNumber, Model.LiabilityAmount);
var Report = new OBS_LIB.DTO.JeopardyAssessmentReport();
Report.Stage = 1;
Report.Status = "Active";
Report.ReportItems = OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetJAReportItems(Report.Stage, Report.Status);
return View(Report);
}
You want to do something like this:
Class:
public class ModelClassHere {
public float Liability {get;set;}
}
Controller:
public ActionResult Index(ModelClassHere model) {
model.Liability = 10.00;
return View(model); // pass model to the view
}
View:
#Html.TextBoxFor(x => x.Liability) // 'x' can be anything
EDIT*
If you already have a model and need to pass one simple value:
Controller:
public ActionResult Index(ModelClassHere model, string otherValue) {
model.Liability = 10.00;
ViewBag.Liability = model.Liability;
return View(model); // pass model to the view
}
View:
<input type="text" id="otherValue" name="otherValue" value="#ViewBag.Liability.ToString()" />
You can use
#Html.TextBox("AdjustedLiabilityAmount", (Decimal)ViewBag.AdjustedValue)}
Or
#Html.TextBox("AdjustedLiabilityAmount", Model.AdjustedLiabilityAmount == null ? (Decimal)ViewBag.AdjustedValue : Model.AdjustedLiabilityAmount)}
In decimal type you put your the type that you need.
You need to pass your model in the
Controller
return view(myModelName);
make sure you have access to it in your controller.
also your view has to reference the model in the #model line at the top.
Finally to call the model it would be
view:
Model.myModelName

MVC Partial View with List Model

I have a news item page and I would like to include a partial view presenting a list of the latest 5 news items. However, I get a
this dictionary requires a model item of type
'System.Collections.Generic.List
error message. I'm assuming the main view is strong typed to present a single item, whereas the partial view is strongly typed with a generic list and the two don't match.
Controller
public ActionResult NewsItem(int newsId, string newsTitle)
{
var q = _ctx.tblNews.Single(x => x.newsID == newsId);
return View(q);
}
public ActionResult NewsLatest()
{
var q = _ctx.tblNews.OrderBy(x => x.newsCreateDate)
.Where(x => x.WebsiteID == 2 && x.newsPublish).Take(5).ToList();
return View(q);
}
View (simplified)
#using MyMVC.Models
#model tblNews
<h2>#Model.newsTitle</h2>
#Html.Raw(Model.newsText)
<p>#Model.newsCreateDate</p>
#Html.RenderPartial("NewsLatest")
Partial View
#using MyMVC.Helpers
#model List<MyMVC.Models.tblNews>
<table>
#foreach (var x in Model)
{
<tr>
<td>
#Html.ActionLink(x.newsTitle, "NewsItem", new { newsId = x.newsID, newsTitle = x.newsTitle.ToSeoUrl() })<br />
<hr />
</td>
</tr>
}
</table>
I tried this in the view:
#{
Html.RenderPartial("NewsLatest", new List<tblNews> { new tblNews()});
}
but it looks like the ActionResult doesn't get fired trying i this way.
There are a few questions on SO relating to this. But I just can't get my head around the solutions. The penny isn't dropping!
Do I really have to create a view model that incorporates the news item data and the list of news items?

Update a Model and a Collection of Models on a Single View (MVC4)

I've been working on an MVC 4 Application and have run into a problem when attempting to update Models in a ViewModel.
My ViewModel (detailed below) contains one ComplexObjectOne and a List<ComplexObjectTwo>.
My GET ActionResult successfully populates the ViewModel from a database and everything displays correctly on my View.
The problem is encountered when attempting to pass the ComplexObjectOne and List<ComplexObjectTwo> to the POST ActionResult.
The ComplexObject is passed correctly but everything I've tried fails pass the List<ComplexObjectTwo> collection.
My ComplexModelOne Model
public class Test
{
public int Id {get;set;}
public string Result {get;set;}
public virtual ICollection<TestResult> TestResults {get;set;}
}
My ComplexModelTwo Model
public class TestResult
{
public int Id {get;set;}
public string Result {get;set;}
public string Comment {get;set;}
public virtual Test Test{get;set;}
}
My ViewModel
public class TestingViewModel
{
public TestingViewModel()
{
if(TestResults == null)
{
TestResults = new List<TestResult>();
}
}
public Test Test {get;set;}
public IEnumerable<TestResult> TestResults {get;set;}
}
My Edit() GET ActionResult
public ActionResult Edit(int id = 0)
{
var viewModel = new TestingViewModel();
Test test = testRepo.GetTestById(id);
var results = test.TestResults;
viewModel.Test = test;
viewModel.TestResults = results;
return View(viewModel);
}
My Edit() POST ActionResult
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(TestingViewModel model)
{
// do update - left out for brevity
}
My Edit.cshtml View
#model Namespace.Models.ViewModels.TestingViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(model => model.Test, "TestHeader")
<table>
<tr>
<th>Test</th>
<th>Result</th>
<th>Comment</th>
</tr>
#Html.EditorFor(model => model.TestResults, "TestResults")
</table>
<input type="submit" value="Update"/>
}
Within my View I do use a couple of EditorTemplates to display the property fields.
Any assistance, comments, or suggestions will be much appreciated. I'd like to be able to accomplish updating these entities on a single page instead of multiple pages which I resorted to in the Create() steps.
Thank you,
Patrick H. (stpatrck)
Replace:
#Html.EditorFor(model => model.TestResults, "TestResults")
with:
#Html.EditorFor(model => model.TestResults)
and then rename your EditorTemplates/TestResults.cshtml editor template to EditorTemplates/TestResult.cshtml (notice the missing s) and inside replace the model declaration from:
#model IEnumerable<TestResult>
to:
#model TestResult
Now obviously this will lead to getting rid of any for or foreach loops you might have written in this editor template because now ASP.NET MVC will automatically invoke the template for each element of the collection.
So for example:
#foreach (var item in Model)
{
#Html.EditorFor(x => item.SomeProperty)
}
will simply become:
#Html.EditorFor(x => x.SomeProperty)
Now look at the generated markup and notice the difference in the names of your input fields. Before you had:
<input type="text" name="item.SomeProperty" value="foo" />
and now you have:
<input type="text" name="TestResults[0].SomeProperty" value="foo" />
Now when you submit the form to the POST action the default model binder will be able to successfully bind the collection because now the naming convention is respected. You can read more about this convention in the following blog post.
Also you have circular references in your object graph which cannot be successfully serialized and model bound. You should use view models in order to break this circular dependency.

Displaying Partial View in a View and Passing Arguments

I'm trying to display two partial views in my index view. In those partial views are data grids that I want to display data when something is searched in the search box I have set up. Both of these pages work when I do them separately, but I don't know how do use them as partial views.
My View looks like this:
#using (Html.BeginForm("Index", "Home", "POST"))
{
<div class="searchField">
<div class="searchbox">
Search: <input type="text" name="heatSearch" />
<input type="submit" value="Submit">
</div>
</div>
}
<div>
#Html.Partial("PartialChemAnalysis", (string)ViewBag.SearchKey)
</div>
#Html.Partial("PartialSlag", (string)ViewBag.SearchKey)
My Controller looks like this:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string heatSearch)
{
ViewBag.SearchKey = heatSearch;
return View();
}
public ActionResult PartialChemAnalysis(string heatSearch)
{
HomeModel C = new HomeModel();
IEnumerable<HomeModel> model = C.ChemList;
C.ChemistryDataPull(heatSearch);
return PartialView(C.ChemList);
}
public ActionResult PartialSlagView(string heatSearch)
{
PartialSlagViewModel D = new PartialSlagViewModel();
IEnumerable<PartialSlagViewModel> model = D.SlagList;
D.SlagViewDataPull(heatSearch);
return PartialView(D.SlagList);
}
Ideally what's in that search box would be passed to both views and the grids would form based on that. I'm not sure what I'm doing wrong so any help is appreciated.
I would start with this:
#{
//create your first model
HomeModel CModel = new HomeModel();
CModel.ChemistryDataPull(Model.SearchValue);
//create your other model
PartialSlagViewModel DModel = new PartialSlagViewModel();
DModel.SlagViewDataPull(Model.SearchValue);
}
#Html.Partial("PartialAnalysis", CModel)
#Html.Partial("PartialSlag", DModel)
This is assuming you've already searched, processed a postback, and you've returned the SearchValue back to your view in your model. You could return it in ViewBag.SearchValue instead I suppose and replace Model.SearchValue with ViewBag.SearchValue, but your model would be a better place to store it.
If I were you, I post it to another method.
#using (Html.BeginForm("Index", "Home", "POST"))
{
<div class="searchField">
<div class="searchbox">
Search: <input type="text" name="Search" />
<input type="submit" value="Submit">
</div>
</div>
}
#Html.Partial("PartialAnalysis", (string)ViewBag.SearchKey)
#Html.Partial("PartialSlag", (string)ViewBag.SearchKey)
//In Home Controller
[HttpPost]
public ActionResult Index(string Search)
{
ViewBag.SearchKey = Search;
return View();
}
Partial views do not require a controller action. The presence of a controller action will actually make it into a view.
In your #Html.Partial call you want to pass a view model for the view to consume. This is where you'd want to put the data for your grid, searched by whatever keywords, sorted, prepped and ready to render.
This can either be an entirely different view model you've created that is dedicated to supporting your partial view, exposed as a property in the parent page's view model, or simply an IEnumerable property in the parent page's view model that has the data (I prefer the first approach btw; it's heavier code-wise but preserves encapsulation better).
To wrap it all up, your controller looks like:
public class HomeController : Controller
{
public ActionResult Index(string search)
{
return View(new IndexViewModel(search));
}
}
Your view model looks like:
public class IndexViewModel
{
private string _search;
public IndexViewModel(string search)
{
_search = search;
}
public AnalysisViewModel AnalysisViewModel
{
get
{
return new AnalysisViewModel(_search);
}
}
public SlagViewModel SlagViewModel
{
get
{
return new SlagViewModel(_search);
}
}
}
and your view for showing the partials looks like
#Html.Partial("PartialAnalysis", Model.AnalysisViewModel)
#Html.Partial("PartialSlag", Model.SlagViewModel)
I needed to change my partial view calls in my view to:
#if(ViewBag.SearchKey != null)
{
<div>
#Html.Action("PartialChemAnalysis", "Home", (string)ViewBag.SearchKey)
</div>
<div>
#Html.Action("PartialSlagView", "Home", (string)ViewBag.SearchKey)
</div>
}

MVC3, Get updated form data from a list

I have a strongly-typed view, with a list of custom objects in the model.
In the view I display textboxes for every object in the list :
#using (Html.BeginForm("SaveData", "Localization", FormMethod.Post))
{
foreach (YB.LocalizationGlobalText m in Model.GlobalTexts)
{
#Html.Label(m.LocalizationGlobal.Name)
#Html.TextBoxFor(model => m.Text)
<br />
}
<input type="submit" value="Save" />
}
Now how would I get the updated data from the textboxes in my model.
I can see in the formcollection the updated data is there:
[HttpPost]
public virtual ActionResult SaveData(FormCollection form)
{
// Get movie to update
return View();
}
form["m.Text"] = "testnewdata1,testnewdata"
But how do I get this mapped to the model, so I have the updated values for each object.
Or how can I get it cleanly from the formcollection, something like this .. form[someid]["m.Text"]
Edit:
I also tried passing the model as a parameter, but the model data is empty.
[HttpPost]
public virtual ActionResult SaveData(LocalizationModel model, FormCollection form)
{
// Get movie to update
return View();
}
When I look into the model: model.GlobalTexts = null
[HttpPost]
public virtual ActionResult SaveData(int movieId, FormCollection form)
{
// Get movie to update
Movie movie = db.Movies.Where(x => x.Id == movieId);
// Update movie object with values from form collection.
TryUpdateModel(movie, form);
// Do model validation
if (!ModelState.IsValid)
return View();
return View("success");
}
Edit See this question I asked a while back: How to use multiple form elements in ASP.NET MVC
Lets say you have a view like this:
#model IEnumerable<CustomObject>
#foreach (CustomObject customObject in Model)
{
<div>
#Html.TextBox(customObject.CustomProperty);
<!-- etc etc etc -->
</div>
}
Refactor it like this:
#model IEnumerable<CustomObject>
#for (int count = 0; count < Model.Count(); count++)
{
<div>
<!-- Add a place for the id to be stored. -->
#Html.HiddenFor(x => x[count].Id);
#Html.TextBoxFor(x => x[count].CustomProperty);
<!-- etc etc etc -->
</div>
}
Now in your action method do this:
public virtual ActionResult SaveData(IEnumerable<CustomObject>)
{
// You now have a list of custom objects with their IDs intact.
}
It's even easier than that if you use editors, but I'll let you figure those out for yourself as they are super simple. The accepted answer in the question I linked shows an example.
NOTE: you can substitute IList for IEnumerable if you need to.
If I understand your question correctly, you can simply use your viewmodel as a parameter of SaveData, and it will map it automatically:
[HttpPost]
public virtual ActionResult SaveData(ViewModelType viewmodel)
{
// Get movie to update
return View();
}

Categories

Resources