Getting a strongly typed Model from MVC3 Helper - asp.net-mvc-3

I've found a property of my helper that I think will give me access to the properties of my model, but I was hoping to get an instance of the model itself. I have a view with a strongly typed Model. One property of the model, is a collection of other models (TestModel). I would like to render each of the items in the collection in a standard way. So, my view code would look something like this.
#foreach(var testModel in #Model.Items){
#Html.DisplayViewerFor(#testModel)
}
My helper looks something like this.
public static MvcHtmlString DisplayViewerFor(this HtmlHelper<TestModel> helper, Expression<Func<TestModel>> expression, bool rightAligned = true) {
var modelData = helper.ViewData;
var prop = modelData[""];
var outterDiv = new TagBuilder("div");
outterDiv.AddCssClass(rightAligned ? "item-display-right" : "item-display");
//Create other markup using modelData here
//Would prefer to use an instance of TestModel
return new MvcHtmlString(outterDiv.ToString(TagRenderMode.EndTag));
}

It sounds like you want a value, not an expression.
Extend the non-generic HtmlHelper class and take a raw TestModel instance as a parameter.
You only need an expression tree if you want to find out the property name.

Related

How to access objects inside a List, saved in a Session. ASP.NET MVC 3

So I have this code:
var list = new List<Carrito> {
new Carrito { ProductId = producto.ID , Cantidad = 1, PrecioUnitario = producto.Precio }
};
Session["list"] = list;
return View();
Then I load the view but I don't know how to print the the content that is inside the session. Any ideas?
This is the code I use inside the view but doesn't work:
#foreach(var item in (IEnumerable<object>)Session["list"] )
{
<p>#item.ProductId</p>
}
it's as simple as reading back the value from your session varable and cast it to the original type, then do whatever you want
example:
#{
if(Session["list"]!= null)
{
var listBackFromSession = (List<Carrito>)Session["list"];
// do what you want
}
}
My recommendation is to use the more elegant way of ViewBag.
a quote from official asp.net mvc website about Viewbag:
New "ViewBag" Property
MVC 2 controllers support a ViewData property that enables you to pass
data to a view template using a late-bound dictionary API. In MVC 3,
you can also use somewhat simpler syntax with the ViewBag property to
accomplish the same purpose. For example, instead of writing
ViewData["Message"]="text", you can write ViewBag.Message="text". You
do not need to define any strongly-typed classes to use the ViewBag
property. Because it is a dynamic property, you can instead just get
or set properties and it will resolve them dynamically at run time.
Internally, ViewBag properties are stored as name/value pairs in the
ViewData dictionary. (Note: in most pre-release versions of MVC 3, the
ViewBag property was named the ViewModel property.)
Further more, This is a good article to read about the different ways you have in MVC in order to preserve data: http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications
example:
var list = new List<Carrito> {
new Carrito { ProductId = producto.ID , Cantidad = 1, PrecioUnitario = producto.Precio }
};
// use ViewBag
ViewBag.myList = list;
then inside your view, read them back like this:
var myList = (List<Carrito>)ViewBag.myList;
// your code
You're doing MVC fundamentally wrong. In MVC, Views are there only to render a model. The logic of accessing that model should be implemented in controller, or in any other place, but not in the View itself.
Thus I recommend that you simply pass your list to the view, and make your view strongly-typed by including #model List<Carrito> at the top.

Passing IEnumerable<Object> to ViewModel - Does Object need to be ViewModel?

Getting my head around MVC today and ran across the best practice of not passing a Model directly to a view. Instead, use a ViewModel.
I researched AutoMapper and plan on using it to map my ViewModels to the respective Models. And I understand that AutoMapper is smart enough to map IEnumerable to IEnumerable without a separate mapping, as long as source and dest are mapped.
But I'm a bit confused about how to handle passing an IEnumerable in my ViewModel to my view. I currently have my page working using a ViewModel that includes IEnumerable but I read that this is just as bad as passing the IEnumerable directly to the view. So do I need a separate ViewModel to hold the object which will be used in an IEnumerable property of the main ViewModel?
So where Activity is the Model in question:
public class ActivityHistoryViewModel
{
public IEnumerable<Activity> activities { get; set; }
}
do I need to create ActivityViewModel and write my ActivityHistoryViewModel like this?
public class ActivityHistoryViewModel
{
public IEnumerable<ActivityViewModel> activities { get; set; }
}
Is there an easier way to do this?
Yes, this is correct. Assuming the only data your model will need is the list, then you don't really need ActivityHistoryViewModel and the view can be typed as such:
#model IEnumerable<ActivityViewModel>
your auto mapper config would look like this:
Mapper.CreateMap<Activity, ActivityViewModel>();
you would map like this:
IEnumerable<Activity> data = GetActivities();
var model = Mapper.Map<IEnumerable<Activity>, IEnumerable<ActivityViewModel>>(data);
return View(model);
And when you define ActivityViewModel you can either create a property-for-property duplicate type, or trim out the excess data you don't need (in my case it would be something like "created date", that is db generated and of no importance to users).
Or if you want to stick with ActivityHistoryViewModel to pass along more than just the list:
view type:
#model ActivityHistoryViewModel
mapping config can remain the same
map like this:
IEnumerable<Activity> data = GetActivities();
var model = new ActivityHistoryViewModel() {
someOtherProperty = "hello world!",
activities = Mapper.Map<IEnumerable<Activity>, IEnumerable<ActivityViewModel>>(data)
};
return View(model);

