Using a model with a dynamic model in MVC4 - asp.net-mvc

I am a front end developer and not very strong with MVC 4, so I apologise if this is a very stupid question.
I am attempting to modify a view I have inherited - I have copied a dynamic model into a page that has a model already - I know that you cannot have 2 models declared, so how should I modify the below?
#model MvcSiteMapProvider.Web.Html.Models.SiteMapNodeModel
#using System.Web.Mvc.Html
#using MvcSiteMapProvider.Web.Html.Models
#using Project.RealTime.LookupService;
#using Project.RealTime.Models;
#model dynamic
#{
SessionVars session = new SessionVars();
Account account = null;
if ((Model != null) && (Model is Account))
{
account = (Account)Model;
}
What is the best way to combine the model and the dynamic model so I can use both in this view?

Try to leave just #model dynamic and delete #model MvcSiteMapProvider.Web.Html.Models.SiteMapNodeModel.
But it will be better to have two separate views with strongly-typed models. Because it helps you to identify some errors at compile time and have intellisense on view.
If you need Account in our view - maybe you should review your ViewModel and add Account to it.

Include the dynamic data you want into the model. A model should usually not be a certain data class but rather a class that is a collection of the data to be used in your view.
For example
public class ControllerActionViewModel
{
public FooClass Foo;
public dynamic Foo2;
}
and then
#model Project.Models.ControllerActionViewModel
#Model.Foo2.whatever

Since you can only have one Model in the View, the best option is to modify the Model so that it includes the information in your new dynamic model.
You have two good options:
-Edit the existing Model class and add the properties
-Or inherit the existing Model:
public class MyNamespace.MyNewModel : MvcSiteMapProvider.Web.Html.Models.SiteMapNodeModel
{
public string Property1 { get; set; }
/* .... */
}
And in your View only reference the new View Model:
#model MyNamespace.MyNewModel

The easiest way to do that is using the ViewBag for the dyanmic part. ViewBag is a dynamic object which is available in both the controller and the template. If you add a property in the controller, it will be available in the template.
In the controller:
ViewBag.Title="Our house in the middle of a street";
In the template:
<h1>#Viewbag.Title</h1>
If you the model is already available, just pass it as a property of ViewBag:
ViewBag.SecondModel=myExistingModel;

Related

Passing data from the controller to the view in asp.net

I'm currently developping a website on asp.net MVC 4.
I'm a bit confused about the different ways to pass data from the controller to the view.
First of all, if we have a list of objects users, what's the difference between passing this list to the view using:
return View(users);
and
ViewBag.users = users;
My other question is about the first solution.
If we use this solution, do we have to use this
#model IEnumerable<mydb.users>
in the View?
Or could we use for instance
#model IEnumerable<mydb.registrations>
I know it would be odd to use a different model in the view than what we've used in the controller, but VS doesn't seem to be bothered.
Thanls a lot for you answers
You can pass parameters as you want, but the best way is to make your own "view model" for each view.
public class UsersViewModel
{
public IEnumerable<UserViewModel> Users { get; set; }
public int UserCount { get; set; }
}
Then pass this view model back to the view:
var viewModel = new UsersViewModel();
// ...
return View(viewModel);
You can use Automapper tool to automatically convert your entities to viewmodels and back. It will look like this:
// in Global.asax.cs on Application_Start
Mapper.CreateMap<User, UserViewModel>();
Mapper.CreateMap<IEnumerable<User>, UsersViewModel>();
// in your action
var viewModel = Mapper.Map<UsersViewModel>(mydb.users);
Your view model will be created automatically, check automapper docs for more info. Good examples on Automapper usage are available in RacoonBlog.
ViewBag is a container. You can pass anything to the View using the ViewBag say it a string or class or whatever. You can use any no of ViewBags to pass to view from controller.
return View(users); here you have the list there and you can pass only one object as model from controller to view.
The reply to the second question you can receive the object Model to View using #model where we use the reference to a Object in particular which is generic. The controller helps in identifying what is being passed to the view. You can use it in further coding using Model in your View. ex: Model.Users

Custom Class in Razor View?

