# MVC Architecture

This material is part of Learning Objective 5 (minimum and desired).

### Exercise preparation: JavaScript

**SQL Server Setup**

Do the following in SQL Server Management Studio:

-   use the script to create database, its structure and some test data: https://pastebin.com/jtJfak9E
-   in the script, **change the database name to Exercise14 and use it**
-   execute it to create database, its structure and some test data
-   execute additional script 1: https://pastebin.com/SeHBs1BA
-   execute additional script 2: https://pastebin.com/7qHM2h2d

**Project starter**

Unpack the project starter archive and open the solution in the Visual Studio.  
Set up the connection string and run the application.  
Check if the application is working (e.g. navigation, list of songs, adding a new song).

> In case it's not working, check if you completed the instructions correctly.

**Application users**  

Admin: username is admin, password is 12345678  
User: username is user1, password is 12345678  

### 1. JavaScript Folders

By default, `wwwroot` folder contains the following JS folders:
- `lib`
- `js`

**lib folder**

The 'lib' folder is one of common folders (also in ASP.NET Core MVC template) for 3rd party JS libraries. By default, it contains the following libraries:
- Bootstrap
- jQuery
- jQuery validation
- jQuery unobtrusive validation
  
ASP.Net Core MVC template uses Bootstrap and jQuery in layout view `_Layout.cshtml`, and so in every page.  

**js folder**

The 'js' folder is a folder for your own scripts. There is `site.js` script file that is already added to the project with the default template. It is also included in `_Layout.cshtml` so that it's available in every page. For example, you can write utility functions in the `site.js` file, or write script that dynamically extends functionality of navigation bar.  

> For page-specific logic, it's a common practice to use per-page JS files. For example, for `Product/Add` route  use `js/product/add.js` JS file.  

### 2. JavaScript example: dynamically creating toasts

Let's use TempData and Bootstrap to signal the user that he just created a new genre. It can be done using "toast" component.   Bootstrap library implements such component.

  ```JavaScript
  // In site.js

  // Template HTML generator function for toast message
  const createToastTemplate = (title, info, body) => 
  `<div class="toast show">
      <div class="toast-header">
          <strong class="me-auto">${title}</strong>
          <small>${info}</small>
          <button type="button" class="btn-close" data-bs-dismiss="toast"></button>
      </div>
      <div class="toast-body">
          ${body}
      </div>
  </div>`

  // Function that creates toast DOM from HTML and instances a new Bootstrap toast
  function createToast(title, info, body, delay = null) {
      const toastTemplate = createToastTemplate(title, info, body);

      const placeholder = document.createElement("div");
      placeholder.innerHTML = toastTemplate;
      const toastEl = placeholder.firstElementChild;

      var toastPh = document.getElementById('toast-placeholder');
      toastPh.append(toastEl);

      var visibleToast = new bootstrap.Toast(toastEl, { 'autohide': true, 'delay': delay });
      visibleToast.show();
  }
  ```

  ```HTML
  <!--In Genre/Index.cshtml, placeholder for toasts (see Bootstrap documentation)--> 
  <div class="toast-container">
      <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11" id="toast-placeholder">
      </div>
  </div>
  ```

Mark "alert" Bootstrap element for the new genre with classes `new-genre` and `d-none`. Class `d-none` will hide the "alert" but also render it in the DOM. When page is loaded, JavaScript can target the hidden element using `new-genre` class, read its text and show it as "toast".

  ```JavaScript
  @*In Genre/Index.cshtml, add Scripts section*@
  @section Scripts {
      <script>
          document.addEventListener("DOMContentLoaded", function (event) {
              // This code turns div with class "new-genre" to toast
              const newGenreAlert = $("div.new-genre");
              const newGenreText = newGenreAlert.text().trim();
              newGenreAlert.remove();
              if (newGenreText) {
                  createToast(
                      "New genre created",
                      "Just now",
                      newGenreText,
                      2500);
              }
          });
      </script>
  }
  ```

