Skip to content

vinodkumaronlinetraining/frontend-javascript

Repository files navigation

JavaScript Sessions — Complete Summary


Topic 1 — JavaScript Basics

Variables and Data Types

// primitive types
let name     = "Vinod";        // string
let balance  = 1445.50;        // number
let isActive = true;           // boolean
const FEE    = 0.02;           // constant — never changes
let cashback = null;           // empty value
let lastTxn;                   // undefined — declared but not assigned

// reference types
let transactions = [500, -200, 300];          // array
let user = { name: "Vinod", balance: 1445 };  // object

Operators

// arithmetic
user.balance += 500;    // add
user.balance -= 200;    // subtract

// comparison — returns true/false
amount > balance        // greater than
amount === balance      // strict equal — checks value AND type
amount !== null         // not equal

// logical
isPremium && amount <= 1000    // AND — both must be true
isPremium || amount <= 1000    // OR  — at least one must be true

Functions — 3 ways to write them

// 1. declaration
function greetUser(name) {
    return `Hello, ${name}!`;
}

// 2. expression
const calculateCashback = function(amount) {
    return amount >= 500 ? amount * 0.05 : 0;
};

// 3. arrow function — modern shorthand
const isAllowed = (amount) => {
    return user.isPremium || amount <= 1000;
};

Topic 2 — Classes and Objects in JS

// Transaction class — represents one transaction
class Transaction {
    constructor(amount, type, date) {
        this.amount = amount;
        this.type   = type;
        this.date   = date;
    }
    getDetails() {
        return `${this.type.toUpperCase()} of ₹${this.amount} on ${this.date}`;
    }
}

// Wallet class — manages balance and transactions
class Wallet {
    constructor(initialBalance = 0) {
        this.balance      = initialBalance;
        this.transactions = [];
    }

    addTransaction(amount, type) {
        // validation
        if (typeof amount !== "number" || amount <= 0) return;
        if (type !== "credit" && type !== "debit")    return;

        const txn = new Transaction(amount, type,
            new Date().toISOString().split("T")[0]);

        this.transactions.push(txn);

        if (type === "credit") {
            this.balance += amount;
        } else {
            if (amount > this.balance) { console.log("Insufficient balance"); return; }
            this.balance -= amount;
        }
    }

    getTotalCredits() {
        return this.transactions
            .filter(t => t.type === "credit")
            .reduce((sum, t) => sum + t.amount, 0);
    }

    getTotalDebits() {
        return this.transactions
            .filter(t => t.type === "debit")
            .reduce((sum, t) => sum + t.amount, 0);
    }

    getCashback() {
        const credits = this.getTotalCredits();
        return credits >= 500 ? credits * 0.05 : 0;
    }
}

Topic 3 — DOM Manipulation

4 core techniques

// 1. SELECT
document.getElementById("wallet-balance")     // by id — one element
document.querySelector(".form-grid")          // by CSS selector — first match
document.querySelectorAll(".stat-card")        // all matching elements

// 2. MODIFY
element.textContent = "₹ 1,940.50"           // change text
element.innerHTML   = "<span>Active</span>"   // change HTML inside
element.setAttribute("href", "/dashboard")    // change attribute
element.classList.add("text-success")         // add CSS class
element.classList.remove("text-danger")       // remove CSS class

// 3. EVENTS
element.addEventListener("click", function() { ... })
element.addEventListener("submit", function(e) { e.preventDefault(); ... })

// 4. CREATE and REMOVE
const row = document.createElement("tr")     // create new element
row.innerHTML = `<td>...</td>`               // add content
tbody.appendChild(row)                       // add to page
tbody.insertBefore(row, tbody.firstChild)    // add at top
element.remove()                             // remove from page

Applied to wallet app — renderTransaction()

function renderTransaction(transaction) {
    const tbody   = document.getElementById("transactions-table");
    const row     = document.createElement("tr");
    const isCredit = transaction.type === "credit";

    row.innerHTML = `
        <td>${transaction.date}</td>
        <td>
            <span class="badge ${isCredit ? 'badge-green' : 'badge-red'}">
                ${isCredit ? 'Credit' : 'Debit'}
            </span>
        </td>
        <td class="${isCredit ? 'text-green' : 'text-red'}">
            ${isCredit ? '+' : '−'} ${transaction.amount.toFixed(2)}
        </td>
    `;
    tbody.insertBefore(row, tbody.firstChild);   // newest on top
}

