Manage tabbed content with full support for routing - c#

I'm building an Asp.net mvc 3 application. What I want to do, is a profile page (pretty mutch like the stackoverflow profile page), and the content of this page will be splited in tabs, each tab is represented by an PartialView.
When the user click on the tab X, I want to refresh only the tab area, without refreshing all my page. And in the same time changing my URL adress, so if the user click on the browser refresh button, it refresh the page with the selected tab. Is this possible ?
What I already know, is how to get data using AJAX, and replace the content of my view. I've read this post , I found it interesting, but it refresh all the page.
Thanks in advance.

You are on the right track. You will need to use both ajax to get the html to render without refreshing the page, as well as use push state to update the URL to include the current tab.
You could do these things as separate operations, but I would suggest using PJAX. With PJAX you will need a little additional logic in your server to decide whether to return the full html page with the layout, or just return the partial (a PJAX request).
Here is our Foo controller. Index has a default selected tab of "Bar". The Bar and Baz actions return the Index view, but with different tabs being the selected tab. If it is a PJAX request, then all we need is the partial view that fills in the tab content.
public class FooController : Controller
{
public ActionResult Index()
{
ViewBag.SelectedTab = "Bar";
return View();
}
public ActionResult Bar()
{
if(Request.Headers["X-PJAX"] != null)
return PartialView();
ViewBag.SelectedTab = "Bar";
return View("Index");
}
public ActionResult Baz()
{
if (Request.Headers["X-PJAX"] != null)
return PartialView();
ViewBag.SelectedTab = "Baz";
return View("Index");
}
}
Inside of the Foo/Index.cshtml we have the Razor code that will determine what partial view to render based on ViewBag.SelectedTab.
#{
ViewBag.Title = "Foo";
}
<h2>Foo</h2>
<ul>
<li><a class="tabs" href="#Url.Action("Bar", "Foo")">Bar</a></li>
<li><a class="tabs" href="#Url.Action("Baz", "Foo")">Baz</a></li>
</ul>
<div id="tab_content">
#if(ViewBag.SelectedTab == "Bar")
{
#Html.Partial("Bar")
}
#if (ViewBag.SelectedTab == "Baz")
{
#Html.Partial("Baz")
}
</div>
#section scripts
{
<script type="text/javascript">
$(function() {
$(".tabs").pjax("#tab_content");
})
</script>
}
The script section at the end is how you wire up PJAX. You are telling it, for all hyperlinks with the tabs class use pjax to dynamically load and render the html resulting from the href into the container with the id tab_content and update the url in the browser to be the url from the href.
Each tab's partial view is fairly simple in this scenario
Bar.cshtml
<p>This is the Bar tab. No pun intended.</p>
Baz.cshtml
<p>This is the baz tab.</p>
This is obviously a very simplified solution. You typically would want to use a presentation model to handle the logic of the view. Also, I have intentionally left out any tab styling to demonstrate that this technique can be used on any type of link. It is not limited to only tabs.
The full source code for this example can be on my GitHub site.

When the user click on the tab X, I want to refresh only the tab area, without refreshing all my page. And in the same time changing my URL adress, so if the user click on the browser refresh button, it refresh the page with the selected tab. Is this possible ?
To accomplish this you need to plug into browser's history API (and it's part of HTML5, and you'll have to use some kind of plugin to get the same thing in browsers that does not support it).
Manning's "HTML5 for .net developers" has pretty good section on that, but it's still in "early access".

Related

how to call c# function in razor page with out redirect page

this goal page
as in the link above
I want to see the sub-object of the tree on the web, so if I press the ▶ button, I want to search the DB through efcore.
To solve this, I thought about how to execute a specific function in cshtml, but I realized that the problem is that even if the function is executed, there is no change in the view.
Whenever the ▶ button to view sub-items in the tree is clicked, I want to search for sub-items in the DB and update the view without page redirection.
I tried using the redirect method. it is not comfortable
cshtml
#if (Model.authority)
{content }
cshtml.cs
public IActionResult OnPostChagneMainCategorySelect()
{
return RedirectToPage("/MyPage/Leader", new
{
_selectionWorkState= workState,
_selectionItem = searchingItems,
_selectionMain = searchingCategorys,
});
}
If you want to return the same page you are on you can use
return Page();

MVC3 razor return current view

