Switching between two partial views in a layout - c#

I have two partial views that I want to load after clicking a button. It should work like this - the first partial view is the one that displays defaultly, after I click the button - the partial view switches to the second one. Once you click again on the same button in the partial view - the layout switches to the first one. I don't really know how to approach that problem - I thought about declaring a flag that would go from 0 to 1, but I couldn't figure out how to save that flag in a controller or in a .cshtml page so that it saves even if I refresh the page. The two partial views show in every page of my app - it's a sidebar.
Code snippet of my _layout.cshtml
<div class="container-fluid">
<div class="row">
#{
int flag = Convert.ToInt32(HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"]);
if (flag == 1)
{
Html.Action("LoadPartial", "Home");
}
else
{
Html.Action("LoadPartial2", "Home");
}
}
}
</div>
</div>
Controller snippet
public PartialViewResult LoadPartial()
{
var context = new ApplicationDbContext();
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var user2 = userManager.FindById(User.Identity.GetUserId());
AspNetUser model = new AspNetUser();
model.Email = user2.Email;
model.Id = user2.Id;
model.UserName = user2.UserName;
model.PhoneNumber = user2.PhoneNumber;
return PartialView("_ProfileEditPartial", model);
}

You could try saving the flag as a session value, the following link shows Mircosoft's documentation on how to set up session state: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-3.1#session-state. Once set up, you can easily set/get your value using
HttpContext.Session.SetInt32("SessionPartial", 0);
HttpContext.Session.GetStringInt32("SessionPartial");
and it stays persistent even if user refreshes. Since you said the partials show up on every page of the app, set the session variable in the first controller method your app goes into, or as early as possible.
After setting up the session variable, create a controller method which determines what partial to return based on the session value.
public PartialViewResult LoadPartial()
{
var flag = HttpContext.Session.GetInt32("SessionPartial");
if (flag == 0) {
// set up model here
return PartialView("_Partial1", model);
}
else {
// set up model here
return PartialView("_Partial2", model);
}
}
Finally, in the view write some JavaScript in which you simply get and display the partial. On the click of the button, get the div in which your partial is stored, empty it of the past partial, and then load the correct partial by calling the controller method.
$(document).ready(function() {
$("#buttonId").click(function () {
$('#divId').empty();
$('#divId').load('#Url.Action("LoadPartial", "<YourControllerNameHere>"));
});
}

Related

Trigger button click after view got loaded

In my old MVC application, I have a login button once the application main page got loaded I have to explicitly click on login to get into the application. Now I would like to trigger the login_btn click event after my view got loaded via code.
In Jquery called the login_btn trigger event in document.ready function, and in controller I used viewBag option. Which is the best way to achieve
In jquery,
$(document).ready(function () {
$('#login_btn').trigger('click');
});
Its getting called when the page get refreshed.
In controller viewBag
public IActionResult Index(string info)
{
loginModel myModel = new loginModel();
test(); //tried
return View(myModel);
}
public void test()
{
ViewBag.JavaScriptFunction = "login()";
}
gives error login not defined, because before loading the model I am calling the test()
Provide me some info on how to trigger the login automatically after the view page got loaded.
Modifying my original answer, the solution using a flag to control the auto-login would be:
if( alreadyLoggedFlag === false ) {
alreadyLoggedFlag = true;
$('#login_btn').trigger('click');
}

Render part of page on dropdown selection part 2

This is a follow on to similar question but taking suggestions into account.
Render part of page on dropdown selection
I have a chart on my main view which I would like to update partially when a dropdown selects different values.
The page renders correctly the first time, but when I select a new value in the dropdown, then I think the .submit script is failing in the script .submit() because when I put a break on window.submitAjaxForm it is never reached.
_PnlChart.cshtml
<img src="#Url.Action("CreateTraderPnlChart3")" width="600" height="600" align="middle" vspace="50" />
My mainview Index.cshtml:
<div class="w3-half">
<div id="ExportDiv">
#{ Html.RenderPartial("_PnlChart");}
</div>
#using (Ajax.BeginForm("GetEnvironment",
new RouteValueDictionary { { "Environment", "" } }, new AjaxOptions() { UpdateTargetId = "ExportDiv" }, new { id = "ajaxForm" } ))
{
#Html.DropDownList("PeriodSelection",
new SelectList((string[])Session["Periods"]),
(string)Session["Period"],
new
{ onchange = "submitAjaxForm()" })
}
</script>
<script type="text/javascript">
$('form#ajaxForm').submit(function(event) {
eval($(this).attr('onsubmit')); return false;
});
window.submitAjaxForm = function(){
$('form#ajaxForm').submit();
}
</script>
</div>
My controller:
public ActionResult PeriodSelection(string dropdownlistReturnValue) // dont know what dropdownlistReturnValue is doing?
{
Session["Period"] = dropdownlistReturnValue;
return PartialView("~/Views/Employee/_PnlChart.cshtml");
}
This line in your code,
eval($(this).attr('onsubmit')); return false;
I am not sure what you were intending to do here. But from your question, i assume you wanted to do a form submission. But that line will not submit the form. The expression $(this).attr('onsubmit') is going to return undefined as your form does not have an onsubmit attribute defined.
But you already have the form submit code in your other method (submitAjaxForm). So if you simply remove the $('form#ajaxForm').submit handler (apparently it does not do anything useful), your code will work. When you change the dropdown, it will make an ajax form submission.
But your form action is set to GetEnvironment action method. That means your ajax form submission will be to that action method. In your question you have a different action method which returns the updated chart content. It does not makes sense!
I personally prefer to write handwritten ajax calls instead of relying on the ajax action helper methods. The below is the code i would probably use (Except the dropdownlist code. read further)
<div id="ExportDiv">
#{ Html.RenderPartial("_PnlChart");}
</div>
#Html.DropDownList("PeriodSelection",
new SelectList((string[])Session["Periods"]),
(string)Session["Period"], new
{ data_charturl = Url.Action("PeriodSelection","Home")})
Now listen to the change event of the SELECT element.
$(function(){
$("#PeriodSelection").change(function(){
var v = $(this).val();
var url=$(this).data("charturl")+'?dropdownlistReturnValue='+v;
$("#ExportDiv").load(url);
});
});
You should consider using the a view model to pass the Dropdownlist data. Why not use the DropDownListFor helper method ? It looks much clean, Mixing a lot of C# code (See all the session casting and all.) makes it kind of dirty IMHO.