Within my Controller I have a class called "ObjectData" that contains an ID and a string:
public class ObjectData
{
public int ObjectId { get; set; }
public string Name { get; set; }
}
I'm trying to pass a List of these to the view via ViewBag, but I don't know how to loop through the items in the array since the classtype isn't normal. I'm doing it this way because I don't want to pass a bunch of Objects and their data to the view, when I only need the ID and Name (is this a valid concern?).
I'm thinking of looping through like this:
foreach (ObjectData i in ViewBag.ParentSetIds)
{
#Html.ActionLink(i.Name, "Detail", new { objectId = i.ObjectId }, null)
}
But Razor doesn't recognize that class type. How can this be accomplished?
You must fully qualify your typename on the line:
foreach (Put.Your.Namespaces.Here.ObjectData i in ViewBag.ParentSetIds)
Razor do not use the same using declaration as your controllers. You may use web.config in the View directory to add such namespaces not to fully qualify it everytime.
Regarding the question if you should be concerned about passing such objects to view. No, there is no need to worry about it. I suggest to move the object ObjectData from controller to the folder next to the controllers folder named ModelView or ViewModel and create the class here. This is something like publicly accepted "hack" to have models which represents just another view on some "real" model. It is same like when you generate MVC3 project it creates for you file AccountModels.cs which contains exactly the same kind of models. But you find it in Model folder, while it may be discussed if it should be rather in ViewModel folder. Also, pass this data as Model not as the part ViewBag if it is not really just helping data.
You could use:
foreach (var i in ViewBag.ParentSetIds)
And let the compiler determine the namespace based on the ViewBag.ParentSetIds
Within my Controller I have a class called "ObjectData" that contains
an ID and a string:
Wait, what? Why do you have a class in your controller?
I'm trying to pass a List of these to the view via ViewBag,
Just use a view model. If you are, you can make List<ObjectData> part of it. In your controller, you load up that list (lets call it ObjectDataList), and send it to your view.
In the view (razor), you'd have something like:
#model MyProject.MyModel
#foreach(var i in Model.ObjectDataList)
{
#Html.ActionLink(i.Name, "Detail", new { objectId = i.ObjectId }, null)
}
Edit:
For clarification, your view model could be:
public class MyModel
{
public string Title {get;set;}
public List<ObjectData> ObjectDataList {get;set;}
}

MVC sending data from View to Controller

I am quite new to MVC 3.
I know how to send a strongly typed object from a Controller to a View. What I have now, is a View which contains a table/form which consists of that data.
The user can change that data whilst they're are in that View (html page).
When they click on "Save", how do I send the data from the View back to the Controller so that I can update my database.
Do I overload the Controller method so that it accepts a parameter of the model type? Can you please provide some source code.
(Please do not show code of persisting data to a database, I know how to do that part).
Thank you very much for helping me.
I would also prefer using #Html.BeginForm()
I like creating an action method made for my post data. So let's say you have a UserViewModel:
public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Then a UserController:
public class UserController
{
[HttpGet]
public ActionResult Edit(int id)
{
// Create your UserViewModel with the passed in Id. Get stuff from the db, etc...
var userViewModel = new UserViewModel();
// ...
return View(userViewModel);
}
[HttpPost]
public ActionResult Edit(UserViewModel userViewModel)
{
// This is the post method. MVC will bind the data from your
// view's form and put that data in the UserViewModel that is sent
// to this method.
// Validate the data and save to the database.
// Redirect to where the user needs to be.
}
}
I'm assuming you have a form in your view already. You'll want to make sure that the form posts the data to the correct action method. In my example, you'd create the form like so:
#model UserViewModel
#using (Html.BeginForm("Edit", "User", FormMethod.Post))
{
#Html.TextBoxFor(m => m.Name)
#Html.HiddenFor(m => m.Id)
}
The key to all this is the model binding that MVC does. Make use of the HTML helpers, like the Html.TextBoxFor I used. Also, you'll notice the top line of the view code I added. The #model tells the view you'll be sending it a UserViewModel. Let the engine do work for you.
Edit: Good call, did that all in Notepad, forgot a HiddenFor for the Id!
In MVC, the act of scraping out data from POST or GET HttpRequests is referred to as Model Binding - there are plenty of SO questions relating to this.
Out of the box, MVC will bind your Get and Post variables based on convention, e.g. a form field with the name 'FormName' will be bound back to a parameter on your controller with the same name.
Model binding also works for objects - MVC will instantiate an object for your controller, and set the properties with the same name as your form.

How to send model object in Html.RenderAction (MVC3)

