Dynamic 2-level menu in web apps - asp.net-mvc

I'm looking to create a top-level horizontal menu, with a second-level horizontal menu below it. Clicking on the top level menu causes the second level menu to change, based on the top level one. clicking on a second level menu causes the content of the page to change.
(BTW - I'm looking to do all this in ASP.NET MVC, so if you have any insights specific to this framework, please share them).
I'm not sure what's the best way to do the two-level menu, so there are zero page refreshes while the user plays with the top level menu. (CSS menu? javascript manipulating the page? a combination of both?)
How do I make the app refresh/redirect/load only the bottom pane (the main content of the page), rather than the entire page? ASP.NET MVC is pretty much full-page oriented by default. Should I frame its pages?
I'm a hard-core server developer working on his first web app, so be gentle... :)

#Shachar, you're asking 2 questions in one post, that's not the best way to use this site. :-)
I'm not sure what's the best way to do the two-level menu, so there are zero page refreshes while the user plays with the top level menu.
In my comment I have linked you to the original Suckerfish article, which has become a very common / perhaps the most common way of doing this. David Liddle showed you a more more recent implementation of Suckerfish using jQuery; if you're already using jQuery then this is IMHO the best solution today.
Since you're asking about the ASP.NET MVC angle, Syncfusion has a package of GUI widgets for ASP.NET MVC, and Telerik is building one using jQuery and community involvement. Not sure if any of them have a menu widget yet...
How do I make the app refresh/redirect/load only the bottom pane (the main content of the page), rather than the entire page? ASP.NET MVC is pretty much full-page oriented by default.
Hmn, I don't think ASP.NET MVC is "full-page oriented", there are just many different opinions on how to do AJAX. ASP.NET MVC gives you excellent building blocks for AJAX, not the full solution.
First off, are you sure you want to do this? I think what you're referring to is "AJAH", Asynchronous JavaScript And HTML. From this article about AJAH: "With true AJAX, a call is made to the server, the nicely formatted data is returned and the client application extracts the data from the xml, and replaces whatever elements need to be replaced on a page. With AJAH, a glob of html is returned and slapped into the page.".
AJAH isn't used that often today, for the following reasons:
You're not saving a significant amount of page weight (bytes) compared to a more conventional approach that uses caching to reduce subsequent page weights.
You're not separating data and presentation, so your code is less clean, and you're not building something that would be re-usable in an API or SOA approach later on.
IMHO the best use of AJAX right now, with regards to (usability improvement) versus (development and QA time) required, is to let high-ROI pages load datasets via AJAX. For example, a statistics section of a webapp might load as a normal page (with an initial dataset showing the graph the user most likely wants), and allow the user to change the graph via an AJAX call for new data.
IMHO you should also consider unobtrusive Javascript. It's kind of hard to explain, but it starts with a simple question: "What if the user agent doesn't support Javascript?". In my graph example above, the user would be out of luck, because he could not change the graph without Javascript. Here is a good presentation showing unobtrusive Javascript examples.
The other side of the coin is full-blown AJAX (like GMail), where more or less everything is built using Javascript UI widgets. This requires quite a lot of effort to build...
Assuming you want to go the AJAX route, here is one short introduction to AJAX using ASP.NET MVC and jQuery. After that, perhaps one of these books could be helpful?

Take a look at jQuery's superfish plugin
http://users.tpg.com.au/j_birch/plugins/superfish - go to Examples and nav-bar style
This works by building up a html list and uses jquery and css to style it.
<ul>
<li>Top level item 1
<ul>
<li>Sub item</li>
</ul>
</li>
<li>Top level item 2
<ul>
<li>Sub item</li>
</ul>
</li>
</ul>
Each item could/should relate to a controller/action method. You will then have to work out which controller/action you are viewing to make sure the correct menu item is selected for each page.
Here's a menu.ascx partial view I created.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% string menu = ViewContext.RouteData.Values["Controller"].ToString().ToLower(); %>
<% string submenu = ViewContext.RouteData.Values["Action"].ToString().ToLower(); %>
<div id="navigation">
<ul id="menu" class="nav-menu nav-navbar">
<% if (menu=="home") { %><li class="current"><% } else { %><li><% } %>
<%= Html.ActionLink("Home", "Index", "Home") %>
<ul></ul>
</li>
<% if (menu=="configuration") { %><li class="current"><% } else { %><li><% } %>
<%= Html.ActionLink("Configuration", "Index", "Configuration") %>
<ul>
<% if (menu=="configuration" && submenu=="page") { %><li class="current"><% } else { %><li><% } %>
<%= Html.ActionLink("Pages", "Pages", "Configuration") %>
</li>
<% if (menu=="configuration" && submenu=="headline") { %><li class="current"><% } else { %><li><% } %>
<%= Html.ActionLink("Headlines", "Headlines", "Configuration") %>
</li>
<% if (menu=="configuration" && submenu=="file") { %><li class="current"><% } else { %><li><% } %>
<%= Html.ActionLink("Files", "Files", "Configuration") %>
</li>
<% if (menu=="configuration" && submenu=="rules") { %><li class="current"><% } else { %><li><% } %>
<%= Html.ActionLink("Application Rules", "Rules", "Configuration") %>
</li>
</ul>
</li>
...

Related

Display selection of index in a partial

I've been trying to solve the following challenge all day without any luck.
When going through forum posts I came across jQuery and AJAX which are both new concepts to me and which I'd rather skip for now, if possible.
I've got a partial, "navbar-left", which shows a list of all bank accounts in my model Account.
When the user clicks on one of the items in the list, all transactions of that account should be shown in the same page at the right. The partial below links to a new page which is not how I'd like it.
The navbar-partial:
<ul class="nav nav-pills nav-stacked">
<% #accounts.each do |account| %>
<li role="presentation"><%= link_to account.account_holder, account_mutations_path(account.id) %></li>
<% end %>
</ul>
Any tips on how to get this fixed is much appreciated!
The page with the navbar at the left
The mutations in a separate page instead of a partial
Either you're sending viewers to a new page, or dynamically loading content within their current page.
If the latter, then the only solution is AJAX.
Luckily, Ruby on Rails makes transitioning from one to the other very easy.
Here is a gist of how it works:
<%= link_to account.account_holder, account_mutations_path(account.id), remote: true %>
This was pointing back to some page previously (e.g. action.html.erb).
Because of remote: true, it's going to be sending JS directly to the browser instead of a new HTML page (e.g. action.js.erb in the same view folder and same action name).
Here we can control the behavior we want by rendering a partial using ERB and using JS to change the HTML content of some part of the page:
// action.js.erb
$('#some_element').html('<%= j render "partial" %>')
Which will insert the HTML of the partial directly into the JQuery that changes the content dynamically.
Where j is a shorthand for escape_javascript.
Without escaping, the Ruby output is interpreted as file output and newlines would break your JS.
Example JS output without escaping:
// Bad
$('#some_element').html('<span>Content</span>
<span>More Content</span>')
Example with escaping:
// Good
$('#some_element').html('<span>Content</span>\n<span>More Content</span>')
http://guides.rubyonrails.org/working_with_javascript_in_rails.html
https://launchschool.com/blog/the-detailed-guide-on-how-ajax-works-with-ruby-on-rails
There are more great examples online and even Railscasts.
Really AJAX is the best way to do this, and it's not as complicated as you might think. But if you really want to skip AJAX then your best approach is probably to load ALL transactions for all accounts, in different div's and then show or hide them based on which is clicked.
For a rudimentary introduction to this look at javascript tabs... you click on a tab, the appropriate information is shown.
http://www.w3schools.com/howto/howto_js_tabs.asp
You can do this very simply without ajax. The big difference would be - it's not the same page. One page would be the account#index (as you have now), the other page is the account#show page.
For the show page, use a very similar view as the index page, the left side would include the partial with one of the account li class="active" to highlight the account you are currently on. For the right side of the page, render the account mutations list items.

How can I load a div in rails in response to clicks on another div?

I'm very new to Rails (and web) programming, so I'm not even sure what technology I should be looking for for this.
I've downloaded and run through the first five chapters of the Rails tutorial, but now have a very simple request.
On the left hand side of a web page, I will have a table. If the user clicks on an element in that table, I want to have the right hand side of the page show something new.
I already have a page to display the table, viz:
<div class="center hero-unit">
<div class="container">
<h2>2012 Yearly Report</h2>
<div class="row-fluid">
<div class="span12">
<div class="span4">
<table border="1">
</table>
</div>
<div class="span6">
<!-- load stuff here based on what someone clicks on in the table -->
</div>
</div>
</div>
</div>
</div>
And I'm using bootstrap layouts to display everything. I just don't understand how to change the contents of the 'span6' div based on user behavior in 'span4'.
This is a difficult question to answer. It really depends on what kind of data you're trying to display and what sort of interactivity you're looking for.
You don't really provide much information about what you're trying to accomplish, but if I had to guess, you're trying to load data from your database and insert it into an element without leaving the current page. This is what AJAX is for (your tutorial goes into it a bit in chapter 11) and involves a good deal of javascript, which is generally beyond the scope of a server side language like Ruby. Luckily, rails includes helpers for making it easy to include AJAX features into your web application without having to write a lot of javascript (although you'll have to write some).
As an example, suppose your table has a list of articles, and you want to display the contents of an article in a div when its link is clicked on.
First the link:
<%= link_to article.name, article_url(article), :remote => true %>
The remote option tells Rails that it's an AJAX link.
Next, you need to render a javascript template for your article's show action. You'll name it show.js.erb.
Supposing the div you want the data to be loaded into looks like this,
<div id='article-content'></div>
you'll want your show.js.erb to contain the following:
$('#article-content').html("<%=javascript_escape #article.content %>");
This javascript (with embedded ruby) code will be evaluated when one of your remote links is clicked and will replace the content of your div with the article's content.
There is plenty of resources online to give you more information. It looks like railscasts just released an episode on this topic just a week ago. It requires a subscription to view, but is well worth it (especially if you're just starting out).

Asp.Net MVC - RenderPartial - Create in a List view

I got a page that lists all my articles (Articles/List.aspx).
I also got a control that create article (Article/Create.ascx).
I will like that my List.aspx page that's render the Create.ascx to be able to create article.
I know that in MVC, the preferred approach is one page by action. But in this case I need to do that. It's a design issue and how the client want the Web site to work.
So for now, I got the following code in List.aspx :
<% Html.RenderPartial("Create", new Domain.Models.Article()); %>
That render correctly. But when I hit the create button, it's doesn't go in the Create[post] method of my ArticleController.
Any idea why and how I could resolve that issue ?
If you have problems with the button, it's not going to have anything to do with how you're rendering the user control. We need to see the form markup that the button is inside, that will show what the problem is most likely.
But just for reference, you're probably looking to do something like this:
<% using (Html.BeginForm("Create",
ViewContext.RouteData.Values["Controller"].ToString())) { %>
your control markup here
<% } %>

Display different forms on Index page depending upon link clicked in ASP.NET MVC

I have a menu control on Index page rendered as <% Html.RenderPartial("MenuUserControl"); %> where MenuUserControl is something like
<li><%= Html.ActionLink("Link1","Index") %></li>
<li><%= Html.ActionLink("Link2", "Index")%></li>
<li><%= Html.ActionLink("Link3", "Index")%></li>
Now I wan to load three different form in Index page itself onclick of these links, with first form being loaded on Page load. How can I do this. Any help is appreciated.
If you need to pass information about links to RenderPartial
<% Html.RenderPartial("MenuUserControl", new[]{"link", "link"}); %>
however it's better to pass a custom model (class object) rather than array of strings.
Use Ajax.ActionLink to load form without page reload.
To load first form either do this in the Index page itself (add HTML tags or call RenderPartial to render form, or use RenderAction), or add script to the menu partial like this
<script type="text/javascript">
$(function(){ $("a").eq(0).click(); }
</script>
This requires jQuery, though.
If you don't know what I'm talking about then you better prepare to learn a lot.
You will need some sort of JavaScript library like jQuery to do this, the rest is imagination:
-You can pre-load the 3 forms on pageload and then hide the last two on DOM ready (PageLoad). i ll wrap this in div just for convenience.
<script type="text/javascript">
$(document).ready(function () { //This is like DOM ready
//here we hide the the last 2 forms
$('#div_id_form2').hide();
$('#div_id_form3').hide();
//Next set the events for the links (on click show form)
//on link 2 click
$('#link2').click(function(){
//show the second form
$('#div_id_form2').show();
});
//on link 3 click
$('#link3').click(function(){
//show the third form
$('#div_id_form3').show();
});
});
</script>
The other option is go the Ajax way but requires more code and knowledge in jQuery.
If you are interested refer to http://docs.jquery.com/ thats the API reference for jQuery.
If you are moving to MVC, I recomend you to learn any JavaScript library to help you with this kind of behaviors that some call DHMTL (Dynamic HTML).
First do the Non Ajax Version.
Have 1 page Index with 3 partials in it. Each partial has only the html for the form to display in it.
In your actions set the ViewModel (here Action Link1)
model.IsForm1Visible = true;
In your View use the model to display partials
<div id="linkContainer">
<% if(Model.IsForm1Visible){%>
<%= Html.RenderPartial("Form1")%>
<%}%>
<% if(Model.IsForm2Visible){%>
<%= Html.RenderPartial("Form2")%>
<%}%>
<% if(Model.IsForm3Visible){%>
<%= Html.RenderPartial("Form3")%>
<%}%>
</div>
If you need Ajax you can continue from there.

Designer-friendly views in Asp.Net MVC

I'm enjoying Asp.Net MVC and am looking to use it in an upcoming project. Part of the project, however, is an emphasis on being able to expose the project Views to designers for things like theming and so on. One problem I'm anticipating is that Asp.Net MVC views are rather developer-centric. I really don't want to have to educate designers on the intracies of <% vs. <%= let alone something like <% foreach ...
Take a typical MVC menu structure, for example.
<div id="menu">
<ul>
<li><%= Html.ActionLink("Home", "Index", "Main")%></li>
<li><%= Html.ActionLink("About", "About", "Main")%></li>
<li><% Html.RenderPartial("LogOnUserControl"); %></li>
</ul>
</div>
I'd much rather be able to tell designers to go with something like
<div id="menu">
<ul>
<li>{ActionLink "Home", "Index", "Main"}</li>
<li>{ActionLink "About", "About", "Main"}</li>
<li>{Partial "LogOnUserControl"}</li>
</ul>
</div>
Or
<div id="menu">
<ul>
<li><my:ActionLink text="Home" action="Index" controller="Main" /></li>
<li><my:ActionLink text="About" action="About" controller="Main" /></li>
<li><my:Partial name="LogOnUserControl" /></li>
</ul>
</div>
Yes, that last looks suspiciously like a raft of UserControls. Personally, I'm not a fan of actually using UserControls to do this if only because the rendering of those controls happens after pretty much everything else (as I understand it) and I'd prefer something that fits more in line with the MVC lifecycle. All I really need is a set of placeholders and a way to replace them with the relevant rendering.
So where's the best place to do so and what kind of trade-offs am I looking at here. I can imagine a couple of angles to come at this:
A custom ViewPage class where I can override something relevant. ViewPage.RenderView or ViewPage.FrameworkInitialize, maybe, but how you get at the text from there I don't know.
Create a custom TextWriter and override ViewPage.CreateHtmlTextWriter that I can then intercept the text output for replacing stuff. This is pretty late in the cycle, though, and will mess with other custom filtering if I'm not careful.
Create my own IView and ViewEngine classes. I didn't get far down this path before wondering if I was headed to a very bad place.
Custom UserControls that can mimic the functionality needed.
Opinions? Other options? Is my own ViewEngine my best option? My own ViewPage? Or are UserControl objects going to be adequate (please say no)?
Take a look at Spark. It's syntax is similar to your example.
As Charles Conway said, Spark is definitely way to go. Look at example. First, you create partial view in _ActionLink.spark with code:
<viewdata text="String" action="String" controller="String">
${ Html.ActionLink(controller, action, text) }
Then you use it like that in other views:
<ActionLink text="Home" action="Index" controller="Main" />
You just have to prepare partial views for your designers and then they an create view in prefered style. Isn't it easy?
EDIT:
Sorry, that was wrong. <ActionLink text="Home" action="Index" controller="Main" /> will not work, because Home, Index and Main are treates as variables. It may not be that easy to do it as you wish.
I have a similar requirement for a current project, except my 'designers' are more or less end users (people that know their way around html, but it's not their job) which leads to some additional challenges. My implementation is probably too specific for your needs but I'll quickly explain it lest it be useful to anyone else.
I wanted to totally avoid any kind of code in the views for the pages they would be designing so I decided to go with a templating system that does something similar to your point #2, but not at runtime. I am also using spark, although it's not for the benefit of the users as they won't be touching anything that looks like code.
Basically the users create a full html-only template that has placeholder tags for user controls and partial views. The users then upload the template through an interface that parses it and turns it into a spark view.
eg.
For a picture gallery, <gallery /> is parsed into something like !{Html.Gallery(Model)} or <use file="Gallery"/>. For a description field, <desc name="Kitchen" /> is parsed into !{Html.Description(Model, x => x.Descriptions.Kitchen)}. It also checks that "Kitchen" is in fact a property for the object/page that is being templated, or that the Model being passed in for a gallery actually contains a collection of images to avoid runtime errors.
Further properties can be specified in the tag to pass additional parameters to the parsed controls. If the control specified requires Javascript, then it is also included in the view. If there are any problems parsing, output is return specifying which placeholder is invalid and why.
While answered and accepted, I don't see the example of this: why don't you just use:
<li><a href='<%= Url.Action("Home", "Index")%>'>Main</a></li>
Similar in Spark. I prefer this to Html.ActionLink, Html.BeginForm, etc, whenever possible (almost always except for form controls where it's easier to have automatic name encoding with Html helpers).
And your designers do see the link.

Resources