Click here to Skip to main content
Click here to Skip to main content

Interactive Menu

, 5 Jan 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Concept of interactive menu based on user activity.

Introduction

In this post, I want to present one way of creating interactive menu based on specific user activity. The main idea is to show suitable menu for each user based on his previous actions. For this, I created a test ASP.NET MVC 3 application. It emulates the "Football News" web site where user can select a country to see its championship news. See the main menu below:

Presentation

As I said, each user would have appropriate menu based on his actions. Let's look at them.

The first one is Pedro Duarte. He is from Spain and usually he clicks on "Spain" menu item, but also he is interested in what happens in England Championship. Sometimes, if the Spain and England news has been read, he visit German, Italy, and France Championships. Thus, if Pedro Duarte goes to the website, he see the next menu:

Next user is Cole Jones. He is from England, therefore the most visited menu item is England Championship. Also, he usually visits Spain and Germany and sometimes Italy and France.

Daniel Weber is from Germany:

Antonio Rossi is from Italy:

Lucas Martin is from France:

So, the above pictures demonstrate the interactive menus that are presented in suitable view for each user. The user doesn't have to find this favorite Championship reading each menu item. He intuitively would know that his favorite items are emphasized and are on the top(left) of the list.

Using the Code

The data is stored in SDF database. For data manipulation, I use Entity Framework. The database structure is described below.

User table:

[Table("Users")]
public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [MaxLength(50)]
    public string Name { get; set; }
} 

Visit table:

[Table("Visits")]
public class Visit
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [MaxLength(50)]
    public string ContentId { get; set; }
        
    public int UserId { get; set; }
} 

Database context:

public class FanatContext : DbContext
{
    public FanatContext()
        : base("FanatConnection")
    {}

    public DbSet<User> Users { get; set; }

    public DbSet<Visit> Visits { get; set; }
} 

Connection string in web.config:

<add name="FanatConnection" 
  connectionString="Data Source=|DataDirectory|Fanat.sdf" 
  providerName="System.Data.SqlServerCe.4.0"/> 

Next class initializes the SDF database:

 public class FanatContextInitializer : CreateDatabaseIfNotExists<FanatContext>
{
    protected override void Seed(FanatContext context)
    {
        // USERS
        var userSpain = new User() { Name = "Pedro Duarte" };
        var userEngland = new User() { Name = "Cole Jones" };
        var userGerman = new User() { Name = "Daniel Weber" };
        var userItaly = new User() { Name = "Antonio Rossi" };
        var userFrance = new User() { Name = "Lucas Martin" };
        context.Users.Add(userSpain);
        context.Users.Add(userEngland);
        context.Users.Add(userGerman);
        context.Users.Add(userItaly);
        context.Users.Add(userFrance);
        context.SaveChanges();
        // FANS VISIT
        InitVisits(context, userSpain.Id, 100, 50, 20, 10, 5);
        InitVisits(context, userEngland.Id, 70, 150, 55, 30, 18);
        InitVisits(context, userGerman.Id, 42, 22, 110, 45, 10);
        InitVisits(context, userItaly.Id, 132, 29, 15, 200, 20);
        InitVisits(context, userFrance.Id, 69, 65, 50, 15, 70);

        base.Seed(context);
    }

    private static void InitVisits(FanatContext context, int userId,
        int spainVisits, int englandVisits, int germanVisits, int italyVisits, int franceVisits)
    {
        InitVisits(context, userId, ContenIds.Spain, spainVisits);
        InitVisits(context, userId, ContenIds.England, englandVisits);
        InitVisits(context, userId, ContenIds.Germany, germanVisits);
        InitVisits(context, userId, ContenIds.Italy, italyVisits);
        InitVisits(context, userId, ContenIds.France, franceVisits);
    }

    private static void InitVisits(FanatContext context, int userId, string contentId, int count)
    {
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                var visit = new Visit()
                {
                    UserId = userId,
                    ContentId = contentId
                };
                context.Visits.Add(visit);
            }
            context.SaveChanges();
        }
    }
} 

Controller has one view action - Index. It returns menu model based on user information. Menu items are ordered by rate value. This value is equal to visits by user.

public ActionResult Index()
{
    var menuMolel = new MenuModel();
    var userId = 0;

    int.TryParse(Request.Params["u"], out userId);
    menuMolel.SelectedId = userId;

    var items = new List<MenuItem>();
    items.Add(new MenuItem("Spain", ContenIds.Spain, GetVisits(userId, ContenIds.Spain)));
    items.Add(new MenuItem("England", ContenIds.England, GetVisits(userId, ContenIds.England)));
    items.Add(new MenuItem("Germany", ContenIds.Germany, GetVisits(userId, ContenIds.Germany)));
    items.Add(new MenuItem("Italy", ContenIds.Italy, GetVisits(userId, ContenIds.Italy)));
    items.Add(new MenuItem("France", ContenIds.France, GetVisits(userId, ContenIds.France)));

    menuMolel.Items.AddRange(items.OrderByDescending(x => x.Rate));
    menuMolel.Users.AddRange(GetUsers());

    return View(menuMolel);
} 
private int GetVisits(int userId, string contentId)
{
    using (var context = new FanatContext())
    {
        return context.Visits.Where(x => x.UserId == userId && x.ContentId == contentId).Count();
    }
}

private IEnumerable<User> GetUsers()
{
    using (var context = new FanatContext())
    {
        return context.Users.ToList();
    }
} 

MenuItem and MenuMode classes:

public class MenuItem
{
    public MenuItem()
    {}

    public MenuItem(string name, string contentId, double rate = 0)
    {
        this.Name = name;
        this.ContentId = contentId;
        this.Rate = rate;
    }

    public string Name { get; set; }

    public string ContentId { get; set; }

    public double Rate { get; set; }
} 
public class MenuModel
{
    public MenuModel()
    {
        Items = new List<MenuItem>();
        Users = new List<User>();
    }

    public List<MenuItem> Items { get; set; }

    public List<User> Users { get; set; }

    public int SelectedId { get; set; }
} 

The menu items are ordered on the server but what about CSS emphasizing? Here, I'm using I2UI JavaScript library:

<script src="http://i2ui.com/Scripts/Downloads/i2ui-1.0.0.js" type="text/javascript"></script> 

To emphasize HTML tags, you need to add additional attribute "data-i2":

<div class="menu clear-fix" data-i2="css:['.from-item','.to-item']">
    @foreach (var item in Model.Items)
    {
        <div class="item" data-i2="rate:@item.Rate">@item.Name</div>
    }
</div> 

Here, the div with "menu" class takes "data-i2" attribute with the CSS selectors range: 'from-item' and 'to-item'. The inner div with "item" class takes the "data-i2" attribute with the rate value.

CSS range:

.from-item
{
    font-size: 12px;
    padding: 3px;
    margin: 3px;
    opacity: 0.5;
    border-radius: 3px;
    background-color: #649151;
    color: #fff;
}
.to-item
{
    font-size: 30px;
    padding: 10px;
    margin: 10px;
    opacity: 1;
    border-radius: 10px;
    background-color: #164C00;
    color: #fff;
} 

Also, you need to call emphasize function in JavaScript:

$(document).ready(function () {
    i2.emph();
}); 

Requirements

Visual Studio 2010

Need to have installed:

  • ASP.NET MVC 3
  • Microsoft SQL Server Compact 4.0
  • Entity Framework 4

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Vadym Poberezhny
Software Developer
Ukraine Ukraine
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 5 Jan 2014
Article Copyright 2014 by Vadym Poberezhny
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid