aspnetcore-app-workshop icon indicating copy to clipboard operation
aspnetcore-app-workshop copied to clipboard

Update session card Add/Remove buttons to use JavaScript

Open DamianEdwards opened this issue 6 years ago • 0 comments

During the workshop today I added the ability for the session cards on the Home and My Agenda pages to progressively enhance the buttons for adding/removing sessions from the personal agenda to post using JavaScript rather than a normal form submit. It also handles dynamically updating the UI including removing the cards on the My Agenda page.

The JavaScript and modified agenda partial follow. We should consider incorporating this into the workshop.

site.js

"use strict";

// Agenda form functionality
let onMyAgendaPage = document.querySelector("h1[data-myAgenda]") !== null;
let form = document.querySelector("#agendaForm");
if (form) {
    form.addEventListener("submit", async e => {
        e.preventDefault();
        let sessionId = document.activeElement.getAttribute("value"),
            card = document.querySelector("#session-" + sessionId),
            button = card.querySelector("button:not(.template)"),
            template = card.querySelector("button.template"),
            url = button.formAction || form.action,
            formData = new FormData(form);

        formData.append("sessionId", sessionId);

        let response = await fetch(url, {
            method: form.method,
            body: formData
        });

        if (response.status === 200) {
            if (url.indexOf("Remove") > 0 && onMyAgendaPage) {
                let timeSlotDiv = card.closest("div.timeSlot"),
                    agendaDiv = document.querySelector("div.agenda"),
                    dayPill = agendaDiv.querySelector("a.nav-link.active");

                card.remove();

                // Check if this was the last card in this time slot and if so remove the track node
                if (timeSlotDiv.querySelectorAll(".session-card").length === 0) {
                    timeSlotDiv.remove();
                    // Check if this was the last card in the day and if so remove the day pill button
                    if (agendaDiv.querySelectorAll(".session-card").length === 0) {
                        dayPill.remove();
                        // Check if there are more days and if so navigate to the next day, else show the empty message
                        let dayPills = agendaDiv.querySelectorAll("a.nav-link");
                        if (dayPills.length > 0) {
                            document.location.search = "";
                        }
                        else {
                            agendaDiv.querySelector("#agendaMessage").classList.remove("template");
                        }
                    }
                }
            } else {
                button.classList.add("template");
                template.classList.remove("template");
            }            
        }
    });
}

_AgendaPartial.cshtml

@model IndexModel

<div class="agenda">
    <ul class="nav nav-pills mb-3">
        @foreach (var day in Model.DayOffsets)
        {
            <li role="presentation" class="nav-item">
                <a class="nav-link @(Model.CurrentDayOffset == day.Offset ? "active" : null)" asp-route-day="@day.Offset">@day.DayofWeek?.ToString()</a>
            </li>
        }
    </ul>

    @{
        var messageClassName = Model.Sessions.Any() ? "template" : null;
    }
    <p id="agendaMessage" class="@messageClassName">There don't appear to be any sessions here.</p>

    <form authz method="post" id="agendaForm">
        @foreach (var timeSlot in Model.Sessions)
        {
            <div class="timeSlot">
                <h4>@timeSlot.Key?.ToString("HH:mm")</h4>
                <div class="row">
                    @foreach (var session in timeSlot)
                    {
                        <div class="col-md-3 mb-4 session-card" id="[email protected]">
                            <div class="card shadow session h-100">
                                <div class="card-header">@session.Track?.Name</div>
                                <div class="card-body">
                                    <h5 class="card-title"><a asp-page="Session" asp-route-id="@session.Id">@session.Title</a></h5>
                                </div>
                                <div class="card-footer">
                                    <ul class="list-inline mb-0">
                                        @foreach (var speaker in session.Speakers)
                                        {
                                            <li class="list-inline-item">
                                                <a asp-page="Speaker" asp-route-id="@speaker.Id">@speaker.Name</a>
                                            </li>
                                        }
                                    </ul>
                                    <p class="mb-0">
                                        <a authz-policy="Admin" asp-page="/Admin/EditSession" asp-route-id="@session.Id" class="btn btn-default btn-xs">Edit</a>
                                        @{
                                            var isInSession = Model.UserSessions.Contains(session.Id);
                                            var removeClassName = isInSession ? "" : "template";
                                            var addClassName = isInSession ? "template" : "";
                                        }
                                        <button type="submit" name="sessionId" value="@session.Id" asp-page-handler="Remove" class="btn btn-default btn-sm bg-transparent @removeClassName" title="Remove from my personal agenda">
                                            <i class="icon ion-md-star" aria-hidden="true"></i>
                                        </button>
                                        <button type="submit" name="sessionId" value="@session.Id" class="btn btn-default btn-sm bg-transparent @addClassName" title="Add to my personal agenda">
                                            <i class="icon ion-md-star-outline" aria-hidden="true"></i>
                                        </button>
                                    </p>
                                </div>
                            </div>
                        </div>
                    }
                </div>
            </div>
        }
    </form>
</div>

DamianEdwards avatar Jun 18 '19 15:06 DamianEdwards