how to take input field prefix name in MVC3 Razor

I have ViewModel, View which uses this viewmodel and controller
in view I have input fields like this:
#Html.EditorFor(model => model.TransitApplication.ApplicationDate)
and field name is TransitApplication_ApplicationDate
I want to update some data from view in database but there is one problem
controller update source
public ActionResult Update(int id, FormCollection collection)
{
string prefix = "TransitApplication";
TransitApplication transitApplication = transitApplicationRepozitory.GetById(id);
if (transitApplication == null)
return Content("Error! Not Found!");
if (TryUpdateModel(transitApplication, prefix))
{
if (ModelState.IsValid)
{
transitApplicationRepozitory.Update(transitApplication);
transitApplicationRepozitory.Save();
return RedirectToAction("Index");
}
}
return Content("Error!");
}
I want to take prefix (TransitApplication) name programmatically and not like I have
string prefix = "TransitApplication";
some advice?
Seeing that the form prefix is built using the Class Name of the Model property, what about:
if (TryUpdateModel(transitApplication, typeof(TransitApplication).Name))
This removes your magic string - although this isn't actually the property name on the model class, but I'm guessing that if you renamed class, you'd probably want to rename the referenced property on the model too - although it is a little brittle.
The alternative is you could use something like this GetPropertyInfo method which would allow you to get the property name as a string like this var propertyInfo = GetPropertyInfo(yourModelObject, u => u.UserID); - although you don't currently have an instantiated model class in your action atm.

Is it possible to pass object as route value in mvc 3?

I'm trying to refactor some of my code and i'm wondering if it is possible something like this:
This is part of my cshtml:
<a href="#Url.Action("Vote", "Ideas", new { id = item.Idea.Id, pageMetadata = Model.PageMetadata, numberOfVotes = 2 })">
This is invoking action:
public ActionResult Vote(string id,PageMetadata pageMetadata, int numberOfVotes = 1)
And PageMetadata is my class.
When im debbuging in cshtml site pageMetadata is correct,but when action is invoking pageMetadata it's becoming to null. Do I some stupid mistake or all idea is wrong?
Thanks for any help.
Query strings are like dictionary : {key, value} pairs. Therefore you cannot pass your class objects in query strings.
But, what you can do, is to pass this the id for your model object and then use that id to load your object on server.
Right now, you are working on a wrong notion ! :-)
One other option is to serialize / deserialize the object for example:
<a href="#Url.Action("Vote", "Ideas", new { id = item.Idea.Id, pageMetadata = JsonConvert.SerializeObject(Model.PageMetadata), numberOfVotes = 2 })">
in the controller:
public ActionResult Vote(string id,string pageMetadata, int numberOfVotes = 1)
var pageMetadataObj = JsonConvert.DeserializeObject<PageMetadata>(pageMetadata)
Note: this will expose your object properties to the browser and could add significant size to the webpage depending on the number and type of objects.
You can use Html.ActionLink method :
https://www.aspsnippets.com/Articles/Pass-Send-Model-from-View-to-Controller-using-ActionLink-in-ASPNet-MVC.aspx

prepopulate Html.TextBoxFor in asp.net mvc 3

I'n new at this, so apologies if this isn't explanatory enough. I want to prepopulate a field in a form in asp.net mvc 3. This works;
#Html.TextBox("CompName", null, new { #value = ViewBag.CompName })
But when I want to prepopulate it with a value and send that value to my model, like this;
#Html.TextBoxFor(model => model.Comps.CompName, null, new { #value = ViewBag.CompName })
It won't work. Any ideas?
Thanks in advance!
So, I would suggest is to move to using viewmodels rather than the ViewBag. I made a folder in my project called ViewModels and then under there make some subfolders as appropriate where I put my various viewmodels.
If you create a viewmodel class like so:
public class MyViewModel
{
public string CompName { get; set; }
}
then in your controller action you can create one of those and populate it, maybe from some existing model pulled from a database. By setting that CompName property in the viewmodel, it'll have that value in your view. And then your view can look something like this:
#model MyNamespace.ViewModels.MyViewModel
#Html.EditorFor(model => model.CompName)
or #Html.TextBoxFor would work too.
Then back in your controller action on the post, you've got something like this:
[HttpPost]
public ActionResult MyAction(MyViewModel viewModel)
{
...
// do whatever you want with viewModel.CompName here, like persist it back
// to the DB
...
}
Might be that you use something like automapper to map your models and viewmodels but you could certainly do that manually as well, though the whole lefthand/righthand thing gets quite tedious.
Makes things much easier if you do it this way and isn't much work at all.
Update
But, if you really want to pass that value in view the ViewBag, you could do this:
In your controller action:
ViewBag.CompName = "Some Name";
Then in your view:
#Html.TextBoxFor(model =>model.Comps.CompName, new {#Value = ViewBag.CompName})
And that'll pre-populate the textbox with "Some Name".
I'd still go with the viewmodel approach, but this seems to work well enough. Hope that helps!
From your controller, if you pass a model initialized with default values using one of the View(...) method overloads that accepts a model object, these values will be used by the view when rendered. You won't need to use the #value = ... syntax.

Resources