ASP.NET MVC4 - Multiple models of same type with partial views on the same page

I have a single page ASP.NET MVC 4 application which should display charts. Each chart (dotnetHighcharts) is contained in a single partial view with its own model.
Now I want to be able to display multiple charts on a single page, each with its own model, rendered in a partial view.
My controller looks like this:
public class ReportController : Controller
{
[HttpGet]
public ActionResult Display(Guid? id)
{
var viewModel = PrepareViewModel(id);
return View(viewModel);
}
[HttpPost]
public ActionResult DisplayChart(Guid? id)
{
var viewModel = PrepareViewModel(id);
return PartialView("Partial_ChartView", viewModel);
}
}
The partial view looks like this:
#model MobileReports.Models.ReportViewModel
#Model.Chart
The main view has this code:
#model IEnumerable<MobileReports.Models.ReportViewModel>
#{
ViewBag.Title = "Display";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="chartContainer" style="float:left">
#{Html.RenderPartial("Partial_ChartView");}
</div>
<div id="secondChartContainer" style="float:right">
#{Html.RenderPartial("Partial_ChartView");}
</div>
The Model itself contains only a rendered chart and a few infos about it.
My problem is, I don't know if I am doing it right. The mainview has to know which charts are already displayed on the page, so that I dont display the same chart twice. In the initial load, I somehow have to tell the partialviews which charts are already being displayed on the page. How can I do that?
Also how do I keep multiple models on the main view?
-edit-
The controller action DisplayChart(Guid? id) is used inside the partialView from a javascript function:
function displayNextReport() {
// try to find a report that is not displayed already
var diff = $(availableReports).not(displayedCharts).get();
if (diff.length > 0) {
// remove old chart data
if ($("#chart_container").highcharts() !== undefined) {
$("#chart_container").highcharts().destroy();
}
// load the new report
$("#chart_container").load('#Url.Action("DisplayChart", "Report")', { id: diff[0] });
}
}
Note: This does not work right now. I need to pass an argument that tells the DisplayChart() method which chart to load next. For this, I need to know which charts are currently diplayed.
My code is most likely very wrong and messed up. I think it is best to just describe what I want to achieve:
I want to have a View that displays multiple partial views of the same type. Each partial view has to know what the other partial view are currently displaying. Thats all I want to do..

