Problem: We have a Main View and a couple of partial views. Everything uses the same model as the main view. On the submit of Main view, I am trying to render a partial view and trying to pass down the model but only the properties that are getting passed down are the editable fields on the page or view. How can I pass down the other properties?
Current workaround: The partial view needs the other data too to generate a e-mail body but as it is not passed down we are creating hidden fields to pass them down.
Main View
#using (Ajax.BeginForm("CommonSave", "Common", null, new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
//OnSuccess = "submitFormSuccess",
//OnFailure = "submitFormFailure"
}, new { id = "commonForm" }))
{
<div>
<table>
<tr>
<td>
#Html.EditorFor(m => m.Name)
</td>
</tr>
<tr>
<td>
<input type ="submit" name="Common Save" />
</td>
</tr>
</table>
</div>
Controller:
public class CommonController : Controller
{
public ActionResult Index()
{
CommonModel model = new CommonModel()
{
Id = 3,
Name = "Test Name"
};
return View("Common", model);
}
[HttpPost]
public ActionResult CommonSave(CommonModel model)
{
return PartialView("CommonPartial", model);
}
public bool BinderSave(CommonModel model)
{
return true;
}
}
On load of the main view(Common) Index is called.
Upon submitting the Ajaxform on the Main view, the actionmethod CommonSave is called but the model passed to CommonSave only contains the Name and not the Id.
How can we pass that down as well without creating hidden fields or doing anything?
My actual model has a lot of fields which needs to be passed down.
instead of using an ajax form I would use an ajax call and populate the fields on success. Change your button to a button instead of submit
<input type ="button" class="btnSubmit" name="Common Save" />
then in your script tag
$('.btnSubmit').click(function () {
$.ajax({
url: '#Url.Action("CommonSave", "CommonController")',
type: "POST",
data: { Id: $('.Id').val() }
cache: false,
async: true,
success: function (result) {
//put the partial into a div on the form
$(".commonForm").html(result);
//now set the fields on the partial from the model
$('#EmailName').val('#Model.EmailName');
}
});
});
I understand the need for partial views and will tell you how I've solved this however each view should have it's own model, it just should. It's a tenet in the MVVM world:
Anyway, the partials could have a model via a interface. Define your partial view using a interface as it's model. For example:
interface:
public interface IPhone
{
string PhoneNumber ( get; set; }
}
you model:
public class MainModel : IPhone
{
public string Name
{
get { ... }
set { ... }
}
public string PhoneNumber
{
get { ... }
set { ... }
}
}
The point is that as long as the model passed to the main view implements the interface (the interface could also define a property that is another model) that the partial view depends on then all you need to do is pass the model to the partial, you may need to cast the model to the interface but technically you shouldn't have to. Let me know if this helps.
Related
I have a model class and a viewmodel class on the similar lines as model class (Code is given below) in a MVC application. There is a view whose model is 'viewmodel' and its a form. The corresponding action method for this form submit button has action parameter as viewmodel class. With this scenario mentioned, model binding works fine.
Now if i change the data type of the Action method from "viewmodel" to "Model" class , Model binding doest not work accurately and correct data is not received on the server side. Below are the model classes -
public class Model
{
public int A { get; set; }
}
public class ViewModel
{
public Model Model { get; set; }
}
View File code is below :
#model ViewModel
#{
ViewBag.Title = "Test";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm("A", "Customers"))
{
<div class="form-group">
#Html.LabelFor(m => m.Model.A)
#Html.TextBoxFor(m => m.Model.A, new { #class="form-control" })
</div>
<button type="submit" class="btn btn-primary">Save</button>
}
Controller Action Method :
With Correct Model Binding behavior -
public ActionResult A(ViewModel model)
{
return Content("Value of A is " + model.Model.A);
}
If i change the action parameter to Model class , model binding behavior doesnot take place. Below is the code -
public ActionResult A(Model model)
{
return Content("Value of A is " + model.A);
}
Why is it so ?
On the browser side , the form data is as -
Model.A - 1
Why cant this value bind to Model Class A parameter in the second case metioned ?
As your view is bound with ViewModel class (Model binding) so it carries the same model in the post event to server. but in case you wanted to bind with some other model then you have to form new model on the client side like your server side model.
In your case to achieve what you are looking for follow the below code:
<input type="button" value="Save" onclick="SaveData()"/>
<script>
function SaveData() {
$.ajax({
url: "/Home/Save",
dataType: "json",
type: "Post",
data: {
model:{A:10}
},
success:function(data) {
}
});
}
</script>
Please keep the same variable name in client and server side.
public ActionResult Save(Model model)
{
return Content("Value of A is " + model.A);
}
Using jquery.ajax, I am trying to return a view, that has a nested partial view to display a datatable. The initial view is returning, but the datatable is not showing or rendering.
AJAX
$.ajax({
type: "GET",
url: "/Controller/Action,
data: {
custNum: custNum
},
success: function (data) {
$('#DivToRenderResults').html(data);
}
Controller
public ActionResult Action(string custNum)
{
Model ReturnModel = GetData(custNum)
if (Request.IsAjaxRequest())
{
return PartialView(ReturnModel);
}
return View(ReturnModel );
}
Model
public class Model
{
public FirstViewsModel FirstViewsModel {get;set;)
public IEnumerable<DataTableModel> DataTableModel {get;set}
}
I ultimately want to use ajax to dynamically load different tabs that all will have nested datatables in partial views, but I am unable to get this first one to work. Please help, & thank you!
Target View
<div id="DivToRenderResults">
<\div>
// Inside the div
#model Model
<div>
// FirstViewModelInfo
<div>
// This one is not rendering in the return
#Html.Partial("_DataTableView", Model)
</div>
</div>
I have 2 controllers that generate 2 index views.
What i would like to do is use these views as global shared partial views but cant seem to get this working.
Does anyone know if this is even possible?
My controller code is
public ActionResult Index()
{
var viewModel = (from P in db.Projects
join R in db.Reports on P.ProjectTitle equals R.ReportProjectID into ps
from R in ps.DefaultIfEmpty()
select new MyViewModel { Project = P, Report = R });
return View(viewModel);
}
My ViewModel code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MiLife2.ViewModels
{
public class MyViewModel
{
public Project Project { get; set; }
public Report Report { get; set; }
}
}
and my view is
#model IQueryable<MiLife2.ViewModels.MyViewModel>
#{
ViewBag.Title = "Index";
}
enter code here
<h2>Index</h2>
<div>#Html.Partial("_Partial1")</div>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.Project.ProjectTitle </td>
<td>#item.Project.ProjectCreatedByID</td>
<td>#item.Project.ProjectCreatedDate</td>
<td>#if (item.Report == null)
{
<text>No Reports</text>
}
else
{
#item.Report.Title;
}
</td>
<td>#if (item.Report == null)
{
<text> </text>
}
else
{
#item.Report.Description;
}</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Project.ProjectID }) |
#Html.ActionLink("Details", "Details", new { id=item.Project.ProjectID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Project.ProjectID })
</td>
</tr>
}
</table>
If i create a partial page and paste the above view into it and then use #HTML.Partial("_ProjPartial") i get the error
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[MiLife2.Project]', but this dictionary requires a model item of type 'System.Linq.IQueryable1[MiLife2.ViewModels.MyViewModel]'.
This does not happen if i use #HTML.Partial("_ProjPartial") from within the Index cshtml page in the specific controller views folder.
From the error it looks like to me that your partial view is looking for the same model as you have on your view. Passing the model to your partial should fix that error
#Html.Partial("_Partial1", Model)
update:
since that didn't work for you I would try using an ajax call
$('.btnSubmit').on('click', function(){
$.ajax({
url: "#(Url.Action("Action", "Controller"))",
type: "POST",
cache: false,
async: true,
data: { id: id },
success: function (result) {
$(".Content").html(result);
}
});
});
then in your controller
public PartialViewResult GetPartial()
{
var viewModel = (from P in db.Projects
join R in db.Reports on P.ProjectTitle equals R.ReportProjectID into ps
from R in ps.DefaultIfEmpty()
select new MyViewModel { Project = P, Report = R });
return PartialView("_Partial1", viewModel);
}
Using this ajax call you can call the partial view from any view and you can pass different id's, on button clicks or as needed to refresh the view. Hopefully calling it this way will fix your error. let me know if you have any questions.
Recently ran into something similar, so I wanted to add my 2 cents. The answer for me was in what I was passing to the Partial View.
I was attempting to pass a string to a partial view, but when that string happened to be null, it was acting as if I had not passed anything into the Partial, which means it defaulted to passing the current view's model.
For example, I have a view which renders a partial and that partial takes in a string:
#model SomeModel
#{ Html.RenderPartial("_MyPartialView", SomeModel.StringProperty) }
If SomeModel.StringProperty happens to be null, then it is going to try and pass what ever the current view's model is (which, in this case is SomeModel). So instead, I simply wrote the following which will pass in an empty string if SomeModel.StringProperty happens to be null:
#model SomeModel
#{ Html.RenderPartial("_MyPartialView", SomeModel.StringProperty ?? string.Empty) }
Hope this helps someone.
I have a simple code from controller
public ActionResult CreatePage() {
return PartialView( "APage" );
}
and the part of that page APage is:
<table class="#className">
<tr>
...
</tr>
</table>
In javascript, I want to generate APage with different class name (css class name)
$.post('CreatePage', function(data) {
$('.result').html(data);
});
How to pass in controller function (if I would declare : public ActionResult CreatePage(string cssClass) { ... }) the parameter to PartialView function ?
Means
I want like:
public ActionResult CreatePage( string cssClass ) {
return PartialView( "APage", cssClass );
}
And I want to use that css class into APage view.
For example:
If I call
$.post('CreatePage', {cssClass: 'aClass' ,function(data) {
$('.result').html(data);
});
Then it will call
public ActionResult CreatePage( string cssClass ) {
return PartialView( "APage", cssClass ); //cssClass = 'aClass'
}
And return the view like
<table class="aClass">
<tr>
...
</tr>
</table>
Thank you
I'm not sure if I understood you correctly, but your example, I think, is already on the right track.
In your partial view, add this at the very top:
#model string
And then in your partial view, change the table tag definition to
<table class="#Model"> <tr> ... </tr> </table>
To extend upon what #rikitikitik said.
You already discovered the PartialView(viewName, model) method overload, now you just have to extend your current model to include the CSS class string. Just add a property called CssClass and you will be able to use it in your partial view.
This of course assumes you are using view models (and thus the MVVM pattern), not "just" models or even database models (handled by for example Entity Framework).
public class APartialModel
{
public string Name { get; set; }
// ... other properties
public string CssClass { get; set; }
}
public ActionResult CreatePage( string cssClass ) {
// Initialize the entire view model for the partial view here
// This usually means you need to pass in an id and use it to
// make a database lookup.
// If it's "too much work", it probably means you
// need to fix a structural problem.
APartialModel model = new APartialModel
{
Name = "Somehow I already know this value",
CssClass = cssClass
};
return PartialView( "APage", model );
}
#model APartialModel
<table class="#Model.CssClass">
<tr>
... for example #Model.Name
</tr>
</table>
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);
}
});
}