Topic 4 — Events (9 types)

Event When it fires Used in wallet app
click element clicked Add transaction button
submit form submitted Transaction form
change input value changes Account type dropdown
mouseover mouse enters element Stat card hover
mouseout mouse leaves element Reset card color
keydown key pressed Enter shortcut
keyup key released Amount preview
focus element gains focus Input border turns blue
blur element loses focus Input border resets

event.preventDefault() — most important

form.addEventListener("submit", function(e) {
    e.preventDefault();    // stops page refresh
    // handle form yourself
});

Topic 5 — Event Delegation

//  without delegation — one listener per element
document.getElementById("home").addEventListener("click", ...)
document.getElementById("profile").addEventListener("click", ...)
document.getElementById("settings").addEventListener("click", ...)

//  with delegation — one listener on parent handles all
document.getElementById("menu").addEventListener("click", function(event) {
    if (event.target.tagName === "LI") {
        alert(`You clicked ${event.target.textContent}`);
    }
});

Why it matters — if you add new <li> items later, they automatically work. No new listeners needed.


Topic 6 — Asynchronous JavaScript

The problem

// synchronous — blocks everything
console.log("Start");
alert("Fetching...");         // freezes the page
console.log("End");

// asynchronous — non-blocking
console.log("Start");
setTimeout(() => console.log("Fetched!"), 2000);
console.log("End");
// prints: Start → End → Fetched! (after 2s)

3 ways to handle async — evolution

1. Callbacks — oldest

function fetchData(callback) {
    setTimeout(() => {
        callback({ name: "Vinod", balance: 1445 });
    }, 2000);
}

fetchData(function(data) {
    console.log(data);       // runs after 2s
});

2. Promises — cleaner

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;
            if (success) resolve("Data fetched!");
            else         reject("Error!");
        }, 2000);
    });
}

fetchData()
    .then(result => console.log(result))   // success
    .catch(error  => console.error(error)); // failure

3. Async/Await — modern, reads like normal code

async function getData() {
    try {
        const result = await fetchData();  // waits here
        console.log(result);
    } catch (error) {
        console.error(error);
    }
}

Applied to wallet — addTransactionAsync()

// in Wallet class
addTransactionAsync(amount, type) {
    return new Promise((resolve, reject) => {
        document.getElementById("loading-text").style.display = "block";

        setTimeout(() => {
            try {
                this.addTransaction(amount, type);
                const txn = this.transactions[this.transactions.length - 1];
                resolve(txn);
            } catch (err) {
                reject(err);
            }
        }, 2000);
    });
}

// in form handler
transactionForm.addEventListener("submit", async function(e) {
    e.preventDefault();
    const amount = parseFloat(document.getElementById("amount").value);
    const type   = document.querySelector('input[name="type"]:checked').value;

    try {
        const txn = await myWallet.addTransactionAsync(amount, type);
        document.getElementById("wallet-balance").textContent = `₹ ${myWallet.balance.toFixed(2)}`;
        renderTransaction(txn);
        document.getElementById("loading-text").style.display = "none";
    } catch (error) {
        document.getElementById("loading-text").textContent = "Error: " + error;
    }
});

Topic 7 — Fetch API

Core syntax

// .then() chain
fetch("https://api.example.com/data")
    .then(response => response.json())
    .then(data  => console.log(data))
    .catch(error => console.error(error));

// async/await — preferred
async function getData() {
    try {
        const response = await fetch("https://api.example.com/data");
        if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
        const data = await response.json();
        return data;
    } catch (error) {
        console.error(error);
    }
}

4 HTTP methods

// GET — read
fetch("https://mockapi.io/transactions")

// POST — create
fetch("https://mockapi.io/transactions", {
    method:  "POST",
    headers: { "Content-Type": "application/json" },
    body:    JSON.stringify({ type: "credit", amount: 500 })
})

// PUT — update
fetch("https://mockapi.io/transactions/5", {
    method:  "PUT",
    headers: { "Content-Type": "application/json" },
    body:    JSON.stringify({ type: "debit" })
})

// DELETE — remove
fetch("https://mockapi.io/transactions/5", { method: "DELETE" })

Topic 8 — MockAPI Integration

Full wallet flow with MockAPI