### 3. JavaScript: LibMan

LibMan is a popular tool that is able to install and uninstall 3rd party client JS libraries. It can also remember which libraries should be install and "clean" them from solution in order to reduce the solution archive size. You can use "restore" functionality later to install back the deleted JS files.  

LibMan is built into the Visual Studio and can be used from the context menu.  

Let's install an example JavaScript library "Backpax" using LibMan:  

**Install Backpax**

- In Solution explorer, in project context menu select "Add > Client-Side Library"
- Select "jsdelivr", search for "backpax" and install it
  - Reference: https://appleple.github.io/backpax/ (find it in README.md in the backpax folder)
- Add following code to `_Layout.cshtml`
  ```HTML
  <script src="~/lib/backpax/bundle/backpax.min.js"></script>
  ```
- Add following code to `Home/Index.html`
  ```HTML
  <!--Home/Index.html-->
  <h2>Scroll down...</h2>
  <div class="js-parallax" style="height: 400px; position: relative; overflow: hidden;"
      data-img="https://images.unsplash.com/photo-1565275706395-d452122d6cfc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80">
  </div>
  ```
- Before that code add few paragraphs generated on https://www.lipsum.com/ with `font-size` set to `x-large` to have enough content height to see the result

- Activate `Backpax` parallax scrolled image
  ```JavaScript
  @section Scripts {
      <script>
          document.addEventListener("DOMContentLoaded", function (event) {
              const parallax = new Backpax('.js-parallax');
          });
      </script>
  }
  ```

- Test the functionality


### 4. Transforming multiselect `<select>` to tag selector using Select2

There are several 3rd party libraries that are able to transform multiselect `<select>` to selection of tags. One of them is `Select2`.  

_See: https://select2.org/getting-started/basic-usage#multi-select-boxes-pillbox_  

_Also: https://apalfrey.github.io/select2-bootstrap-5-theme/_  

Let's use this library to implement styled multiselect.  
First observe how are the tags implementing by logging in as `admin` and editing a song. You can see TagIds multiple select field (use Ctrl+click).  

- Add client-side library: `cdnjs`, `Select2`
  - Note: `Select2` depends on `jQuery`
- Add `Select2` CSS and JS to `_LayoutAdmin.cshtml`
- Use the following JavaScript on `Song/Edit.cshtml` to transform multiselect into multiple tag display

  ```JavaScript
  <script>
  $(() => { 
    $("select[multiple]").select2();
  })
  </script>
  ```

Check how are the tags displayed now.  

- Add client-side library to style `Select2` component as Bootstrap 5 component: `cdnjs`, `select2-bootstrap-5-theme`
- Add `select2-bootstrap-5-theme` CSS to `_Layout.cshtml`
- Update JavaScript on `Song/Edit.cshtml`
  ```
  $(() => { 
    $("select[multiple]").select2({
      theme: "bootstrap-5"
    });
  })
  ```

Check how are the tags displayed now.  
This adapts multiselect tags to match Bootstrap look and feel.  


### 5. Introduce Bootstrap validation

In `_ValidationScriptsPartial.cshtml` partial view that adds client side validation JavaScript, add the following script to the end of view. The script will configure Bootstrap validation, that uses `is-valid` and `is-invalid` classes to mark the displayed form inputs with the proper feedback markings.

  ```C#
  <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
  <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
  <script>
      var settings = {
          validClass: "is-valid",
          errorClass: "is-invalid"
      };
      $.validator.setDefaults(settings);
      $.validator.unobtrusive.options = settings;
  </script>
  ```

Test the validation with and without these settings.

### 6. List of Interesting Javascript Libraries

- SweetAlert: https://sweetalert2.github.io/
- Tailwind: https://tailwindcss.com/
- Volt - Bootstrap 5 Admin Dashboard: https://github.com/themesberg/volt-bootstrap-5-dashboard
- Bootstrap Icons: https://icons.getbootstrap.com/
