I am having trouble with sharing the values of my partial views across the views.
My main view:
<ul class="nav nav-tabs" style="margin-bottom: 5%;">
<li id="first" role="presentation" class="active"><a>Anschrift</a></li>
<li id="second" role="presentation"><a>Kunden Daten</a></li>
<li id="third" role="presentation"><a>Preis / Zahlung</a></li>
</ul>
#model CustomerViewModel
<div id="inhalt">
#Html.Partial("_General", Model)
</div>
The script for my view:
$("#first").click(function () {
$("#inhalt").load('#Url.Action("General", "Home")');
});
$("#second").click(function () {
$("#inhalt").load('#Url.Action("Data", "Home")');
});
#first and #second are buttons.
All views are nested inside a controller and my goal is to share the models across the partial views.
My controller:
public ActionResult Customer()
{
return View();
}
public ActionResult General(CustomerViewModel model)
{
return PartialView("~/Views/Home/_General.cshtml");
}
public ActionResult Data(CustomerViewModel model)
{
return PartialView("~/Views/Home/_Data.cshtml");
}
Customer is the main view in which the partial views are getting rendered.
A snippet from my partial view:
#model CustomerViewModel
<h1>General Partial View</h1>
#Html.TextBoxFor(model => model.Name1, new { #class = "text", placeholder = "Name 1", id = "Name1" })
Edit:
I tried the following code in order to share the model with the different views:
$("#inhalt").load('#Url.Action("Data", "Home", model)');
But this didn't seem to work because when I am debugging the controller everything in the model is null.
Explanation:
I press a list element which has an id (#first, #second..). The I want to replace the div with the id of #inhalt with my partial views. In order to do that I am using the javascript to replace the div with the partials, which all works fine. But I am not able to pass my model to the views. How do I achieve this?
Since you are passing in your model on the route (URI) you'll need to use Route Values here.
<img src="#Url.Action("DisplayData", "Home", Model.RouteValues)" alt="Image" />
As was shown in Binding the Model variable to an Action Method in ASP.NET MVC3
public class MyViewModel
{
public string Name { get; set; }
public string Surname { get; set; }
public bool IsPeriod { get; set; }
public RouteValueDictionary RouteValues
{
get
{
var rvd = new RouteValueDictionary();
rvd["name"] = Name;
rvd["surname"] = Surname;
rvd["isPeriod"] = IsPeriod;
return rvd;
}
}
}
or call directly using the Route Values
<img src="#Url.Action("DisplayData", "Home", new RouteValueDictionary(Model)" alt="Image" />
Keep in mind that because you are using the URL you can run across limits in length and the entire model may not fit, in that case you'd need to load via POST and not GET.
Related
I have a controller sending a view model consisting of a list and an object client to a view.
The view will show the list in a grid but hide the object client.
Here is the view:
#model .Business.BusinessModels.MatchesClientViewModel
#{
ViewBag.Title = "SaveClient";
}
<h2>SaveClient</h2>
<h3>
The info captured matches #Model.ClientMatches.Count()
</h3>
#using (Html.BeginForm("SaveClient", "Client", FormMethod.Post))
{
#Html.AntiForgeryToken()
WebGrid grid = new WebGrid(Model.ClientMatches);
#grid.GetHtml(columns: new[]
{
grid.Column("Name"),
grid.Column("Surname"),
grid.Column("Email"),
})
#Html.Hidden("client", Model.client)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
My action which submit button hits is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveClient(MatchesClientViewModel matchesClientViewModel)
{
*some actions*
return View();
}
However the view model sent to controller from view is null. Any idea how to properly pass the hidden part of the view model to the controller?
If you want to pass an entire object as hidden you will have to add hidden fields for every attribute of the class like this:
Let's say the model Client is something like this
public class Client
{
public string Id { get; set; }
public string SomeAttribute { get; set; }
\\ ......
}
In order to pass your values to your Action you should add to your form every property as a hidden field like this
#Html.HiddenFor(m => m.client.Id, Model.client.Id)
#Html.HiddenFor(m => m.client.Someattribute, Model.client.Someattribute)
One other way to go would be to change your model to something like this:
public class MatchesClientViewModel
{
public List<ClientMatch> ClientMatches { get; set; }
public string clientId { get; set; }
\\ .....
}
and pass your clientId only to your view and back to the controller like this
#Html.HiddenFor(m => m.clientId., Model.clientId)
Or If you do not want to change your ViewModel just add a hidden field like you did for your object for the client id and pass it as an extra parameter to the controller
#Html.HiddenFor('clientId', Model.client.Id)
and make your action like this
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveClient(MatchesClientViewModel matchesClientViewModel, string clientId)
{
*some actions*
return View();
}
I'm moving from WPF development to Asp MVC and have started doing an Asp MVC app. So far I've set up my:
model
controller
and
view(with the relevant fields.)
The next step involves sending the data entered in my form to the controller on the Submit button click.
I know in WPF I can bind the control properties to a property in the viewmodel, also there would be a click event on the button which I don't see in MVC.
This is my pseudo understanding of how to do that in MVC but correct me if I' wrong (Model is of type Case):
1.Set button click event to send form data to controller.
2.Pass data into controller constructor and assign to typed Case object.
Question:
How can you pass view values on button submit to a typed object in a controller?
Code:
View -
<form action="" method="post">
<div class="form-horizontal">
<div class="col-lg-6">
<!-- SELECT STATUS STATIC-->
<div class="form-group">
<label class="col-md-3 control-label" for="Current Status">Status</label>
<div class="col-md-8">
<select id="Status" name="Status" onchange="" class=" form-control">
<option value="Down">Down</option>
<option value="Up">Up</option>
</select>
</div>
</div>
<!-- SELECT APP STATIC-->
<div class="form-group">
<label class="col-md-3 control-label" for="App">App</label>
<div class="col-md-8" >
<select id="App" name="App" onchange="" class=" form-control">
<option value="SAP">SAP</option>
<option value="JAP">JAP</option>
</select>
</div>
</div>
<asp:Button id="b1" Text="Submit" runat="server" />
</div>
</div>
</form> <!--
Controller -
public class CaseController : Controller
{
public ActionResult Index()
{
return View();
}
}
Model -
Public class Case
{
public string Status { get; set; }
public string App { get; set; }
}
I hope that I understand your scenario well? You have a form with two drop down lists and a submit button? When you click the submit button you want to extract the selected values? This is how I understand it and this is how I will try to explain my answer with examples.
I would suggest that you bind your view/page to a view model. A view model is a kind of model that will represent your data in the view, whether it be textboxes, drop down lists, textareas, radio buttons, checkboxes, etc. It can also display static text on your view. I wrote a detailed answer as to what a view model is, if you have the time please go and read it:
What is ViewModel in MVC?
Go and create your view model. It will contain two lists that will represent your two drop down lists. Each list has an id associated with it that will contain the value of the selected drop down list item:
public class CaseViewModel
{
public int StatusId { get; set; }
public List<Status> Statuses { get; set; }
public int AppId { get; set; }
public List<App> Apps { get; set; }
}
Your domain models, namely Status and App, for the above mentioned lists:
public class Status
{
public int Id { get; set; }
public string Name { get; set; }
}
public class App
{
public int Id { get; set; }
public string Name { get; set; }
}
Now that you have this setup your next step is to populate these lists in your controller's action method. Ideally you would populate it with values from a database, but in your case I guess it is ok to hard code these values:
public ActionResult Index()
{
CaseViewModel model = new CaseViewModel();
model.Statuses = new List<Status>();
model.Statuses.Add(new Status { Id = 1, Name = "Down" });
model.Statuses.Add(new Status { Id = 2, Name = "Up" });
model.Apps = new List<App>();
model.Apps.Add(new App { Id = 1, Name = "SAP" });
model.Apps.Add(new App { Id = 2, Name = "JAP" });
return View(model);
}
As soon as you have populated your two lists, you pass the view model directly to the view. The view will receive a strongly type model and will do with it what it needs to do with it. In your case, a form will be created with two drop down lists and a submit button. I have left out all your CSS for clarity (just go and add it):
#model WebApplication_Test.Models.CaseViewModel
#using (Html.BeginForm())
{
<div>
#Html.DropDownListFor(
m => m.StatusId,
new SelectList(Model.Statuses, "Id", "Name", Model.StatusId),
"-- Select --"
)
#Html.ValidationMessageFor(m => m.StatusId)
</div>
<div>
#Html.DropDownListFor(
m => m.AppId,
new SelectList(Model.Apps, "Id", "Name", Model.AppId),
"-- Select --"
)
#Html.ValidationMessageFor(m => m.AppId)
</div>
<div>
<button type="submit">Submit</button>
</div>
}
So now you have two drop down lists populated with data. Select a value in each and press the submit button. Your view is bound to a view model and will retain values on form submission. Values in lists are not kept on form submission and will need to be populated again:
[HttpPost]
public ActionResult Index(CaseViewModel model)
{
// Check form validation
if (!ModelState.IsValid)
{
// If validation fails, rebind the lists and send the current view model back
model.Statuses = new List<Status>();
model.Statuses.Add(new Status { Id = 1, Name = "Down" });
model.Statuses.Add(new Status { Id = 2, Name = "Up" });
model.Apps = new List<App>();
model.Apps.Add(new App { Id = 1, Name = "SAP" });
model.Apps.Add(new App { Id = 2, Name = "JAP" });
return View(model);
}
// Form validation succeeds, do whatever you need to do here
return RedirectToAction("Index");
}
I hope this helps.
In the view just add a button in the form like
<button id="b1" Text="Submit"/>
In the controller add an action method to handle the post.
public class CaseController : Controller
{
[HttpPost]
public ActionResult Index(Case case)
{
//Do Something
return View();
}
public ActionResult Index()
{
return View();
}
}
You may also want to look into using Razor and strongly typed views. Makes things much simpler.
another approach is to use mvc ajax call, by doing these you also can pass parameter to controller from simple parameter to a selected row in gridview.
On the view in the button control add onclick property that point to a javascript function and passing parameter. In these sample will get selected row on the gridview
<input id="GenerateData" type="button" value="GenerateData" onclick="generateData(App.grdNameOfGridview.getRowsValues({selectedOnly:true}) [0]);" />
On the view create a javascript function that use ajax to call the controller, note the paramater that can be passing from click button event to the javascript function that will use ajax to call the controller. In this sample i use extjs framework, if you want you can also use jquery as well
generateData= function (recordData) {
var jsonStringContractUnit = JSON.stringify(recordData);
Ext.Ajax.request({
url: '../ControllerName/GenerateData',
method: 'POST',
params: {
SelectedContractUnit: jsonStringContractUnit
},
On the controller the parameter will be pass from view and will be store on SelectedData
public ActionResult GenerateData(string SelectedData)
{
}
I am new to asp.net MVC. I have a dynamic table in my project. Adding dynamic rows in table is achieved with the help of following link
Adding and deleting rows in dynamic table in Asp.net mvc razor view
I need to edit and update the dynamic table.
I have tried following code
My sample model
public class Gift
{
public string Name { get; set; }
public double Price { get; set; }
}
public class GiftViewModel
{
public string Age { get; set; }
public DateTime TheDate { get; set; }
public IEnumerable<Gift> Gifts { get; set; }
}
My sample Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(GiftViewModel model)
{
// do work here
return RedirectToAction("Index");
}
public ViewResult AddNew()
{
return View("_TimeSheetView");
}
}
My sample Partial View
#model HelloWorldMvcApp.Gift
#using (Html.BeginCollectionItem("giftList"))
{
<div>
<span class="drop_medium">
#Html.TextBoxFor(m => m.Name)
</span>
<span class = "drop_medium">
#Html.TextBoxFor(m => m.Price)
</span>
</div>
}
My sample main view
#model HelloWorldMvcApp.GiftViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Age)
#foreach (var data in Model.Gifts)
{
{ Html.RenderPartial("_TimeSheetView", data); }
}
#Html.ActionLink("Add another", "AddNew", null, new { id="addItem" })
<input type="submit" value="Save"/>
}
<script type="text/javascript">
$("#addItem").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#dynamic").append(html); }
});
return false;
});
</script>
When I click 'Add Another' button a row is added to the table. After editing the values in the table When I click submit button I receive nothing in the controller. The IEnumerable Gifts variable is null. How to take the table values to the controller. Please help me to fix this is issue. Thanks in advance
Your model's collection property is named Gifts so the partial needs to be
#model HelloWorldMvcApp.Gift
#using (Html.BeginCollectionItem("Gifts")) // not "giftlist"
{
...
}
This will generate inputs with the correct name attributes for binding to a collection (where ## is a Guid)
<input name="Gifts[##].Name" ... />
<input name="Gifts[##].Price" ... />
<input type="hidden" name="Gifts.Index" value="##" />
The problem you're facing is the name of the rendered input isnt matching your model structure. There are a couple of ways out of this:
Make an editor template for the model type
your partial view:
#model IEnumerable<HelloWorldMvcApp.Gift>
#Html.EditorForModel("","Gifts")
and an EditorTemplate for the Gift model:
#model HelloWorldMvcApp.Gift
<div>
<span class="drop_medium">
#Html.TextBoxFor(m => m.Name)
</span>
<span class = "drop_medium">
#Html.TextBoxFor(m => m.Price)
</span>
</div>
Manually create the inputs with the properly parsed name - "Gifts[x].Property"
Obviously the first option is far cleaner and imho preferred.
Hope this works, and helps :)
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>
}
how can i render multiple different actions in one call to a speccific controller?
Html.RenderAction() / Html.Action() only handles one controller&action.
But what if i want in one call to render different views on the screen?
thanks in advance,
Sagiv
EDIT:
Hi again.
I'm not sure you understood my question.
this is the cshtml:
<div id="menu">#using (Ajax.ActionLink("click me", "SomeAction","SomeController", new AjaxOptions() { HttpMethod = "POST", OnSuccess = "showMsg", OnFailure = "showError" }))</div>
<div id="div1">bla bla content</div>
....
<div id="div2">bla bla content</div>
and this is the controller:
public class SomeController : Controller
{
public ActionResult SomeAction()
{
return View("somethingfordiv1", ModelForDiv1);
return View("somethingfordiv2", ModelForDiv2); //i want also return another view here
}
}
in this ajax call on the controller, i want to return 2 different views for 2 different divs.
thanks again :)
Here's one way you could proceed. You could aggregate the two view models into a unique view model and then have the controller action return a view containing javascript which will inject the two view results into the different divs.
As always start with the view models:
public class Model1 { }
public class Model2 { }
public class AggregatedModel
{
public Model1 Model1 { get; set; }
public Model2 Model2 { get; set; }
}
Then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult SomeAction()
{
var model = new AggregatedModel
{
Model1 = new Model1(),
Model2 = new Model2()
};
Response.ContentType = "text/javascript";
return PartialView(model);
}
}
Then the corresponding ~/Views/Home/Index.cshtml view:
<div id="menu">
#Html.ActionLink("click me", "SomeAction", "Home", new { id = "clickme" })
</div>
<div id="div1">bla bla content</div>
<div id="div2">bla bla content</div>
<script type="text/javascript">
$('#clickme').click(function () {
$.getScript(this.href);
return false;
});
</script>
Next the ~/Views/Home/SomeAction.cshtml view:
#model AggregatedModel
$('#div1').html(#Html.Raw(Json.Encode(Html.Partial("Model1", Model.Model1).ToHtmlString())));
$('#div2').html(#Html.Raw(Json.Encode(Html.Partial("Model2", Model.Model2).ToHtmlString())));
and finally the two ~/Views/Home/Model1.cshtml and ~/Views/Home/Model2.cshtml views:
#model Model1
<span>This is the contents for model1</span>
and:
#model Model2
<span>This is the contents for model2</span>
If you want to render different views on the screen return a model which represents the data for those views, then you can use RenderPartial and pass the part of the model data required to each view.
You can also use viewdata to separately have this available.
Html.RenderAction is also available but simulates another full request
For your ajax request you can return a html chunk from the rendering of a partial view and this can be determined by Request.IsAjaxRequest. Then your javascript can set the result into the document.
This is in your action
if (Request.IsAjaxRequest())
{
return View("PartialViewName", partialModel);
}
return View("NormalView", normalModel);
And the client side example (using jquery)
function hijack(form) {
$("div#SearchResults").html("");
$("div#SearchResults").addClass('loading');
$.ajax({
url: form.action,
type: form.method,
dataType: "html",
data: $(form).serialize(),
success: function(data) {
$("div#SearchResults").removeClass('loading');
$("div#SearchResults").html(data);
}
});
}