let myWallet;    // declared globally — initialized after fetch

// LOAD transactions on page start
async function loadTransactions() {
    const response     = await fetch("https://mockapi.io/transactions");
    const transactions = await response.json();

    let balance = 0, credits = 0, debits = 0;
    transactions.forEach(txn => {
        if (txn.type === "credit") { credits += txn.amount; balance += txn.amount; }
        else                       { debits  += txn.amount; balance -= txn.amount; }
    });

    myWallet = new Wallet(balance);       // initialize AFTER fetch
    localStorage.setItem("walletBalance", myWallet.balance);

    document.getElementById("wallet-balance").textContent = `₹ ${balance.toFixed(2)}`;
    document.getElementById("total-credits").textContent  = `₹ ${credits.toFixed(2)}`;
    document.getElementById("total-debits").textContent   = `₹ ${debits.toFixed(2)}`;

    const tbody = document.getElementById("transactions-table");
    tbody.innerHTML = "";
    transactions.forEach(txn => renderTransaction(txn));
}

// ATTACH form handler AFTER wallet is initialized
document.addEventListener("DOMContentLoaded", () => {
    loadTransactions().then(() => {
        const form = document.querySelector(".form-grid");

        form.addEventListener("submit", async function(e) {
            e.preventDefault();
            if (!myWallet) return;

            const amount = parseFloat(document.getElementById("amount").value);
            const type   = document.querySelector('input[name="type"]:checked').value;

            // POST to server
            const response = await fetch("https://mockapi.io/transactions", {
                method:  "POST",
                headers: { "Content-Type": "application/json" },
                body:    JSON.stringify({ date: new Date().toISOString().split("T")[0], type, amount })
            });
            const txn = await response.json();

            myWallet.addTransaction(amount, type);
            document.getElementById("wallet-balance").textContent = `₹ ${myWallet.balance.toFixed(2)}`;
            renderTransaction(txn);
            form.reset();
        });
    });
});

Topic 9 — Login and Register with MockAPI

// login.js — find user in MockAPI
document.getElementById("login-button").addEventListener("click", async () => {
    const firstName = document.getElementById("first-name").value.trim();
    const lastName  = document.getElementById("last-name").value.trim();
    const password  = document.getElementById("password").value.trim();

    const response = await fetch("https://mockapi.io/users");
    const users    = await response.json();

    const user = users.find(u =>
        u.first_name === firstName &&
        u.last_name  === lastName  &&
        u.password   === password
    );

    if (user) {
        localStorage.setItem("currentUser", JSON.stringify(user));
        window.location.href = "dashboard.html";
    } else {
        alert("Invalid credentials.");
    }
});

// register.js — POST new user to MockAPI
document.getElementById("register-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const newUser = {
        first_name:   document.getElementById("first-name").value.trim(),
        last_name:    document.getElementById("last-name").value.trim(),
        password:     document.getElementById("password").value.trim(),
        account_type: document.getElementById("account-type").value
    };
    await fetch("https://mockapi.io/users", {
        method:  "POST",
        headers: { "Content-Type": "application/json" },
        body:    JSON.stringify(newUser)
    });
    window.location.href = "login.html";
});

Common errors encountered and fixes

Error Cause Fix
Cannot read properties of null getElementById returns null — wrong id or JS runs before HTML Check id matches exactly, move script to bottom of body
CORS policy blocked Opening HTML with file:// — no server Use Live Server in VS Code or python -m http.server
text is not defined Missing quotes around class names in template literal Use single quotes inside template literals
fetch failed ENOTFOUND Placeholder URL like api.example.com doesn't exist Use jsonplaceholder.typicode.com or MockAPI
Cannot read balance of undefined localStorage.setItem ran before async loadTransactions finished Move localStorage code inside the async function

Full topic progression

Variables & Types
      ↓
Operators & Functions
      ↓
Classes & Objects (Transaction, Wallet)
      ↓
DOM Manipulation (select, modify, create, remove)
      ↓
Events (click, submit, change, focus, blur, keydown, keyup, mouseover, mouseout)
      ↓
Event Delegation
      ↓
Async JS — Callbacks → Promises → Async/Await
      ↓
Fetch API (GET, POST, PUT, DELETE)
      ↓
MockAPI — real server integration
      ↓
Login + Register with MockAPI

Each topic was first explained with a simple standalone example, then implemented directly into the wallet app — same approach as the Python journey.

