asp.net-corelocal-storagerazor-pagesfavorites

ASP.NET Core Razor page favorite list with localstorage


Who can help me create a favorite list of teams for example that I can then display on another page and do this with local storage? The list comes from a SQL database.

At the end of the list (table) there is a heart icon, which you can click on. When you click on the heart icon it changes into another icon. But when I refresh the page I want to see the selected items again. Also, when I open another page, I get a list of my selected items.

teams.cshtml:

@page
@model organizer.Pages.TeamsModel
@using Microsoft.AspNetCore.Http
@addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers

@{
    Layout = "_Layout2";
}

<div class="eigentabel">
    <h3 class="text-end"> @Model.variabelTNaam</h3>
    @foreach (var itemD in Model.listDivisieD)
    {           
    //hier zetten we de titel op de pagina
        <span><h2>@itemD.naam </h2></span>
        <table id="" class="display">
        @{
        Model.nummer = 0;  
        }
        <thead>
            <tr>
                    <th style="width: 2%">#</th>
                <th style ="text-align: center; width: 2%"></th>
                <th style="text-align: left; width: 10%">Team name</th>
                <th style="width: 5%">Country</th>
                <th style="width: 5%">Payed on</th>
                <th style="width: 5%">Like</th>
            </tr>
        </thead>
                <tbody>

            @foreach (var itemT in Model.listTeamT)
            {
            if (itemT.divisie == @itemD.naam)
            {
            <tr>
            @{
            Model.nummer = Model.nummer + 1; 
            }

                    <td>@Model.nummer</td>
                    <td><img src="https://@itemT.vlag" width="20" height="13"></td>
                    <td><a asp-page-handler="Team" asp-route-varTeamId="@itemT.id">@itemT.naam</a></td>
                    <td>@itemT.land</td>
                    <td>@itemT.betaling</td>
                    <td><i onclick="myFunction(this)" id="hartje" class="fa fa-heart-o"></i></td>
            </tr>
            }
        }
        </tbody>
        </table>
    }
</div>

teams.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Data.SqlClient;

namespace organizer.Pages
{
    public class TeamsModel : PageModel
    {
        public String? variabelTNaam;
        public List<TeamInfoT> listTeamT = new();
        public List<DivisieInfoD> listDivisieD = new();
        public string? sessionvarTorId;
        public int nummer;
        private readonly IConfiguration _configuration;

        //Dit moeten we hier zetten en de variabele instellen
        public void OnGetTeamAsync(Guid? varTeamId)
        {
            HttpContext.Session.SetString("SessionTeamId", varTeamId.ToString());
            Response.Redirect("/Team_detail"); 
        }