I've got a actionlink in my master page _Layout That when pressed, changes the layout of my menu. But I don't want the current Content of my page to change.
How can I accomplish this with MVC3 razor without using javascript?
I'm guessing it will be something along the lines of:
Button is clicked postback happens
Set some value so changed menu state persists
Return previous view
Especially the "return previous view" part perplexes me, could someone explain how to accomplish this?
In your controller override OnActionExecuting:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.QueryString["MenuLayoutName"] != null && IsValidMenuLayoutName(filterContext.RequestContext.HttpContext.Request.QueryString["MenuLayoutName"] != null))
ViewBag.MenuLayoutName = filterContext.RequestContext.HttpContext.Request.QueryString["MenuLayoutName"];
}
In your _Layout.cshtml when you render the menu, look at the ViewBag.MenuLayoutName to decide which menu to use. The most efficient way is to simply create partial views so you can render the menu as follows:
#{ Html.RenderPartial(ViewBag.MenuLayoutName); }
However, take note of the call to IsValidMenuLayoutName! Otherwise people could put the name of any valid partial view in there and get it rendered where you expect your menu to appear.
In your links where you want to allow the user to select the various menu layouts, change your link to the page to specify the name of the layout to use.
Use Red Menu
Using a VERY primitive approach, you can create buttons essentially linking to itself:
Foo Menu
Bar Menu
(Or use logic to show either/or based on what's visible) Then modify your _Layout.cshtml to render what's provided:
#{
String menu = (String)Request.Params["menu"] ?? "foo";
if (menu == "foo"){
/* Foo menu render */
} else {
/* bar menu render */
}
}
Then it's just a round-trip to the same URL. Again, if they landed on the page via POSTed information, you'll lose that. Also, I didn't add logic to test if menu already existed in the request, but you should.

Telerik Styles with multiple views in ASP.NET MVC

In a previous post I had trouble setting the styles on my views in the same way that they do it on the telerik demo site by selecting the style from a dropdown. This was answered however I now have a new but related problem.
I have multiple pages on my site (as is common to MVC) and each of these pages have many telerik controls on them. Allowing the user to style the site using predefined css done for me is great and saves me a lot of work.
The problem is that when I move from page to page, the combo box that telerik uses resets to its default value, thus resetting the styles on the site everytime the user changes a pages (not ideal).
I have tried using sessions to store the state, but there is no way to detect postback like with standard aspx development. So I cant do something like:
if(isPostBack)
{
if(string.isNullOrEmpty(Session["MyTheme"]+""))
{
Session["MyTheme"]="black";
}
else
{
Session["myTheme"]=//Some combo box selected value
}
}
Even if I could, the combo box onChange event is handled via JavaScript but the Telerik control requires C# Razor and try as I mgiht, I cant get them to talk and share a simple value.
Ultimately all I want to do, is allow the user pick a theme from the combo box and from then on, that theme is remembered throughout the site until they next change it.
I have tried query strings and sessions, but neither work as I cant access them in JavaScript. Aparently they are used on the server side only.
I have tried cookies but that doesnt work because I cant access them in C# Razor. Aparently they are client side only.
Below is my code:
<head>
#(
Html.Telerik().StyleSheetRegistrar()
.DefaultGroup(group => group
.Add("telerik.common.css")
.Add(string.IsNullOrEmpty(#Html.ViewContext.HttpContext.Request.QueryString["theme"]) ? "telerik.black.css" : "telerik."+#Html.ViewContext.HttpContext.Request.QueryString["theme"]+".css").Combined(true).Compress(true)
))
</head>
<body>
#(
/* TELERIK COMBOBOX */
Html.Telerik().ComboBox()
.Name("cbxTheme")
.SelectedIndex(0)
.ClientEvents(events => events.OnChange("cbxTheme_onChange"))
//.BindTo((IEnumerable<DropDownItem>)ViewData["Files"])
.Items(item =>
{
item.Add().Text("black");
item.Add().Text("common");
item.Add().Text("default");
item.Add().Text("forest");
item.Add().Text("hay");
item.Add().Text("metro");
item.Add().Text("office2007");
item.Add().Text("office2010black");
item.Add().Text("office2010blue");
item.Add().Text("office2010silver");
item.Add().Text("outlook");
item.Add().Text("rtl");
item.Add().Text("simple");
item.Add().Text("sitefinity");
item.Add().Text("sunset");
item.Add().Text("telerik");
item.Add().Text("transparent");
item.Add().Text("vista");
item.Add().Text("web20");
item.Add().Text("webblue");
item.Add().Text("windows7");
})
)
#(Html.Telerik().ScriptRegistrar().DefaultGroup(group => group.Combined(true).Compress(true)))
</body>
<script type="text/javascript">
function cbxTheme_onChange()
{
var selectedItemText = $("#cbxTheme").data("tComboBox").text();
//var selectedItemValue = $("#cbxTheme").data("tComboBox").value();
window.location.href = window.location.protocol
+ '//'
+ window.location.host
+ window.location.pathname
+ '?theme='
+ selectedItemText;
}
</script>
As I explained, for the most part it works fine. Execpt when I click on a likn to another page. Then everything gets set back to a preset default.
Ideally what I am looking for is a way to do a postback when a new item is selected in the combo box (like in the JavaScript). The style is changed so the whole page needs to be refreshed anyway. This works. But when I move to another page, it resets to a default style. So I need a way to store the selected style either client side or server side (preferred as my pages are loaded this way).
I have read this can be done by using a controller but it is not clear how. I would like the controller method if possible, because I am going to use a controller to load a list of CSS styles dynamically allowing the user to download additional styles and they will be added to the list automatically. So anything along this line would be great.
You can create a static class with a static property which will act as a global property.
public static class MyTheme
{
public static string MyGlobalTheme { get; set; }
}
or you could you the Application class.
Application["MyTheme"] = "black";
You could put this code in _Layout.cshtml. If your project name is TProj and your static class is in a folder called Objects, it would look like this.
_Layout.cshtml
#{
if (#Html.ViewContext.HttpContext.Request.QueryString["theme"] != null)
{
TProj.Objects.MyTheme.MyGlobalTheme = Html.ViewContext.HttpContext.Request.QueryString["theme"];
}
else
{
if (TProj.Objects.MyTheme.MyGlobalTheme == null)
{
TProj.Objects.MyTheme.MyGlobalTheme = "black";
}
}
}
Now in after this in _Layout.cshtml, you can use the string #TreasuryReportsMvc.Objects.MyTheme.MyGlobalTheme, which should stay the same even when you go to another page. _Layout.cshtml may not be the best place for this logic. You should think about where it makes the most sense for your project.
Be aware that global variables are frowned on by many. This question has a good discussion of Asp.Net MVC global variables.