Assignment 2 — Wallet App JavaScript (Full Implementation)

Building on Assignment 1, this assignment covers everything from Classes → DOM → Events → Async → Fetch → MockAPI → Login/Register.


Part 1 — Classes and Objects

Task: Refactor your Assignment 1 code to use Transaction and Wallet classes.

Requirements:

Transaction class must have:
- constructor(amount, type, date)
- getDetails() method — returns formatted string

Wallet class must have:
- constructor(initialBalance)
- addTransaction(amount, type) — with validation
- getTotalCredits()  — uses .filter() and .reduce()
- getTotalDebits()   — uses .filter() and .reduce()
- getCashback()      — 5% of credits if credits >= 500

What you need to implement:

// when form is submitted, create a Transaction object
// add it to Wallet
// update the balance card
// render the transaction in the list
// show total credits, debits, cashback below the list

// validate inside addTransaction:
// - amount must be a positive number
// - type must be "credit" or "debit"
// - debit cannot exceed current balance

Expected output in console:

Transaction added: CREDIT of ₹500 on 2026-04-23
New balance: ₹1945.50
Total Credits: ₹500
Total Debits: ₹0
Cashback Earned: ₹25

Part 2 — DOM Manipulation

Task: Dynamically render everything using DOM methods — no hardcoded HTML in the transaction list.

Requirements — you MUST use each of these:

document.getElementById()          // select balance card, stat cards
document.querySelector()           // select form, checked radio
document.createElement()           // create tr, td, span for each transaction
element.classList.add()            // add text-green or text-red
element.classList.remove()         // remove on reset
element.textContent                // update balance, totals
element.innerHTML                  // build badge inside td
tbody.insertBefore(row, firstChild) // newest transaction at top
element.remove()                   // delete button removes a row

What to build:

Each transaction row must have:
  - Date column
  - Type column — badge (green for credit, red for debit)
  - Amount column — colored + or − prefix
  - Delete button — clicking removes that row and reverses the balance

Part 3 — All 9 Events

Task: Wire up all 9 events from the requirements above plus these new ones specific to the wallet flow:

New events to add on top of Assignment 1:

change    → when Credit/Debit dropdown changes:
             - update a live preview label
             - change the border color of amount input
               (green for credit, red for debit)

keyup     → as user types amount:
             - show "You will receive ₹X after 2% fee" for credit
             - show "You will pay ₹X including 2% fee" for debit
             - update live every keystroke

focus     → amount input:
             - border turns blue
             - show a hint text below: "Enter amount between ₹1 and ₹50,000"

blur      → amount input:
             - border resets
             - hint text disappears

mouseover → each transaction row:
             - background turns light yellow
             - show a tooltip: "Click × to delete"

mouseout  → each transaction row:
             - background resets to white

Part 4 — Async JavaScript

Task: Simulate an async transaction — show a loading state while the transaction "processes".

Requirements:

// addTransactionAsync(amount, type) must:
// 1. return a Promise
// 2. show "Processing transaction..." text immediately
// 3. wait 1.5 seconds (simulate server delay using setTimeout)
// 4. resolve with the new Transaction object
// 5. reject if validation fails
// 6. hide loading text in finally block

// form handler must:
// - use async/await
// - disable the Add button while processing
// - change button text to "Processing..."
// - re-enable button after done
// - catch errors and show them to the user

Expected UI behaviour:

User clicks Add
    ↓
Button → "Processing..." (disabled)
"Processing transaction..." text appears
    ↓
1.5 seconds later
    ↓
Balance updates
New row appears in table
Button → "Add Transaction" (enabled)
Loading text disappears

Part 5 — Fetch API with MockAPI

Task: Replace the simulated async with real MockAPI calls.

Setup steps:

1. Go to mockapi.io — create free account
2. Create project: "WalletAssignment"
3. Create resource: "transactions"
   Fields: type (String), amount (Number), date (String)
4. Copy your base URL

Requirements:

// loadTransactions() must:
// - GET all transactions from MockAPI on page load
// - calculate balance, credits, debits from the response
// - render each transaction in the table
// - initialize Wallet with the fetched balance

// addTransaction form must:
// - POST new transaction to MockAPI
// - only render the row AFTER server confirms (response.ok)
// - show error message if POST fails