        public TeamsModel(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public void OnGet()
        {
            // Set value in Session object.
            if (HttpContext.Session.GetString("SessionTorId") != null)
                sessionvarTorId = HttpContext.Session.GetString("SessionTorId");
                
            try
            {
                string connString = _configuration.GetConnectionString("DefaultConnection");
                using SqlConnection connection = new(connString);
                connection.Open();
                String sqlD = "SELECT  .....";
                String sqlT = "SELECT ...";
                String sql1 = "SELECT ...";

                using SqlCommand command1 = new(sql1, connection);
                variabelTNaam = (string)command1.ExecuteScalar();

                using (SqlCommand commandD = new(sqlD, connection))
                {
                    using SqlDataReader readerD = commandD.ExecuteReader();

                    while (readerD.Read())
                    {
                        DivisieInfoD divisieInfoD = new()
                        {
                            id = readerD.GetGuid(0),
                            naam = readerD.GetString(2),
                            maxTeams = readerD.GetInt32(14),
                        };

                        listDivisieD.Add(divisieInfoD);
                    }
                }

                using SqlCommand commandT = new(sqlT, connection);
                { 
                    using SqlDataReader readerT = commandT.ExecuteReader();

                    while (readerT.Read())
                    {
                        TeamInfoT teamInfoT = new()
                        {
                            id = readerT.GetGuid(0),
                            naam = readerT.GetString(1),
                            land = readerT.GetString(2),
                            vlag = readerT.GetString(3).ToString().ToLower().Replace(" ", "_"),
                            betaling = readerT.IsDBNull(4) ? "-" : readerT.GetDateTime(4).ToString("dd-MMM-yyyy"),
                            divisie = readerT.GetString(5),
                        };
                    
                        listTeamT.Add(teamInfoT);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("NOT Connected"); 
                Console.WriteLine("Exception: connectie NIET ok " + ex.Message);
            }
        }
    }

    public class DivisieInfoD
    {
        public String? naam;
        public Guid? id;
        public int maxTeams;
    }

    public class TeamInfoT
    {
        public Guid id;
        public String? naam;
        public String? land;
        public String? vlag;
        public String? betaling;
        public String? divisie;
    }
}

_layout2.cshtml:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - TEST</title>

    <!-- DataTables -->
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.2.0/css/bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
    <link rel="stylesheet" href="~/js/datatables.min.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" />
    <link href="~/css/site.css" rel="stylesheet" />
    <!-- Font Awesome CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
   
<body>
    <header>
     <div class="fixed-top"> 
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm bg-primary navbar-dark border-bottom box-shadow mb-3 ">
            <div class="container-fluid">
                <div class="navbar-left">
                    <a class="navbar-brand"  target="_blank">                     
                    </a>
                </div>
                <div class="navbar-right">
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                
                    <div class="navbar-collapse collapse d-sm-inline-flex justify-content-end">
                        <ul class="navbar-nav flex-grow-1">
                            <li class="nav-item">
                                <a class="nav-link text-light " style="margin-left:1em" asp-area="" asp-page="/Index"><span class="fa fa-home"></span> Home</a>
                            </li>
                            <li class="nav-item">
                                <a class="nav-link text-light " style="margin-left:1em" asp-area="" asp-page="/Tornooi_Algemeen"><span class="fa fa-dashboard"></span> Dashboard</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </nav>
    </div>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy;  - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    <script type="text/javascript">
        //function changing heart
        function myFunction(x) {
            x.classList.toggle("fa-thumbs-up");
            window.localStorage.setItem("FavoriteTeam", "test");
        }

        // Initialize the DataTable
        $(document).ready(function () {
            $('table.display').DataTable({
                // Set the number of rows to be
                // displayed per page on the DataTable
                pageLength: 25,
                lengthMenu: [25, 50]
            });
        });

        // Initialize the DataTable
        $(document).ready(function () {
            $('table.display2').DataTable({
 
        "dom": "<'row'<'col-lg-10 col-md-10 col-xs-12'f><'col-lg-2 col-md-2 col-xs-12'l>>" +
                    "<'row'<'col-sm-12'tr>>" +
                    "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",

                // Set the number of rows to be
                // displayed per page on the DataTable
                pageLength: 25,
                lengthMenu: [25, 50, 100]
            });
        });
    </script>

    <!-- Google tag (gtag.js) -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-4CPZWF653F"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'G-4CPZWF653F');
    </script>



    <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>

    @await RenderSectionAsync("Scripts", required: false)

</body>
</html>

Solution

  • You could try below code:

    Data/ApplicationDbContext.cs:

    using Microsoft.EntityFrameworkCore;
    using System.Text.Json.Serialization;
    
    namespace FavoriteTeams.Data
    {
        public class ApplicationDbContext : DbContext
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
                   : base(options)
            {
            }
    
            public DbSet<Team> Teams { get; set; }
            public DbSet<Division> Divisions { get; set; }
        }
    
        public class Team
        {
            public Guid Id { get; set; }
            public string Name { get; set; }
            public string Country { get; set; }
            public string Flag { get; set; }
            public DateTime? Payment { get; set; }
            public Guid DivisionId { get; set; }
    
            [JsonIgnore]
            public Division Division { get; set; }
        }
    
        public class Division
        {
            public Guid Id { get; set; }
            public string Name { get; set; }
            public int MaxTeams { get; set; }
    
            [JsonIgnore]
            public ICollection<Team> Teams { get; set; }
        }
    
    }
    

    Data/DbInitializer.cs:

    using Microsoft.EntityFrameworkCore;
    