I'm using MVC3 razor, and I'm trying to pass an object to a partial view, and it's not working.
This works fine without sending the object model to the partial view:
Html.RenderAction("Index", "ViewName");
Trying this doesn't sent the model object, i'm getting nulls instead (the object has data, and the view expects it):'
Html.RenderAction("Index", "ViewName", objectModel);
Is this even possible using RenderAction?
Thanks!
Edit: I found the error, there was an error with the controller's action that didn't pick up the sent object. Thanks for all your help!
You can actually pass an object to a controller method using Action. This can be done on any avaialble view, for instance I have one in a shared library that gets built to project bin folders that reference my shared project (properties - Copy if newer on the view file, in Visual Studio). It is done like so:
Controller:
public class GroovyController : Controller
{
public ActionResult MyTestView(MyModel m)
{
var viewPath = #"~\bin\CommonViews\MyTestView";
return View(viewPath, m);
}
}
MVC page (using Razor syntax):
#Html.Action("MyTestView", "Groovy", new { m = Model })
or using RenderAction method:
#{ Html.RenderAction("MyTestAction", "MyTestController", new { area = "area", m = Model }); }
Note: in the #Html.Action(), the Model object must be of type MyModel and that 3rd parameter must be set to the controller variable name, of which mine is MyModel m. The m is what you must assign to, so I do m = Model.
say you want to pass foo as model, make it first
public class Foo {
public string Name { get; set; }
public int Age { get; set; }
}
now make an ActionResult
public ActionResult FooBar(Foo _foo){
return PartialView(_foo);
}
call it
#Html.RenderAction("FooBar", "Controller", new { Name = "John", Age=20 });
Usually if I have a model already available it makes more sense to use Html.Partial than trying to render an action.
#Html.Partial("Foo", Model.FooModel)
Where Foo.cshtml is a view file (perhaps in your Shared folder) strongly typed with with #model FooProject.Models.FooModel or whatever your model is called. This can be as complex a model as you need it to be. Model is your page's main model into which you must set FooModel - or just omit this parameter if the Foo view uses the same model as the parent page.
RenderAction is generally better when you have just simple parameters, because you're just simulating a request to a regular action which has routing/query string parameters - and then dumping that response into your page. It works well if you need to put something in a Layout that isn't available in your page's model such as an element in a side bar.

Making changes to MOVIE list MVC tutorial - Adding a new partial view

I am following this tutorial to learn basic MVC Movie List Tutorial in MVC I am at the end of the tutorial. Now I want to do my own modification to this tutorial. First, I want to add a new partial view to this movie list view. So in a DIV, I put the following code in the index page that already renders the movie list.
#{Html.RenderPartial("_NewPartialView");}
For this to work, first in the Models folder, I create a new model class for NewClass.cs. The model folder already has a Movie Model Class.Movie.cs
Question1 : Should I be creating a separate Model .cs file for the new partial view or Should I create additional classes in the same Movie.cs file?
Then I created a partial view using scaffolding based on the new Model (for now I have the new model in a separate .cs file - meaning I now have two Models one for Movies and one for the NewModel (for partialview). I want this rendered in the original movie list index page as a partial view on the side.
I have a MoviesController that has the code
public ViewResult Index()
{
return View(db.Movies.ToList());
}
Am I missing anything else? If I try to run this, it is breaking at the line of code
#{Html.RenderPartial("_NewPartialView");}
and the error message I get at this point of the code is "The model item passed into the dictionary is of type System.Collections.Generic.List1[Project.Models.Movie]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[Project.Models.NewModel]'.
I need some MVC expert guidance in this step of adding a new partial view based on a new model to an existing View/Model. I need help and appreciate any tid bits of information that will help me learn. Thank you
Looking at your error message your view is expecting an IEnumerable which contains classes of Project.Models.NewModel where as your passing a List containing classes of Project.Models.Movie. Basically your passing your view data it's not designed to deal with. You can either change your view/partial at the top to read something like:
#model List<Project.Models.Movie>
This sets you view to expect a list of moives which is what your passing your view from your controller in the example. On a side note
#model IEnumerable<Project.Models.Movie>
would work as well as a List inherits from IEnumerable.
If you want the view to accept an IEnumerable<Project.Models.NewModel> then you need to modify your controller to something like: (I'm making assumptions about your model properties here)
public ViewResult Index()
{
return View(db.Movies.Select(m => new NewModel { Title = m.Title, Director = m.Director}));
}
This will then pass an IEnumerable<Project.Models.NewModel> to you view.
On another note a simpler way to reference partials in razor is:
#Html.Partial("_NewPartialView")
Update
You need to create yourself a ViewModel so it will look something like this:
public class IndexViewModel
{
public List<Movie> Movies {get; set;}
public List<NewModel> NewModels {get; set;}
}
public ViewResult Index()
{
var viewModel = new IndexViewModel
{
Movies = db.Movies.ToList(),
NewModels = new List<NewModel>() // Or however you populate it
};
return View(viewModel );
}
Then in your view it will be something like this for your movies
#foreach (var moive in Model.Movies) { }
and you new model partials will be
#Html.Partial("_NewPartialView", Model.NewModels)
Note you will need to update your model at the top of the index page to reference IndexViewModel.

Resources