Good day
I am working with 7 partial views on my index page.
Index.cshtml (code section that creates the partial views in their own tabs)
#model project1.Models.MasterModel
<div class="tab-content col-lg-9 col-md-9 col-sm-9 col-xs-9" style="margin-bottom:110px;">
<div id="partial1" class="tab-pane fade in active">
#Html.Partial("partial1", Model)
</div>
<div id="partial2" class="tab-pane fade in">
#Html.Partial("partial2", Model)
</div>
<div id="partial3" class="tab-pane fade in">
#Html.Partial("partial3", Model)
</div>
<div id="partial4" class="tab-pane fade in">
#Html.Partial("partial4", Model.Owners)
</div>
<div id="partial5" class="tab-pane fade in">
#Html.Partial("partial5", Model)
</div>
<div id="partial6" class="tab-pane fade in">
#Html.Partial("partial6", Model)
</div>
<div id="partial7" class="tab-pane fade in">
#Html.Partial("partial7", Model)
</div>
On partial1 I have a submit button that should populate the other partial views with the information that is submitted on the first partial view.
My Model consist of 7 models (one for each partial view)
MasterModel.cs
public class MasterModel
{
public DisplayPartial1 view1 {get;set;}
public DisplayPartial2 view2 {get;set;}
public DisplayPartial3 view3 {get;set;}
public DisplayPartial4 view4 {get;set;}
public DisplayPartial5 view5 {get;set;}
public DisplayPartial6 view6 {get;set;}
public DisplayPartial7 view7 {get;set;}
}
In my controller's Index Action result I create a new instance of the MasterModel and then I create new instances for all the sub models and return to the Index view.
MainController.cs
// Global variable used and returned by all partial views
MasterModel main = new MasterModel();
public ActionResult Index()
{
MasterModel master = new MasterModel();
master.view1 = new DisplayPartial1 ();
master.view2 = new DisplayPartial2 ();
master.view3 = new DisplayPartial3 ();
master.view4 = new DisplayPartial4 ();
master.view5 = new DisplayPartial5 ();
master.view6 = new DisplayPartial6 ();
master.view7 = new DisplayPartial7 ();
return View(master);
}
public ActionResult MyPartial1()
{
return PartialView("MyPartial1", master);
}
[HttpPost]
public ActionResult MyPartial1(MasterModel model, string submitButton)
{
if(submitButton == "GetInfo")
{
/*Process input values*/
//wcf service return data
main.view1.id = serviceObject.Id;
...
main.view4.name = serviceObject.Name;
...
}
return PartialView("MyPartial1", master);
}
When MyPartial1 is returned then the other 6 partial view do not update with the assigned information until I do a submit call with a java script that looks like the following:
<script type="text/javascript">
$(document).ready(function () {
$('#input1').change(function () {
$('form').submit();
});
$('#input2').change(function () {
$('form').submit();
});
});
</script>
An Example Partial view (all the partial views work on the same principals)
#model OperatorLicense.Models.MasterModel
#using (Ajax.BeginForm("MyPartial1", "Operator", null, new AjaxOptions
{
UpdateTargetId = "MyPartial1",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post"
}, new { id = "MyPartial1" }))
{
#Html.TextBoxFor(model => model.view1.SerialNumber, new { id="SerialNumber", #class = "form-control", placeholder = Html.DisplayNameFor(n => n.view1.SerialNumber) })
...
}
Is there a way to refresh the other partial views when the MyPartial1 partial view has returned so that the assaigned values can be displayed on the required partial view?
You can use OnSuccess or OnComplete property of AjaxOptions class.
#using (Ajax.BeginForm("MyPartial1", "Operator", null, new AjaxOptions
{
UpdateTargetId = "MyPartial1",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post",
OnSuccess="partial1Success"
}, new { id = "MyPartial1" }))
{
#Html.TextBoxFor(model => model.view1.SerialNumber, new { id="SerialNumber", #class = "form-control", placeholder = Html.DisplayNameFor(n => n.view1.SerialNumber) })
...
}
define partial1Success method in javascript
<script type="text/javascript">
function partial1Success(){
// write your other partial view refresh logic here
}
</script>
partial1Success method called after from submit successfully.
Related
Currently we have a page where you select some parameters and click on a button to load data and display it in a grid, but there is no functionality to display the data on page load (via url parameters) yet. I've added the necessary routing configurations and Action, but I'm having troubles to render the page, it only displays the PartialView without styles.
How can I get the whole page to render and not just the PartialView?
Below is my simplyfied code for the View and Controller.
Views/Planing/Index.cshtml
#model PlaningTool.Web.Models.PlaningViewModel
<div class="row">
<div>
#using (Ajax.BeginForm("GetDataRows",
"Planing",
new AjaxOptions
{
HttpMethod = "Get",
UpdateTargetId = "gridPlaceholder",
LoadingElementId = "loadingIndicator"
}))
{
<!-- some comboboxes to select project and year -->
<input type="submit" value="Load data" />
}
</div>
</div>
<div id="gridPlaceholder">
<div id="loadingIndicator" style="display: none;">
<img src="~/Content/images/loading-image.gif" />
</div>
</div>
Controllers/PlaningController.cs
public partial class PlaningController : Controller
{
public virtual ActionResult Index()
{
return View();
}
public virtual ActionResult Plan(long projectID, int year)
{
var viewModel = new PlaningViewModel
{
ProjectID = projectID,
Year = year
};
// return GetDataRows(viewModel);
return RedirectToAction("GetDataRows", viewModel);
}
[RestoreModelStateFromTempData(typeof(PartialViewResult))]
public virtual PartialViewResult GetDataRows(PlaningViewModel viewModel)
{
// Load data from database with viewModel.ProjectID
// and viewModel.Year as parameters
[...]
var vm = new PlaningViewModel
{
// Set ViewModel for loaded data
[...]
};
return PartialView("Shared/_PlaningViewModelRows", vm);
}
[...]
}
I finally found a solution. I'm pretty sure it's not the best way to do this but it works.
If the Model is already set I render the PartialView.
<div id="gridPlaceholder">
#{
if (Model != null)
{
Html.RenderPartial("Shared/_PDataViewModelRows", Model);
}
}
<div id="loadingIndicator" style="display: none;">
<img src="~/Content/kendo/Bootstrap/loading-image.gif"/>
</div>
</div>
And in my Controller I've changed to this, so my ViewModel gets loaded independently and I simply return the same view as I would for Index with the new ViewModel.
public virtual ActionResult Plan(long projectID, int year)
{
var viewModel = new PlaningViewModel
{
ProjectID = projectID,
Year = year
};
return View("Index", LoadViewModel(viewModel));
}
public PlaningViewModel LoadViewModel(PlaningViewModel viewModel)
{
// Load data from database with viewModel.ProjectID
// and viewModel.Year as parameters
[...]
var vm = new PlaningViewModel
{
// Set ViewModel for loaded data
[...]
};
return vm;
}
I have a dashboard view. In this dashboard I want to render number of partial views. I started this exercise just for learning purpose. Actually I am not sure what I am doing wrong. Here is my code:
My DashboardController:
public ActionResult DashboardIndex()
{
return View();
}
public ActionResult DebitAndCreditExpensesPV()
{
DashboardModel objGet = new DashboardModel();
DashboardViewModel objVM = new DashboardViewModel();
DateTime date = new DateTime();
objVM.StartDate = new DateTime(date.Year, date.Month, 1);
objVM.EndDate = objVM.StartDate.AddMonths(1).AddDays(-1);
objVM.ExpenseType = objGet.GetExpensesByDebitAndCredit(objVM.StartDate, objVM.EndDate);
return PartialView(objVM);
}
My DashboardIndex.cshtml
#model GPI.ViewModel.DashboardViewModel
#{
ViewBag.Title = "DashboardIndex";
}
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="col-md-4">
#{
Html.RenderPartial("DebitAndCreditExpensesPV");
}
</div>
<div class="col-md-8"></div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$.ajax({
type: "get",
url: "/Dashboard/DebitAndCreditExpensesPV",
data: {
'startDate': $('#StartDate').val(),
'endDate': $('#EndDate').val()
},
dataType: 'json',
success: function () {
alert('success');
},
error: function () {
alert('failure');
}
});
});
</script>
DashboardModel.cs
public class DashboardViewModel
{
public double ExpenseAmount { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public ExpenseList ExpenseType { get; set; }
}
public class ExpenseList
{
public double TotalDebits { get; set; }
public double TotalCredits { get; set; }
}
My Partial View: DebitAndCreditExpensesPV.cshtml
#model GPI.ViewModel.DashboardViewModel
<div class="row">
<div class="col-sm-4 col-md-12">
<div class="stat-panel">
<div class="stat-row">
<div class="stat-cell bg-pa-purple padding-sm">
<div class="col-xs-6">
<div class="text-xs" style="margin-bottom:5px;">
Debit EXPENSES
</div>
<div style="width:100%;display:inline-block;margin-bottom:-2px;position:relative;">
<span class="text-xlg">
<span class="text-lg text-slim">₹</span>
<strong>#Model.ExpenseType.TotalDebits</strong>
</span>
</div>
</div>
<div class="col-xs-6">
<div class="text-xs" style="margin-bottom:5px;">
Credit EXPENSES
</div>
<div style="width:100%;display:inline-block;margin-bottom:-2px;position:relative;">
<span class="text-xlg">
<span class="text-lg text-slim">₹</span>
<strong>#Model.ExpenseType.TotalCredits</strong>
</span>
</div>
</div>
</div>
</div>
<div class="stat-row">
<div class="stat-counters bordered no-border-t text-center">
<div class="stat-cell col-xs-12 padding-sm">
<div class="input-daterange input-group" id="datepicker">
#Html.TextBoxFor(m => m.StartDate,"{0:d}", new { #class = "input-sm form-control" })
<span class="input-group-addon">to</span>
#Html.TextBoxFor(m => m.EndDate, "{0:d}", new { #class = "input-sm form-control" })
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I put two break points in my controller: one at 'DashboardIndex' action and other at 'DebitAndCreditExpensesPV'. The first one executes but later one does not. After first breakpoint, I got 'object null reference ' exception in my partial view at this line <strong>#Model.ExpenseType.TotalDebits</strong>.
I want to know why second breakpoint is not executing. I this break point executes, I can not get this exception. Please tell me where I am going wrong.
In the RenderPartial method, you are calling the DebitAndCreditExpensesPv partial view. This view is strongly typed to your DashboardViewModel and you are using different properties of this Model inside the view (Ex :Model.ExpenseType.TotalDebits).
But in your Index view, you are not passing any model object to your RenderPartial method. If you do not pass any object in this method, It will try to use the Model of the parent view(Index). In your case, You Index view does not have any model, So the essentially the Model which the partial view now has is NULL. You are trying to access the ExpenseType property of NULL and that is the reason you are getting the exception.
Even if you fix your index view to pass the model, You are doing it twice. Once via RenderPartial and again you are making a call to the DebitAndCreditExpensesPV method via ajax on the document ready event. May be you can get rid of the RenderPartial call.
So in your index view, Add a div to show the result of the ajax call.
<div id="divDebitAndCredit"></div>
And your script to load the markup to this div. I removed the datatype:"json" as we do not want receive the data in json format.
$(function () {
$.ajax({
type: "get",
url: "#Url.Action("DebitAndCreditExpensesPV","Home")",
data: {
'startDate': $('#StartDate').val(),
'endDate': $('#EndDate').val()
},
success: function (r) {
$("#divDebitAndCredit").html(r);
},
error: function (a,b,c) {
alert('Error ! See browser console');
console.log(b,c);
}
});
});
Now in the above code, you are trying to send the startDate and endDate to the action method. So update your action method to accept those.
public ActionResult DebitAndCreditExpensesPV(DateTime? startDate,DateTime? endDate)
{
DashboardViewModel objVM = new DashboardViewModel();
DateTime date = DateTime.Now;
if(startDate!=null)
{
objVM.StartDate = startDate.Value;
}
else
{
objVM.StartDate = new DateTime(date.Year, date.Month, 1);
}
if(endDate!=null)
{
objVM.EndDate = endDate.Value;
}
else
{
objVM.EndDate = objVM.StartDate.AddMonths(1).AddDays(-1);
}
objVM.ExpenseType = new ExpenseList { TotalCredits = 45.00, TotalDebits = 634.00 };
return PartialView(objVM);
}
But the startDate and endDate input fields are part of the partial view. so when you make the ajax call in the ready event of the index view, those fields won't be part of your page. You can either keep the Partial view inside our div and pass a DashboardViewModel object to the Partial view
#model DashboardViewModel
<div id="divDebitAndCredit">
#{ Html.RenderPartial("DebitAndCreditExpensesPV",Model) }
</div>
This means your Index action should send an object of DashboardViewModel to the index view with whatever default values you want to render.
public ActionResult Index()
{
var objVM = new DashboardViewModel();
DateTime date = DateTime.Now;
objVM.StartDate = new DateTime(date.Year, date.Month, 1);
objVM.EndDate = objVM.StartDate.AddMonths(1).AddDays(-1);
objVM.ExpenseType = new ExpenseList { TotalCredits = 45.00, TotalDebits = 634.00 };
return View(objVM);
}
Situation: In my C#/MVC 4 solution I am employing a view with a partial view within. The view is a form with a submit button. The partial view is with a div that is hidden, but can be displayed if the checkbox is selected.
Issue: If the partial view is hidden, the submit works normally. If the partial view is not hidden the submit causes the page to become unresponsive, if one waits the 3 plus minutes or so the submit eventually works as expected.
The code is below. Thank you in advance for your consideration. I am a novice developer, therefore all comments, suggestions and critiques are welcome.
Code:
Model
namespace MyModels
{
public class MainModel
{
public SelectListItem Things { get; set;}
public IEnumerable<OtherModel> MoreThings { get; set;}
}
}
View
//named MyView
#model MyModels.MainModel
#using MyModels
#if (Model != null){
using (Html.BeginForm("MyViewName", "MyControllerName", FormMethod.Post, new { id = "view-form" }))
{
#Html.LabelFor(model => model.things)
#Html.DropDownList("", (Selectist)ViewBag.things)
#Html.ValidationMessageFor(model => model.field1)
#Html.CheckBoxWithLabel("aNameAttribute", Model.valueAttribute.ToString(), "anIdAttribute", Model.valueAtttribue ==1, "aLabel", "a_Toggle_Class")
<div class="treeview" style="display: none;">
<fieldset>
<legend>Title</legend>
//view causing issues replaces the div below
<div id="replacedDiv"></div>
</fieldset>
</div>
<p>
<input type="submit" value="Submit" />
</p>
}
}
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
url: "/MyController/MyPartialView",
contentType: "application/html; charset=utf-8",
cache: "false",
type: "GET",
datatype: "html"
})
.success(function (result) {
$('#replacedDiv").html(result);
})
});
</script>
Partial View
//named _MyPartialView
#model MyModels.MainModel
#using MyModels
#foreach (var moreThings in ViewBag.moreThings)
{
<div id="replacedDiv">
<label>
<input type="checkbox" id=#moreThings.id value=#moreThings.name />#moreThings.name </label>
</div>
}
Controller
namespace Main.Controllers
{
public class MyController
{
[HttpGet]
public ActionResult Index(MainModel model)
{
return View(model);
}
public ActionResult MyView()
{
var model = new MainModel();
return View(model);
}
public ActionResult MyPartialView(MainModel model)
{
<OtherModel> moreThings = BLotherModel.GetMoreThings();
ViewBag.moreThings = moreThings;
return PartialView("_MyPartialView", promotion);
}
[HttpPost]
public ActionResult MyView(FormCollection collection)
{
MainModel model = new MainModel();
return SaveModel(model);
}
}
}
In your ajax you are using:
$('#replacedDiv").html(result);
But your partial view contains <div id="replacedDiv"> that are generated in a loop
replace your partial view code with :
#foreach (var moreThings in ViewBag.moreThings)
{
<label>#moreThings.name </label>
<input type="checkbox" id=#moreThings.id value=#moreThings.name />
}
and it should be OK
In a View i have the next structure ( control of Subject*s for each *Group):
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#for (int i = 0; i < ViewBag.AllGroups.Count; i++)
{
<h4>#ViewBag.AllGroups[i].Code</h4>
<select id="e-#i" multiple="multiple">
#foreach (Subject subject in ViewBag.AllSubjects)
{
<option value="#subject.Name">#subject.Name</option>
}
</select>
}
<input type="submit" value="Generate" class="btn btn-default" />
</div>
}
The question is that how can I retreive this data (I want to receive (1)list of Groups and and I want to get a (2)list of all selected Subjects for each group in my list(1)) in my Controller?
Thank you in advance.
Recommended way is to use strongly typed View Model Object
public class GroupViewModel
{
public string Code { get;set; }
public List<Subject> AllSubjects { get; set; }
}
Pass List as the Model to the Razor view in the controller.
return new View(new List<GroupViewModel>()); // populated one.
Use this list in the View.
#model IList<GroupViewModel>
#for (int i = 0; i < Model.Count; i++)
{
<h4>Model[i].Code</h4>
<select id="e-#i" multiple="multiple">
#foreach (Subject subject in Model[i].AllSubjects)
{
<option value="#subject.Name">#subject.Name</option>
}
</select>
}
There is nothing especial to deal with this situation, except that you have missed the tag name of the select element.
To be exact, all html elements such as select you have used here, should have a name not id (id="e-#i") and all elements are serialized based their names and sent to server. On the other side, at server-side, you should get the posted values which are in a csv formatted (due to multiple ability added you have added to select element)
Solved my problem by simplifying the task. What i had to to: I created new ViewModel for this thing. I replaced tag <select></select> with #Html.ListBoxFor(m => m.Subjects, Model.SubjectItems). I had to create a SubjectItems list in my ViewModel.
Here's the code (Sorry for tons of code: I just want to make everything clear):
My View:
#using System
#using System.Linq
#using TimeTable.GenericRepository
#model TimeTable.Models.GroupViewModel
#{
//it's better to move the next line to a Controller later
ViewBag.GroupId = new SelectList(new GroupRepository().Get().ToList(), "Id", "Code", Model.GroupId);
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_LayoutBootstrap.cshtml";
}
<h2>Index</h2>
<hr />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.GroupId, "Group is: ", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("GroupId", String.Empty)
#Html.ValidationMessageFor(model => model.GroupId)
</div>
</div>
#Html.ListBoxFor(m => m.Subjects, Model.SubjectItems, new { #id = "e", #style = "width:80%; " })
<br /><br />
<input type="submit" value="Generate" class="btn btn-default" />
</div>
}
#* ReSharper disable once Razor.SectionNotResolved *#
#section Scripts {
#Styles.Render("~/Content/select2")
#Scripts.Render("~/bundles/select2")
<script type="text/javascript">
$(function () { $("#e").select2(); });
</script>
}
My Controller:
public ActionResult Generate()
{
return View(new GroupViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Generate(GroupViewModel gvm)
{
var subjects= gvm.Subjects; // <== selected subjects are here
return View();
}
My Model:
public class GroupViewModel
{
public int GroupId{ get; set; }
public Group Group {
get { return new GroupRepository().GetById(GroupId); }
}
public object Subjects { get; set; }
public IEnumerable<SelectListItem> SubjectItems
{
get
{
var items = new SelectList(new SubjectRepository().Get().ToList(), "Id", "Name");
return items;
}
}
}
P.S. Select2 is a custom replacement for selectBoxes, it's not necessary, but I like it: http://ivaynberg.github.io/select2/
I am beginner and I think my question is very obvious but I am stuck in it!
In MVC and trying to pass a custom Model (class) which is not my view's main Model to my controller.
My Razor code is as follow:
#helper CreatForm()
{
MyViewModel myModel = new MyViewModel();
using (Html.BeginUmbracoForm("Post", "ShowPost", FormMethod.Post, new { #class = "formCM" }))
{
myModel.PostNode = Node.GetCurrent();
<div class="row">
#Html.TextBoxFor(x => myModel.Name, new Dictionary<string, object> { { "placeholder", "Name" } })
</div>
<div class="row">
#Html.TextBoxFor(x => myModel.Email, new Dictionary<string, object> { { "placeholder", "Email Address" } })
</div>
<div class="row">
#Html.TextBoxFor(x => myModel.Website, new Dictionary<string, object> { { "placeholder", "Website" } })
</div>
<div class="row tall">
#Html.TextAreaFor(x => myModel.Comment, new Dictionary<string, object> { { "placeholder", "Comment" } })
</div>
<div class="row">
<input type="submit" id="Submit" name="Submit" value="Submit" />
</div>
}
}
Clicking on Submit button will take me to the controller but the Model is always empty.
My controller is like below:
[HttpPost]
public ActionResult Post(MyViewModel model)
{
return this.View();
}
Any suggestions? Do I have to add this MyModel properties to current page's ViewData?
Create a partial-view that takes MyViewModel -- that will be required to make Html.TextBoxFor() work the way you want it to. Then call that partial view from your main view. Let's say you name the view "myForm", and place it in the shared folder. Then in your main view:
#Html.Partial("myForm", myModel)