    namespace FavoriteTeams.Data
    {
        public class DbInitializer
        {
            public static void Initialize(IServiceProvider serviceProvider)
            {
                using (var context = new ApplicationDbContext(
                    serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
                {
                    if (context.Divisions.Any() || context.Teams.Any())
                    {
                        return;   // DB has been seeded
                    }
    
                    var divisions = new Division[]
                    {
                           new Division { Id = Guid.NewGuid(), Name = "Division 1", MaxTeams = 10 },
                           new Division { Id = Guid.NewGuid(), Name = "Division 2", MaxTeams = 10 }
                    };
    
                    foreach (var d in divisions)
                    {
                        context.Divisions.Add(d);
                    }
    
                    context.SaveChanges();
    
                    var teams = new Team[]
                    {
                           new Team { Id = Guid.NewGuid(), Name = "Team 1", Country = "Country 1", Flag = "flag_url_1", Payment = DateTime.Now, DivisionId = divisions[0].Id },
                           new Team { Id = Guid.NewGuid(), Name = "Team 2", Country = "Country 2", Flag = "flag_url_2", Payment = DateTime.Now, DivisionId = divisions[1].Id }
                    };
    
                    foreach (var t in teams)
                    {
                        context.Teams.Add(t);
                    }
    
                    context.SaveChanges();
                }
            }
        }
    
    }
    

    Pages/Shared/_Layout.cshtml:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>@ViewData["Title"] - FavoriteTeams</title>
       @*  <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> *@
        <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
        <link rel="stylesheet" href="~/FavoriteTeams.styles.css" asp-append-version="true" />
    
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.2.0/css/bootstrap.min.css" />
        <!-- DataTables CSS -->
        <link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
        <!-- Font Awesome CSS -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    
    </head>
    <body>
        <header>
            <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
                <div class="container">
                    <a class="navbar-brand" asp-area="" asp-page="/Index">FavoriteTeams</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                            aria-expanded="false" aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                        <ul class="navbar-nav flex-grow-1">
                            <li class="nav-item">
                                <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                            </li>
                            <li class="nav-item">
                                <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        </header>
        <div class="container">
            <main role="main" class="pb-3">
                @RenderBody()
            </main>
        </div>
    
        <footer class="border-top footer text-muted">
            <div class="container">
                &copy; 2024 - FavoriteTeams - <a asp-area="" asp-page="/Privacy">Privacy</a>
            </div>
        </footer>
    
        @* <script src="~/lib/jquery/dist/jquery.min.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script> *@
    
        <!-- jQuery -->
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
        <!-- Bootstrap JS -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/js/bootstrap.bundle.min.js"></script>
        <!-- DataTables JS -->
        <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
    
    
        @await RenderSectionAsync("Scripts", required: false)
    </body>
    </html>
    

    Pages/Teams.cshtml:

    @page
    @model FavoriteTeams.Pages.TeamsModel
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    @{
        Layout = "_Layout";
    }
    
    <div class="eigentabel">
        <h3 class="text-end">Teams Overview</h3>
        @foreach (var division in Model.Divisions)
        {
            <span><h2>@division.Name </h2></span>
            <table id="teamsTable-@division.Id" class="display">
                <thead>
                    <tr>
                        <th style="width: 2%">#</th>
                        <th style="text-align: center; width: 2%"></th>
                        <th style="text-align: left; width: 10%">Team name</th>
                        <th style="width: 5%">Country</th>
                        <th style="width: 5%">Payed on</th>
                        <th style="width: 5%">Like</th>
                    </tr>
                </thead>
                <tbody>
                    @{
                        var num = 0;
                    }
                    @foreach (var team in Model.Teams.Where(t => t.DivisionId == division.Id))
                    {
                        <tr>
                            <td>@(++num)</td>
                            <td><img src="https://@team.Flag" width="20" height="13"></td>
                            <td>@team.Name</td>
                            <td>@team.Country</td>
                            <td>@(team.Payment.HasValue ? team.Payment.Value.ToString("dd-MMM-yyyy") : "-")</td>
                            <td><i onclick="toggleFavorite('@team.Id', this)" class="fa fa-heart-o heart-icon" data-team-id="@team.Id"></i></td>
                        </tr>
                    }
                </tbody>
            </table>
        }
    </div>
    
    @section Scripts {
        <script type="text/javascript">
            function toggleFavorite(teamId, element) {
                const favorites = JSON.parse(localStorage.getItem('favoriteTeams')) || [];
                const index = favorites.indexOf(teamId);
    
                if (index === -1) {
                    favorites.push(teamId);
                    element.classList.remove("fa-heart-o");
                    element.classList.add("fa-heart");
                } else {
                    favorites.splice(index, 1);
                    element.classList.remove("fa-heart");
                    element.classList.add("fa-heart-o");
                }
    
                localStorage.setItem('favoriteTeams', JSON.stringify(favorites));
            }
    
            document.addEventListener("DOMContentLoaded", function () {
                const favorites = JSON.parse(localStorage.getItem('favoriteTeams')) || [];
                const icons = document.querySelectorAll('.heart-icon');
    
                icons.forEach(icon => {
                    const teamId = icon.getAttribute('data-team-id');
                    if (favorites.includes(teamId)) {
                        icon.classList.remove('fa-heart-o');
                        icon.classList.add('fa-heart');
                    }
                });
            });
        </script>
    }
    