scripts doesn't executed after partial rendering in mvc, why?

I used mvc 4.0 to develop my web application, I have created a pager and data-list it works fine, I implement it by some jquery code and I define $.get jquery method to get a partial view as new page like this :
$.get("http://localhost:13824/bid/index?page=8&script=1", function(data) {
$Element.html(data);
}
on the other side in control I have Action method like following :
public ActionResult Index(string provinceNo="21", int page=1, string script="0"){
if(script=="1") { return PartialView("mypartialwebusercontrol",model); }
else // do something else;
}
in the web user control I have some items it loads all items and my pager works very nice but there is a problem I have link in each item that is for opening a popup window when I click on pager it calls $.get method. all click events and scripts wont be rise again.
my web user control is like this :
<% control language="c#" inherits="system.web.mvc.viewusercontrol<model>" %>
<% foreach(var item in model) { %>
<div id="card1">
<a class="linkbutton"> item.text1 </a>
</div>
<% } %>
all of the click script will be stop after $.get method calling.
Still not sure what you mean by 'in constructor', but I can see two possible causes of the problem:
One, you are running the bind before you load the html and consequently the linkButtons aren't bound. Solution is to run the bind after loading, or better, use .delegate on the container you are loading into.
Two, when the browser is running the $.get method or any javascript after that, it is hitting an error and stopping executing any more scripts.
If its neither of these, you'll need to give a full listing of your Javascript or a link to a page where me or someone else can see exactly what's going on

Is this project doable in ASP.NET MVC?

I am new to Stack Overflow and to ASP.NET MVC.
I have been asked to do a project where I want to use ASP.NET MVC, but I have some problems wrapping my head around it and I hope some of you could get me in the right direction.
The project is a kind of a search portal. On every page there is a dropdown box where you basicly select the dataset (it's based on books) you want to search. In the dropdown is the name of the book you want to search.
Of course there is also a search field. These 2 objects are on every page and has the same function on all pages, and I can't get these 2 objects to communicate.
I have these 2 in separate partialviews and want to generate an action for the search formfield something like this:
domain.com/{bookname}/search/{searchterm}: this is the thing created from the dropdown and the search box.
But can I do this in the searchfields partialview in some way, or do I have to grab these value in each controller?
I hope this makes any sense.
Create a partial view with your dropdown and textbox, using the BeginForm helper:
<% using(Html.BeginForm("Index", "Search")) %>
<% { %>
<%= Html.DropDownList("BookNames") %>
<%= Html.TextBox("SearchTerm") %>
<% } %>
Then in your SearchController's Index action, you should be able to grab the values from the form collection or using your dropdown's and textbox's id.
public ActionResult Index(FormCollection frmCollection)
{
// ...
// also you can redirect to another action/controller if you needed
// return RedirectToAction("...", "...");
}
or
public ActionResult Index(int bookNames, string searchTerm)
{
// ...
// also you can redirect to another action/controller if you needed
// return RedirectToAction("...", "...");
}
Hope this helps.
I have implemented a similar search requirement on one of my projects with ASP.NET MVC. However, I had the Dropdown and Search in a single Partial View.
I then used Javascript to pick up the selected values and redirect the user to the URL with pattern domain.com/{criteria}/search/{searchWord}.
This way I had to use a single controller to search, with a single view to view search results.

Categories

Resources