I have a View that contains a set of tabs each rendering a different partial view. After reading the documentation and W3Schools samples of these bootstrap tabs, I am unable to work out a way that makes the active tab remain active on Postback. All of the examples I've seen are using older versions of .Net and don't apply either.
Here is my code.
My controller action:
public IActionResult DisplayCharts(DashboardChartsByMonthModel model)
{
//...do stuff
model.MonthOrQuarterChart = monthChart;
model.UserChart = userChart;
return View(model);
}
Within the view @Scripts
section:
<script>
$(function(){
var hash = window.location.hash;
hash && $('ul.nav a[href="' + hash + '"]').tab('show');
$('.nav-tabs a').click(function (e) {
$(this).tab('show');
var scrollmem = $('body').scrollTop() || $('html').scrollTop();
window.location.hash = this.hash;
$('html,body').scrollTop(scrollmem);
});
});
</script>
<script>
$('a[data-toggle="tab"]').on('shown.bs.tab',
function(e) {
switch ($(e.target).attr('href')) {
case '#tab1':
drawMonthAndQuarterChart();
break;
case '#tab2':
drawUserChart();
break;
}
});
</script>
Within the body:
<ul class="nav nav-tabs" role="tablist" id="myTabs">
<li class="nav-item">
<a class="nav-link active" id="tab1-tab" data-toggle="tab" href="#tab1" role="tab" aria-controls="tab1" aria-selected="true">By Month & Quarter</a>
</li>
<li class="nav-item">
<a class="nav-link" id="tab2-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="tab2" aria-selected="false">By Leasing / Billing Rep</a>
</li>
<div class="tab-content" id="myTabContent">
<div class="tab-pane active" id="tab1" role="tabpanel" aria-labelledby="tab1-tab">
<form method="post">
...model fields, etc.
<button type="submit" class="btn btn-success">Submit</button>
<div id="chart_monthandquarter_div"></div>
</form>
<div class="tab-pane" id="tab2" role="tabpanel" aria-labelledby="tab2-tab">
<form method="post">
....
</form>
And the same would go on for tab 2, tab 3, etc. Each tab has its own form with its own button that submits the model and when the page reloads after submit, I can swap between both tabs and see my charts rendering just fine however it keeps making the first tab active any time I post.
One of the several things I've tried was working out some of the older examples with a hidden field that I've seen some people use but I was unable to get that to work.
So with the code presented, how can I make it so that the current tab that you are viewing when you click submit is the one that's active on postback?
I have a View that contains a set of tabs each rendering a different partial view. After reading the documentation and W3Schools samples of these bootstrap tabs, I am unable to work out a way that makes the active tab remain active on Postback. All of the examples I've seen are using older versions of .Net and don't apply either.
Here is my code.
My controller action:
public IActionResult DisplayCharts(DashboardChartsByMonthModel model)
{
//...do stuff
model.MonthOrQuarterChart = monthChart;
model.UserChart = userChart;
return View(model);
}
Within the view @Scripts
section:
<script>
$(function(){
var hash = window.location.hash;
hash && $('ul.nav a[href="' + hash + '"]').tab('show');
$('.nav-tabs a').click(function (e) {
$(this).tab('show');
var scrollmem = $('body').scrollTop() || $('html').scrollTop();
window.location.hash = this.hash;
$('html,body').scrollTop(scrollmem);
});
});
</script>
<script>
$('a[data-toggle="tab"]').on('shown.bs.tab',
function(e) {
switch ($(e.target).attr('href')) {
case '#tab1':
drawMonthAndQuarterChart();
break;
case '#tab2':
drawUserChart();
break;
}
});
</script>
Within the body:
<ul class="nav nav-tabs" role="tablist" id="myTabs">
<li class="nav-item">
<a class="nav-link active" id="tab1-tab" data-toggle="tab" href="#tab1" role="tab" aria-controls="tab1" aria-selected="true">By Month & Quarter</a>
</li>
<li class="nav-item">
<a class="nav-link" id="tab2-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="tab2" aria-selected="false">By Leasing / Billing Rep</a>
</li>
<div class="tab-content" id="myTabContent">
<div class="tab-pane active" id="tab1" role="tabpanel" aria-labelledby="tab1-tab">
<form method="post">
...model fields, etc.
<button type="submit" class="btn btn-success">Submit</button>
<div id="chart_monthandquarter_div"></div>
</form>
<div class="tab-pane" id="tab2" role="tabpanel" aria-labelledby="tab2-tab">
<form method="post">
....
</form>
And the same would go on for tab 2, tab 3, etc. Each tab has its own form with its own button that submits the model and when the page reloads after submit, I can swap between both tabs and see my charts rendering just fine however it keeps making the first tab active any time I post.
One of the several things I've tried was working out some of the older examples with a hidden field that I've seen some people use but I was unable to get that to work.
So with the code presented, how can I make it so that the current tab that you are viewing when you click submit is the one that's active on postback?
Share Improve this question edited Oct 27, 2017 at 14:39 Mkalafut asked Oct 26, 2017 at 18:36 MkalafutMkalafut 7412 gold badges16 silver badges37 bronze badges 5- What are you returning from the HttpPost action methods, to which the form is being submitted ? – Shyju Commented Oct 26, 2017 at 19:43
-
@Shyju
return View(model);
Just refreshing the page with the updated model based on my selectlist values. – Mkalafut Commented Oct 26, 2017 at 20:01 - You might want to consider using a Javascript framework like VueJS. They make these sort of problems trivial to solve. – Matt LaCrosse Commented Oct 27, 2017 at 15:36
- @MattLaCrosse What is the overhead of adding something like this? Is it as simple as including a Nuget package and using a script or something? Could you please provide more info or an example if able? – Mkalafut Commented Oct 27, 2017 at 15:57
- @Mkalafut If you're using NodeJS it's usually as simple as including the correct library/configuration in your build setup. Then using the framework as needed. For instance, my ASP.NET Core Webapp uses Aurelia for the front-end UI with Webpack. The .NET is for the API backend. – Matt LaCrosse Commented Oct 27, 2017 at 16:13
1 Answer
Reset to default 5When user submits a form, you should follow the P-R-G pattern. So after saving, you should return a redirect response which issue a totally new GET request to load the page from scratch.
When issuing the redirect response, you can add a querystring speciific to the tab you want to select. For example, for the below sample markup, you can send the href value without the #
as the querystring value and in the view read this querystring value and set to a js variable. In the document ready event, you can explicitly enable the tab you want with that.
<ul class="nav nav-tabs" role="tablist" id="myTabs">
<li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">Home</a></li>
<li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">Profile</a></li>
<li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">Messages</a></li>
<li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Settings</a></li>
</ul>
And in your HttpPost action
public IActionResult UpdateProfile(YourViewModel model)
{
// to do :Save
return RedirectToAction("Index", new { t = "profile" });
}
And in the view, you inject IHttpContextAccessor
implementation so that we can access Request
and then querystrings
@inject IHttpContextAccessor HttpContextAccessor
<!-- your code for the tabs goes here-->
<script>
$(function() {
var t = '@HttpContextAccessor.HttpContext.Request.Query["t"]';
if (t.length) {
$('#myTabs a[href="#' + t + '"]').tab('show');
}
});
</script>