    Teams.cshtml.cs:

    using FavoriteTeams.Data;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.EntityFrameworkCore;
    
    namespace FavoriteTeams.Pages
    {
        public class TeamsModel : PageModel
        {
            private readonly ApplicationDbContext _context;
    
            public TeamsModel(ApplicationDbContext context)
            {
                _context = context;
            }
    
            public IList<Team> Teams { get; set; }
            public IList<Division> Divisions { get; set; }
    
            public async Task OnGetAsync()
            {
                Teams = await _context.Teams.Include(t => t.Division).ToListAsync();
                Divisions = await _context.Divisions.ToListAsync();
            }
    
    
        }
    }
    

    Pages/FavoriteTeams.cshtml:

    @page
    @model FavoriteTeams.Pages.FavoriteTeamsModel
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    @{
        Layout = "_Layout";
    }
    
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Favorite Teams</title>
    </head>
    <body>
        <h1>Favorite Teams</h1>
        <div id="favoriteTeamsContainer"></div>
    </body>
    </html>
    
    @section Scripts {
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", () => {
                const favorites = JSON.parse(localStorage.getItem('favoriteTeams')) || [];
                console.log('Favorites from local storage:', favorites);
    
                const allTeams = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.Teams));
                console.log('All Teams:', allTeams);
    
                // Log the structure of allTeams
                console.log('Structure of allTeams:', JSON.stringify(allTeams, null, 2));
    
                if (Array.isArray(allTeams)) {
                    favorites.forEach(favoriteId => {
                        console.log('Processing favorite teamId:', favoriteId);
                        const team = allTeams.find(t => {
                            console.log('Checking team:', t);
                            console.log('Favorite Team ID:', favoriteId);
                            if (t && t.Id) {
                                console.log('Current Team ID:', t.Id);
                                const idsMatch = t.Id.toLowerCase() === favoriteId.toLowerCase();
                                console.log('IDs match:', idsMatch);
                                return idsMatch;
                            } else {
                                console.error('Team or Team ID is undefined:', t);
                                return false;
                            }
                        });
                        console.log('Found team:', team);
                        if (team) {
                            const teamElement = document.createElement('div');
                            teamElement.innerHTML = `
                                        <div>
                                            <img src="https://${team.Flag}" width="20" height="13">
                                            <a href="/Team_detail?varTeamId=${team.Id}">${team.Name}</a>
                                            <span>${team.Country}</span>
                                            <span>${team.Payment}</span>
                                        </div>
                                    `;
                            console.log('Appending team element to container:', teamElement);
                            document.getElementById('favoriteTeamsContainer').appendChild(teamElement);
                        } else {
                            console.error('Team not found:', favoriteId);
                        }
                    });
                } else {
                    console.error('allTeams is not an array');
                }
            });
        </script>
    }
    

    FavoriteTeams.cshtml.cs:

    using FavoriteTeams.Data;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.EntityFrameworkCore;
    
    namespace FavoriteTeams.Pages
    {
        public class FavoriteTeamsModel : PageModel
        {
            private readonly ApplicationDbContext _context;
    
            public List<Team> Teams { get; set; }
    
            public FavoriteTeamsModel(ApplicationDbContext context)
            {
                _context = context;
            }
    
            public void OnGet()
            {
                Teams = _context.Teams.Include(t => t.Division).ToList();
            }
    
    
        }
    }
    

    Program.cs:

    using FavoriteTeams.Data;
    using Microsoft.EntityFrameworkCore;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    
    builder.Services.AddDbContext<ApplicationDbContext>(options =>
           options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
    builder.Services.AddSession();
    
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    
    SeedDatabase(app);
    
    
    app.Run();
    static void SeedDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        {
            DbInitializer.Initialize(serviceScope.ServiceProvider);
        }
    }
    

    enter image description here

    enter image description here