// delete button must:
// - DELETE from MockAPI using the transaction id
// - remove the row from table only AFTER server confirms
// - reverse the balance

// check response.status for every request:
// 200/201 → success
// 404     → not found
// 500     → server error

Expected flow:

Page loads
    ↓
GET /transactions → renders all existing transactions
    ↓
User adds ₹500 credit
    ↓
POST /transactions → server saves it → row appears
    ↓
User clicks delete on a row
    ↓
DELETE /transactions/:id → server deletes → row removed

Part 6 — Login and Register pages

Task: Build a complete login and register flow connected to MockAPI.

Setup:

Add another resource to your MockAPI project: "users"
Fields: first_name (String), last_name (String),
        password (String), account_type (String),
        balance (Number, default: 1000)

register.html requirements:

// form must collect:
// first_name, last_name, password, account_type

// on submit:
// 1. validate password — min 8 chars, has uppercase, lowercase, digit
//    (use regex: /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$/)
// 2. POST to MockAPI /users
// 3. on success → alert "Registered! Please login" → redirect to login.html
// 4. on failure → show error message on page (not alert)

login.html requirements:

// on submit:
// 1. GET all users from MockAPI
// 2. find user where first_name AND last_name AND password match
// 3. if found:
//    - save user to localStorage: localStorage.setItem("currentUser", JSON.stringify(user))
//    - redirect to dashboard.html
// 4. if not found:
//    - show "Invalid credentials" error on page
//    - shake the form (add a CSS class that animates it)

dashboard.html requirements:

// on page load:
// 1. check localStorage for currentUser
// 2. if not found → redirect to login.html immediately
// 3. if found → show "Welcome back, {first_name}!" in the heading
// 4. show account type badge (Premium/Standard)
// 5. load transactions filtered by userId if you store it

Bonus challenges

Once all 6 parts work, try these:

1. PUT — edit a transaction amount inline
   - clicking amount cell makes it editable (contenteditable)
   - pressing Enter saves it — PUT to MockAPI
   - pressing Escape cancels

2. Search — filter transactions live as you type
   - input above the table
   - keyup event filters rows by amount or type
   - matching rows stay, non-matching rows get display:none

3. Sort — click column headers to sort
   - clicking Date sorts by date asc/desc
   - clicking Amount sorts by amount asc/desc
   - show ▲ ▼ arrow in header to indicate direction
   - implement using your bubble sort from the Python DSA sessions!

4. Logout button
   - clears localStorage
   - redirects to login.html

5. Session persistence
   - on dashboard load, check if token is expired
   - store login timestamp in localStorage
   - if more than 30 minutes have passed → auto logout

File structure

wallet-assignment/
    login.html          ← Part 6
    register.html       ← Part 6
    dashboard.html      ← Parts 1-5
    style.css           ← your own CSS, no Bootstrap
    js/
        transaction.js  ← Transaction class (Part 1)
        wallet.js       ← Wallet class (Part 1)
        render.js       ← renderTransaction() (Part 2)
        events.js       ← all event listeners (Part 3)
        api.js          ← all fetch calls (Part 5)
        login.js        ← login logic (Part 6)
        register.js     ← register logic (Part 6)
        dashboard.js    ← page init, DOMContentLoaded (Parts 4-5)

Checklist before submitting

Part 1 — Classes
  ☐ Transaction class with constructor and getDetails()
  ☐ Wallet class with all 5 methods
  ☐ Validation inside addTransaction()

Part 2 — DOM
  ☐ All 9 DOM methods used
  ☐ Delete button reverses balance
  ☐ No hardcoded rows in HTML

Part 3 — Events
  ☐ All 9 events implemented
  ☐ Live fee preview on keyup
  ☐ Border color changes with transaction type

Part 4 — Async
  ☐ addTransactionAsync returns a Promise
  ☐ Button disabled during processing
  ☐ Loading text shows and hides correctly

Part 5 — Fetch
  ☐ GET loads transactions on page load
  ☐ POST saves new transaction
  ☐ DELETE removes transaction
  ☐ response.ok checked on every request

Part 6 — Login/Register
  ☐ Register POSTs to MockAPI with validation
  ☐ Login GETs and finds matching user
  ☐ currentUser saved to localStorage
  ☐ Dashboard redirects if not logged in
  ☐ Welcome message shows user's name

About

Frontend with Html and Javascript

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors