Can a Partial View and Parent View have two different View Models?
For instance, a partial view may have a dropdownlist specific to that model and a parent view may have another model for some other entities.
Yes, the partial and parent views can have two different view models.
The partial view has to get it's viewModel from somewhere though, so this could either be just creating it straight from the view
Parent View
#{
var partialViewModel = new SomeOtherModel()
{
PartialName = Model.Name,
SomeProperty = SomeOtherVariable
};
Html.Partial("_MyPartialView", partialViewModel);
}
Or a more common method is the Partial ViewModel is a property of the parent ViewModel
#Html.Partial("_MyPartialView", Model.PartialViewModel)
There are other ways too, but these are fairly common ones you see.
If you call Partial view from the Parent view, the viewModel will be in a way subset of the ViewModel of the parent. You can have different ViewModels for Parent and Partial views.
Related
I have a view "Register Application", containing 20 fields. The user registers. After user registered I have an option for user to update components that were submitted.
for example: view Register has sections "Contact Information" , "Address Information" ...etc currently have 5 sections.
so in the Register view I create a viewmodel #model ViewModels.RegisterVMwith all the fields.
and for edit contact information, I have its own #model ViewModels.ContactInformationVM
Now, here is my question since both views will have the same markup code I decided to create a partial view for Contact Information so I can reuse the markup code and will be able to manage it in one place instead of two places.
So in the Register view
#model ViewModels.RegisterVM
.......
#Html.Partial("~/Views/Shared/widget/_ContactInformation.cshtml", #Model)
and in the Contact Information view I want to reuse this partial view
#model ViewModels.ContactInformationVM`
#Html.Partial("~/Views/Shared/widget/_ContactInformation.cshtml", #Model)
Both views have its own viewmodel and the partial view will only be able to accept one viewmodel
No idea what viewmodel I should declare in the partial view
I know I can just copy the code from the partial view and place in the Register view and in the Contact Information view and it would work and solve the issue.. but was wondering if there a better approach to avoid having same code in multiple files.
I hope it makes sense what I am asking. Thanks for reading.
What you want to do here is create a composite view model that has each section as a separate property. For example:
public class RegisterVM
{
public ContactInformationVM ContactInformation { get; set; }
public AddressInformationVM AddressInformation { get; set; }
...
}
Then in your partial(s), you reference the sub-model:
_ContactInformation.cshtml
#model ViewModels.ContactInformationVM
<!-- contact info fields here, for example: -->
#Html.EditorFor(m => m.FirstName)
...
Then, in your register view, you use RegisterVM as your model and load the partials for each section:
#model ViewModels.RegisterVM
#Html.Partial("_ContactInformation", Model.ContactInformation)
#Html.Partial("_AddressInformation", Model.AddressInformation)
...
Now, you can reuse these components at will.
How do I post from one controller into another view?
I have a Review model and a Product model. The Review form is displayed in the Product view through a widget, but how do I submit the form itself? Right now, it doesn't do anything. I can submit through review/create, but not through the Product View.
Or am i suppose to do the post in the widget?
You can achieve it if you put code like below on components/ReviewWidget.php . I supposed you have Review as model and its respective controller and views file on default locations.
<?php
class ReviewWidget extends CWidget{
public function init() {
return parent::init();
}
public function run(){
$model = new Review;
if (isset($_POST['Review'])) {
$model->attributes = $_POST['Review'];
$model->save();
}
$this->renderFile(Yii::getPathOfAlias('application.views.review'). '/_form.php',array(
'model' => $model,
));
}
}
Then, call above widget on any where on view like below ,
<?php $this->widget('ReviewWidget'); ?>
It will handle item creation only. You have to create code to item update by yourself.
In your controller action you must use function renderPartial
$this->renderPartial('//views/reviw/_form',array('data' => $data ) );
First argument of this function is used to determine which view to use:
absolute view within a module: the view name starts with a single slash '/'. In this case, the view will be searched for under the
currently active module's view path. If there is no active module,
the view will be searched for under the application's view path.
absolute view within the application: the view name starts with double slashes '//'. In this case, the view will be searched for
under the application's view path. This syntax has been available
since version 1.1.3.
aliased view: the view name contains dots and refers to a path alias. The view file is determined by calling
YiiBase::getPathOfAlias(). Note that aliased views cannot be themed
because they can refer to a view file located at arbitrary places.
relative view: otherwise. Relative views will be searched for under the currently active controller's view path.
Also you can use this function in your views. But the most convenient way to reuse views is to create widgets.
How to set the Label Text which is available on _Layout.cstml from different Controller.
For Example
If I want to navigate from Dashboard to ProductList Page. Then My Label Text on _Layout Page should be "Product List". which I am setting from ProductList Controller Index Method.
Thanks in advance.
Use the ViewBag.xyz in _Layout.cshtml. Pass the viewdata from controller action and it will be shown on your html page.
Note:- Please confirm me if you means something else. I will update my answer if this doesn't means what you looking for.
it's look like you want to set the ViewBag.Xyz different different for every controller.
I recommanded you to use ActionFilterAttribute to make it work. The code will something like this.
public class DashboardCustomData : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewBag.xyz = "This is my Dashboard page";
base.OnActionExecuting(filterContext);
}
}
Now put this Actionfilter to every controller. You need to use different different ActionFilter for every controller which have different title. After doing this you never need to set it manually from every controller.
If you don't like to write the multiple filter then try this one.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controllerName = filterContext.RouteData.Values["Controller"].ToString();
string ActionName = filterContext.RouteData.Values["Action"].ToString();
if (controllerName == "Dashboard")
{
filterContext.Controller.ViewBag.xyz = "This is my Dashboard page";
}
else
{
}
base.OnActionExecuting(filterContext);
}
You make BaseViewModel class with that prop, set _Layout's model as this type and derive other models from it. Now you can access that prop from any derived model
You use ViewBag or ViewData
You make a #section in Layout view and populate it within Controller's views
If you need Layout's fields in many controllers then usage of #1 looks preferred.
Why does not use this simple approach:
#{
ViewBag.Name = "...";
Layout = "_Layout.cstml";
}
And in your layout set your lable text with #ViewBag.Name
Layout
<label>#ViewBag.Label</label>
Then just assign a value to ViewBag.Label in your controllers, and it will automatically change.
public ActionResult OtherPage()
{
ViewBag.Label = "Other Label";
}
Solution you have suggested works when I am on the same Controllers View but here I want to Change the Text of Controller on Master Page.
In Asp.net We use Master Page Reference on Child Page then we can
easily Change the Text, but how do i do same in MVC... Hope you
understood the scenario. –
If you look at what is generated when you start a new project with the "Internet Template" in MVC 4, you have a way to do it already working for you:
In the element of _Layout, look for <title>#ViewBag.Title - My ASP.NET MVC Application</title>, then in all the different views, you have something like this:
#{
ViewBag.Title = "Contact";
}
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
<h2>#ViewBag.Message</h2>
</hgroup>
All you need to do is to move/duplicate ViewBag.Title out of the HEAD intot the BODY, or create your own ViewBag variable, and set it's values from your different views. Obviously you could just as well set the value from the controller, but I don't see the need, as this really has to do exclusively with the user interface, which is the Views job.
Finally, if I may, don't try to duplicate in MVC what you're used to with ASP.NET. The paradigms are way too differents, chances are that you are going to waste time while there might be an easy MVC way to achieve the same thing.
It seems to me this is just an example of it.....
I have some issues with rendering strongly type partial view in layout view.
partial view (menu) is band with model Menu
this partial view I want to render in _layout.chtml, so it 'll be avliable in all views.
I want to make avalible the partial view(menu) in all pages/view. the problem I face is where to put the action for partial view to populate it from DB on page load.
thanks
---------------------- My code is--------------------
partial view inside shared folder.
#model List<Menu>
#foreach(var item in Model){// here is the html/model item inside to display}
--------------------------------------
HomeView.chtml inside home folder
#model List<homemodel>
.... here goes html code/ plus homemodel loop/data etc.
------------------------------
HomeController{
public ActionResult HomeView()
{
.........return view();
}
public PartialViewResult partialmenu()
{
// data from db
return partialview(partialobject as list);
}
------------------------
layoutview.chtml
--html code---
{# Html.renderpartial("partialview");}
.. html code...
I want to make available the partial view(menu) in all pages/view. the problem I face is where to put the action for partial view to populate it from DB on page load.
Write in layout: Html.RenderAction('MyMenu') OR Html.Action('MyMenu') and then populate it from any source. Your action will return strongly typed model.
where to put the action for partial view to populate it from DB on
page load.
every view has it's own controller..regardless if it is partial or not...therefore you could populate your view on it's own controller...
Here is what I'd like to do :
I have an Silverlight application using navigation frame and MEF. (like this one : http://msdn.microsoft.com/en-us/magazine/gg535672.aspx)
This application consists of a set of buttons. Each button click load a view and its associated ViewModel.
Within theses views, I've a list with items and when I click on each items it refreshs a kind of sub-view in this view.
I'd like to create a navigation system : for example myapp.aspx#view1/2, where 2 is in fact the item clicked in the list. If I click on one of the button, it would load a default item and refresh all the view, but when I click on an item, I wouldn't like to refresh all the view but only certain part of the view (I do not want to create another instance of the view and viewmodel).
My problem is in fact that I would like to get the best pratice to get a reference to an existing view or viewmodel when i'm navigating to this page that has already been loaded (for example from myapp.aspx#view1/2 to myapp.aspx#view1/3)(I plan to do this into the BeginLoad of the ContentLoader class)
If I get the viewmodel, I can do that I want by changing for example the current itemId property which could refresh the view thanks to binding.
Thanks in davance if you have something to propose.
A common approach is to use some form of Messenger to do this type of operation. The item's click could trigger the sending of a message, with the Item attached. The ViewModel in question would be a subscriber, and edit its current settings (ie: it's ItemId, which would trigger the binding refresh).
The most common implementations are usually ones similar to the Messenger service in MVVM Light.
It's fairly easy to roll your own here, though, especially since you're already using MEF. Just create a service to handle the message passing, and import it into both endpoints.
Actually, I would have prefered to use an URI to navigate in my application when I click on an item, but if I use an URI, the entire view is reloading and not the specific part I'd like to.
With the messenger, I won't be able to use navigation with url within the view, I think ? Or else I didn't really figure out what you proposed to me.
The algorithm I would like to take is :
navigate("...asp#MyView1/1")
MyView1 is current view ?
yes then I'd like to get the viewmodel of the current view and change it the ItemId property with 1
no, then the view will be created
And I'd like to implement this algorithm there : (this is the place where the view is instancied for each navigation, in my CompositionNavigationContentLoader class)
public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, object asyncState)
{
// Convert to a dummy relative Uri so we can access the host.
var relativeUri = new Uri("http://" + targetUri.OriginalString, UriKind.Absolute);
// Get the factory for the ViewModel.
var viewModelMapping = ViewModelExports.FirstOrDefault(o => o.Metadata.Key.Equals(relativeUri.Host, StringComparison.OrdinalIgnoreCase));
if (viewModelMapping == null)
throw new InvalidOperationException(
String.Format("Unable to navigate to: {0}. Could not locate the ViewModel.", targetUri.OriginalString));
// Get the factory for the View.
var viewMapping = ViewExports.FirstOrDefault(o => o.Metadata.ViewModelContract == viewModelMapping.Metadata.ViewModelContract);
if (viewMapping == null)
throw new InvalidOperationException(
String.Format("Unable to navigate to: {0}. Could not locate the View.", targetUri.OriginalString));
// Resolve both the View and the ViewModel.
var viewFactory = viewMapping.CreateExport();
var view = viewFactory.Value as Control;
var viewModelFactory = viewModelMapping.CreateExport();
var viewModel = viewModelFactory.Value as IViewModel;
// Attach ViewModel to View.
view.DataContext = viewModel;
viewModel.OnLoaded();
Thanks.