Our plan is to use the TabStrip component as a contaner for Grids and other content. We would like a combination of:
http://demos.telerik.com/aspnet-mvc/tabstrip/accessibility
and
http://demos.telerik.com/aspnet-mvc/tabstrip/ajaxloading
(the latter of which we are currently using)
Are there any examples for this/could you give us any hints? We would like the tab content to stay in separate pages to avoid clutter in the main file and are using MVC3 and Razor if that makes any difference.
Kind regards
Victor Ström
19 Answers, 1 is accepted
We currently do not have example which covers your requirements.
Nevertheless you can achieve your goal with the following actions:
1. Define TabStrip UI component without setting items' content:
<% var tabstrip = Html.Telerik().TabStrip()
.Name(
"TabStrip"
)
.Items(tabstrip =>
{
tabstrip.Add()
.Text(
"ASP.NET MVC"
)
.ImageUrl(
"~/Content/Common/Icons/Suites/mvc.png"
)
.ImageHtmlAttributes(
new
{ alt =
"ASP.NET MVC suite logo"
})
.Url(Url.Action(
"Accessibility"
,
"TabStrip"
,
new
{ selectedIndex = 0 }));
tabstrip.Add()
.Text(
"Silverlight"
)
.ImageUrl(
"~/Content/Common/Icons/Suites/sl.png"
)
.ImageHtmlAttributes(
new
{ alt =
"Silverlight suite logo"
})
.Url(Url.Action(
"Accessibility"
,
"TabStrip"
,
new
{ selectedIndex = 1 }));
}).toComponent();
%>
2. Depending on the posted selectedIndex select item and apply appropriate content:
<%
tabStrip.Items[selectedIndex].Content = () => Html.RenderPartial(
/* Determine which partial Grid to render*/
);
%>
3. Render the tabstrip.
tebStrip.Render();
Second option is to not use accessible TabStrip UI component (will not post on every item select) and define LoadContentFrom Action methods, which will render partial grids. If you need to avoid rendering Grids with same IDs, you can empty Content of all items and then put the content returned from defined Action method into current selected item.
Georgi Krustev
the Telerik team
/Victor
I have now started putting this code to work, but am having some issues. Using this type of code (Razor syntax):
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
@{
var tabStrip = Html.Telerik().TabStrip()
.Name("TabStrip")
.Items(tabstrip => {
tabstrip.Add()
.Text("Tab 1")
.Selected(true);
tabstrip.Add()
.Text("Tab 2");
}).ToComponent();
//Commented for now, but basically works
//switch(tabStrip.SelectedIndex) {
// default:
// tabStrip.Items[0].Content = () => Html.RenderAction("Companies", "Companies");
// break;
//}
<
text
>
Testing some text
</
text
>
//Tried both with and without flush
Response.Flush();
tabStrip.Render();
<
text
>
Testing some text
</
text
>
}
I get this output (note that the tabstrip is at the very top of the document, even before the <html> tag! (The test text is positioned correctly though)Have I misunderstood anything or do you have any suggestions of how to solve this?<
div
class
=
"t-widget t-tabstrip t-header"
id
=
"TabStrip"
><
ul
class
=
"t-reset t-tabstrip-items"
><
li
class
=
"t-item t-state-default t-state-active"
><
span
class
=
"t-link"
>Administer Companies</
span
></
li
><
li
class
=
"t-item t-state-default"
><
span
class
=
"t-link"
>Revive Deleted Companies</
span
></
li
></
ul
></
div
><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<
html
xmlns
=
"http://www.w3.org/1999/xhtml"
>
<
head
>
Thanks
/Victor
Using Render() with razor will not currently work. Render() uses the Response.Write which is not supported by Razor. As a workaround you can try this:
@{
var tabStripBuilder = Html.Telerik().TabStrip()
.Name("TabStrip")
.Items(tabstrip => {
tabstrip.Add()
.Text("Tab 1")
.Selected(true);
tabstrip.Add()
.Text("Tab 2");
});
var tabStrip = tabStripBuilder.ToComponent();
//other code
}
<!-- render the tabstrip -->
@tabStripBuilder
Atanas Korchev
the Telerik team
Unfortunately we now get the case where the content of the tab is displayed first, then the tabstrip component with the content again. I'll attach a screenshot to show the result. The grid is a partial view, produced by the Companies view. The code producing this is:
var tabStripBuilder = Html.Telerik().TabStrip()
.Name("TabStrip")
.Items(tabstrip => {
tabstrip.Add()
.Text("Administer Companies")
.Selected(true);
tabstrip.Add()
.Text("Revive Deleted Companies");
});
var tabStrip = tabStripBuilder.ToComponent();
switch(tabStrip.SelectedIndex) {
default:
tabStrip.Items[0].Content = () => Html.RenderPartial("Companies");
break;
}
<
text
>
Testing some text
@tabStripBuilder
</
text
>
<
text
>
Testing some text
</
text
>
}
Also, to explain a bit more, when removing the @tabStripBuilder line nothing is shown.
The first grid (the one outside the tabstrip) is produced by the server-side code, the inner grid (with the menus(!), why is that?) is fetched using ajax after the page loads.
/Victor
@tabStripBuilder is actually what renders the tabstrip. The @ symbol in Razor does the output.
The second may occur if you have both a view and a partial view named Companies (Companies.aspx and Companies.ascx). RenderPartial picks the aspx first.If you need further assistance please attach a working project to this thread.
Regards,
Atanas Korchev
the Telerik team
Attached is a project which demonstrates the behaviour discussed. It uses Asp MVC 3 RC2.
/Victor
This seems to work as expected:
switch(tabStrip.SelectedIndex) {
default:
tabStrip.Items[0].Html = Html.Action("ThePartialView").ToHtmlString();
break;
}
Regards, Atanas Korchev
the Telerik team
So - after changing that and figuring some other things out most things basically work, however when I try to add the Ajax support (as in the second example in the first post) i get "You cannot set Url and ContentUrl at the same time.". How do I hook up the Ajax call for browsers that supports it? Right now I basically have:
@{
var tabStripBuilder = Html.Telerik().TabStrip()
.Name(
"TabStrip"
)
.Items(tabstrip =>
{
tabstrip.Add()
.Text(
"Tab 1"
)
.Url(Url.Action(
"Index"
,
"Home"
,
new
{ selectedIndex = 0 }))
.LoadContentFrom(
"ThePartialView"
,
"Home"
);
tabstrip.Add()
.Text(
"Tab 2"
)
.Url(Url.Action(
"Index"
,
"Home"
,
new
{ selectedIndex = 1 }))
.LoadContentFrom(
"ThePartialView2"
,
"Home"
,
new
{ selectedIndex = 1 });
})
.SelectedIndex(Convert.ToInt32(ViewBag.selectedIndex));
var tabStrip = tabStripBuilder.ToComponent();
switch
((
int
)tabStrip.SelectedIndex) {
case
1:
//Second tab
tabStrip.Items[1].Html = Html.Action(
"ThePartialView2"
).ToHtmlString();
break
;
default
:
tabStrip.Items[0].Html = Html.Action(
"ThePartialView"
).ToHtmlString();
break
;
}
Edit: Also there seems to be a bug in the code that selects the active tab. If I leave out the "selectedIndex = 0" part (which should not be needed since that is the default) BOTH tabs are selected visually when going to the second tab and none of them are clickable.
/Victor
Thank you for reporting this. We are currently fixing the described behavior, though it requires quite a few changes in the code (serialization and client-scripts of both TabStrip and PanelBar). I will post a follow-up with an updated build on Monday next week (27th).
Happy holidays,
Alex Gyoshevthe Telerik team
Attached is the updated build, as promised.
Best wishes,Alex Gyoshev
the Telerik team
Do you have any pointers for the main issue described, "You cannot set Url and ContentUrl at the same time."? How do I hook up the Ajax call for browsers that supports it? Or is that addressed as well in the hotfix?
Thanks again
/Victor
Indeed, that was the problem that took so long to fix. You can use both Url() and LoadContentFrom() at the same time -- the content will be loaded from the LoadContentFrom() location if the user has JavaScript enabled, and navigate to Url() if JavaScript is disabled (or the user middle-clicks the tab, opening it in a new browser tab).
Regards,Alex Gyoshev
the Telerik team
/Victor
After trying out the new build, most things seems to work. Very nice! The one real issue I'm having is that the first tab is open as well as the second one when using the tabstrip without javascript and clicking the second tab.
(Code-wise, apart from both tab headers being active I also get double divs (both id TabStrip-1 and TabStrip-2 are set as display:block, however only the second one is (as is expected) filled with any content).
Edit: I just discovered a second issue: Navigating to ...?SelectedIndex=1 (second tab) takes you to the second tab when javascript is turned off (expected behaviour). However, when js is turned ON behaviour is very strange. It seems like the second tab is loaded is loaded server-side as it should be, however after that the first tab is loaded using ajax and focus is switched to that tab.
On a side note, would it be possible to get this behavious with less [repeated] code? I feel that I basically would like to specify the action method in the controller (or similairly in the view) as
public
ActionResult Index(
)
{
ViewBag.Tabs =
new
[]
{
new
{
title =
"Administer Persons"
,
actionName =
"Persons"
,
controllerName =
"Persons"
},
new
{
title =
"Revive Persons"
,
actionName =
"RevivePersons"
,
controllerName =
"Persons"
}
};
return
View();
}
Of course some extra parameters would be needed like serverOrAjax = both, serverSideIndexVariable = "selectedTabIndex", ... but basically that kind of configuration would (should?) be all needed for a complete ajax + accessible serverside solution, which additionally would be very easy to implement and replace an existing structure with.
Any chances of that happening anytime soon?
Thanks
/Victor
Please take a look at the attached solution. It shows how to implement the requirements for an accessible tabstrip + AJAX content (if JavaScript is available) with the available API of the tabstrip. We don't have plans of supporting this scenario out-of-the-box, since it is quite specific. We would happily promote this as a code library, though, since others might find it useful, too.
All the best,Alex Gyoshev
the Telerik team
Thanks for the solution. After switching to the latest dll (2010.3.1303) and scripts, and using ItemAction as you do, everything works as expected - however very strange results occur if you specify "too much" directly in Items.
Specifically:
in "item.Add(...)" currently Text and ContentUrl can be put. If Url is specified here specifying selectedIndex=1 (second tab) gives the content of the second tab twice, on top of each other. Ajax does not work starting from second tab.
Html content for currently selected tab can be specified either in itemAction (using if(item.Selected)) or as suggested before using tabStripBuilder.ToComponent().Items[selectedIndex].Html = ...
Edit: Specifying Html outside of itemAction does not work if ContentUrl is not set in the items.Add() clause.... Even more confusing...
All in all very confusing behaviour to me - very unclear what makes things work in one place and not in the other, especially since everything can be specified in both.
All in all though, I'm happy to say that things now work as expected - very nice! Next step is to get a grid to work inside (and dropdowns inside the grid's editor). Right now the grid show with data as expected, but is unable to use ajax for any actions and reverts back to server-side behaviour. If you have any quick pointers about that that would be appreciated, anyway I'm greatful for the help so far!
/Victor
Regarding the problem with the grid -- components that are loaded through AJAX do not register their scripts by themselves, so you need to include them manually.
I am not experiencing the confusing behavior -- maybe I am not getting it. The following code works, but using ItemAction is more concise:
tabstrip.Add()
.Text(
"Sitefinity ASP.NET CMS"
)
.LoadContentFrom(Url.Action(contentLocations[4]))
.Url(Url.Action(
"Index"
,
new
{ selectedIndex = 4 }))
.ImageUrl(
"~/Content/Icons/Suites/sitefinity.png"
)
.Content(Html.Partial(contentLocations[4]).ToHtmlString());
Greetings, Alex Gyoshev
the Telerik team
/Victor