Devexpress 12.1 MVC GridView Inside Tab Strip Issues

I'm an intern that has never done any web development just so you know where I'm coming from. I'm currently trying to learn asp.NET MVC 3 using devexpress 12.1 tools. I started with a template that had a devexpress gridview in the content area that is linked up to the Northwind db. It works by itself, but when I create a devexpress tab strip and place the gridview inside the second tab I get the column headings, but no data is displayed. When I click on a column heading to sort the data shows up. I'm wanting the gridview to load after I click the tab and not when the page loads. Maybe my callbacks are the problem. My tab strip is using an ajax callback and the gridview is as well for the paging. I have added the model to the TabControlPartial page and passed in the model in the controller for the TabControlPartial action. I've tried looking at the demos at mvc.devexpress.com, but there is nothing that puts the two together. I don't 100% understand passing the model into the view I guess. I know this is simple, but I don't know what to do. Thanks for your help.
Controller (this may be my issue):
public ActionResult LookUp()
{
return View(NorthwindDataProvider.GetCustomers());
}
public ActionResult _TabControlPartial()
{
return PartialView("_TabControlPartial", NorthwindDataProvider.GetCustomers());
}
public ActionResult _GridViewPartial()
{
return PartialView("_GridViewPartial", NorthwindDataProvider.GetCustomers());
}
LookUp View (Index):
#model System.Collections.IEnumerable
#Html.Partial("_TabControlPartial", Model)
Tab Partial:
#model System.Collections.IEnumerable
#Html.DevExpress().PageControl(
settings =>
{
settings.Name = "TabControl";
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
settings.Height = System.Web.UI.WebControls.Unit.Percentage(100);
settings.CallbackRouteValues = new { Controller = "Customers", Action =
"_TabControlPartial" };
settings.TabPages.Add(
tabOne =>
{
tabOne.Name = "TabOne";
tabOne.Text = "Start";
tabOne.SetContent(() =>
{
ViewContext.Writer.Write("Start");
});
});
settings.TabPages.Add(
tabTwo =>
{
tabTwo.Name = "TabTwo";
tabTwo.Text = "Customer List";
tabTwo.SetContent(() =>
{
Html.RenderPartial("_GridViewPartial", Model);
});
});
}).GetHtml()
GridView Partial:
#Html.DevExpress().GridView(
settings =>
{
settings.Name = "GridView";
settings.CallbackRouteValues = new { Controller = "Customers", Action =
"_GridViewPartial" };
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
settings.Height = System.Web.UI.WebControls.Unit.Percentage(100);
settings.SettingsPager.Visible = true;
settings.SettingsPager.PageSize = 15;
settings.ControlStyle.Paddings.Padding = System.Web.UI.WebControls.Unit.Pixel(0);
settings.ControlStyle.Border.BorderWidth = System.Web.UI.WebControls.Unit.Pixel(0);
settings.ControlStyle.BorderBottom.BorderWidth =
System.Web.UI.WebControls.Unit.Pixel(1);
//Configure grid's columns in accordance with data model fields
settings.Columns.Add("ContactName");
settings.Columns.Add("Address");
settings.Columns.Add("City");
settings.Columns.Add("PostalCode");
settings.Columns.Add("Phone");
}).Bind(Model).GetHtml()
You're missing the data in the GridView when the tab is opened. When you open the page, the data for the GridView needs to be loaded in the Model that is returned. right now you load the page (in LookUp), but you aren't pushing the data for the grid. whenever any callback occurs, only at that point is the data getting pulled from the database and returned to the screen (notice you only return data in the Callback methods _TabControlPartial and _GridViewPartial). When you sort a column, or filter, etc, then the callback is fired and the data is returned from the server.
The code you have looks correct, but somewhere in the process the Model is losing it's value. the best option is to put a breakpoint in the tab control, the Grid Binding, and the controller and make sure the data you expect is in place when it's bound.
You could "cheat" by putting in a callback when the tab is activated such as:
#Html.DevExpress().PageControl(
settings =>
{
settings.Name = "TabControl";
settings.ClientSideEvents.Init = "TabControl_Init";
...
}).GetHtml()
and in JavaScript have:
function TabControl_Init(s, e) {
GridView.PerformCallback();
}
this way, after the tabs are initialized, the GridView will run a callback, and grab the data correctly. But it would be better to figure out why the data isn't being sent down in the first place by stepping through the code.

Submitting strongly typed repeating partial views

Im making a form in ASP.Net MVC 3 C#.
This particular page of the form contains the user's employment history.
The user can have more than one employment history. So the view model contains a list.
Now it would be easy to so this (and it works):
int i = 0;
foreach (FrgCandidatePortal_2.Models.tblCandidateEmploymentHistory item in Model.empHistList)
{
<div>
<label>
Employment History #Html.Encode(i + 1)</label></h4>
<label>
Company Name</label>
<div>
#Html.EditorFor(c => c.empHistList[i].LJCOMP)
#Html.ValidationMessageFor(c => c.empHistList[i].LJCOMP)
</div>
...
</div>
i++;
}
BUT i want to be able to add an empty one using a button and ajax.
SO i figure "ill make it a partial view".
QUESTION 1: is a partial view the correct way to handle a recurring form element that needs add remove and save functionality?
Now I've made it a partial view and this is my view model for the page:
public class EmploymentHistoryViewModel : ViewModels
{
private List<EmploymentHistory_Partial> _EmploymentHistory_Partial_List;
public List<EmploymentHistory_Partial> EmploymentHistory_Partial_List
{
get
{
if (_EmploymentHistory_Partial_List.Count == 0)
{
int i = 0;
foreach (tblCandidateEmploymentHistory item in dataModel.candidateModel.tblEmpHistList)
{
_EmploymentHistory_Partial_List.Add(new EmploymentHistory_Partial(i, item));
i++;
}
return _EmploymentHistory_Partial_List;
}
else
{
return _EmploymentHistory_Partial_List;
}
}
set {
//foreach emphist partial fill emp hist
_EmploymentHistory_Partial_List.Clear();
dataModel.candidateModel.tblEmpHistList = value.Select(c=>c.empHist).ToList();
}
Basically my view model is a list of _EmploymentHistory_Partial's.
That displays data correctly when i use this code in my employment history view:
int i = 0;
foreach (FrgCandidatePortal_2.Models.EmploymentHistory_Partial item in Model.EmploymentHistory_Partial_List)
{
Html.RenderPartial("_EmploymentHistory_Partial",new FrgCandidatePortal_2.Models.EmploymentHistory_Partial(i,Model.EmploymentHistory_Partial_List[i].empHist));
}
BUT IT DOESNT SUBMIT
QUESTION 2: Why don't the values submit to the model on post?
(Im assuming its something to do with mvc naming conventions in the html document)
UPDATE
PROGRESS!
by editing the html of one of the fields (so that ID and NAME equaled EmploymentHistory_Partial_List[0].empHist.LJCOMP instead of empHist.LJCOMP) before i submitted when debugging. IT WORKED. It got to the set of EmploymentHistory_Partial_List in the view model.
So its naming. What seems to be happening is the partial view isn't inheriting the beginning of the naming from the rest of the form (and quite rightly). Is there any way to make that happen?
You can use EditorTemplates, either through an Html.BeginCollectionItem helper or just by calling Html.EditorFor(Model.EmploymentHistory_Partial_List).

Categories