JavaScript Fundamentals

Programming 2 - Web Technologies

Building Interactive Web Applications

What is JavaScript?

JavaScript is a programming language that runs in web browsers and makes web pages interactive.

The Three Pillars of Web Development:

  • HTML: Structure (the skeleton) - defines content
  • CSS: Style (the appearance) - makes it look good
  • JavaScript: Behavior (the brain) - makes it interactive

What Can JavaScript Do?

  • Respond to user actions (clicks, typing, scrolling)
  • Update content dynamically without reloading the page
  • Fetch data from servers (APIs)
  • Validate forms and process data
  • Create animations and visual effects
  • Build complete web applications

Adding JavaScript to HTML

Three Ways to Include JavaScript:

1. Inline (Not Recommended):

<button onclick="alert('Hello!')">Click Me</button>

2. Internal Script:

<script>...your code...</script>

3. External File (Best Practice):

<script src="app.js"></script>

💡 Best Practice: Put scripts at the end of <body> so HTML loads first!

<!DOCTYPE html>
  <html>
  <head>
      <title>My Page</title>
  </head>
  <body>
      <h1>Hello World</h1>
      <button id="myBtn">Click Me</button>
      
      <!-- JavaScript at the end -->
      <script>
          console.log('Page loaded!');
          
          document.getElementById('myBtn')
              .addEventListener('click', () => {
                  alert('Button clicked!');
              });
      </script>
  </body>
  </html>

Variables and Data Types

Declaring Variables:

  • const - Cannot be reassigned (use by default)
  • let - Can be reassigned
  • var - Old way (avoid using)

Data Types:

  • Number: 42, 3.14
  • String: 'text', "text"
  • Boolean: true, false
  • Array: [1, 2, 3]
  • Object: {name: 'John', age: 25}
// Numbers
  const temperature = 25.5;
  const count = 100;

  // Strings
  const name = 'Arduino';
  const sensor = "DHT11";

  // Booleans
  const isConnected = true;
  const hasError = false;

  // Arrays
  const temps = [25.5, 26.0, 25.8];
  const sensors = ['DHT11', 'MF52A'];

  // Objects
  const reading = {
      temperature: 25.5,
      humidity: 60,
      timestamp: '10:30:00'
  };

Console and Debugging

The Console is Your Best Friend!

Press F12 in your browser to open Developer Tools, then go to the Console tab.

Console Methods:

  • console.log() - Print messages
  • console.error() - Print errors
  • console.warn() - Print warnings
  • console.table() - Display arrays/objects nicely

💡 Debugging Tip: Use console.log() everywhere to see what your code is doing!

// Basic logging
  console.log('Hello World');

  // Multiple values
  const temp = 25.5;
  console.log('Temperature:', temp);

  // Objects
  const sensor = {dht: 25.5, mf52: 25.3};
  console.log('Sensor data:', sensor);
  console.table(sensor); // Nice table format!

  // Arrays
  const readings = [25, 26, 24];
  console.log('Readings:', readings);

  // Errors
  console.error('Connection failed!');

  // Check variable types
  console.log(typeof temp); // "number"
  console.log(typeof sensor); // "object"

Functions

Functions are reusable blocks of code.

Three Ways to Define Functions:

  1. Function Declaration: function name() {...}
  2. Function Expression: const name = function() {...}
  3. Arrow Function (Modern): const name = () => {...}

💡 Tip: Arrow functions are shorter and commonly used in modern JavaScript!

// Function Declaration
  function greet(name) {
      return 'Hello ' + name;
  }

  // Function Expression
  const calculateAverage = function(numbers) {
      const sum = numbers.reduce((a, b) => a + b, 0);
      return sum / numbers.length;
  };

  // Arrow Function (Recommended)
  const celsiusToFahrenheit = (celsius) => {
      return celsius * 9/5 + 32;
  };

  // Short arrow function (one line)
  const square = (x) => x * x;

  // Using functions
  console.log(greet('John'));
  console.log(calculateAverage([25, 26, 24]));
  console.log(celsiusToFahrenheit(25));

DOM Manipulation: Selecting Elements

DOM = Document Object Model - JavaScript's way to interact with HTML.

Selecting Elements:

  • getElementById() - Select by ID
  • querySelector() - Select by CSS selector
  • querySelectorAll() - Select all matching elements

💡 Tip: Use querySelector - it's flexible and works like CSS!

// HTML: <div id="temp">25°C</div>
  const tempDiv = document.getElementById('temp');

  // Using querySelector (more flexible)
  const tempDiv2 = document.querySelector('#temp');
  const div = document.querySelector('div');
  const button = document.querySelector('button');

  // Select multiple elements
  const alldivs = document.querySelectorAll('div');
  console.log('Found', alldivs.length, 'divs');

  // Loop through elements
  alldivs.forEach((div) => {
      console.log(div);
  });

  // Check if element exists
  if (tempDiv) {
      console.log('Element found!');
  } else {
      console.log('Element not found!');
  }

DOM Manipulation: Updating Content

Common Properties:

  • textContent - Text only (safe)
  • innerHTML - HTML content (use carefully)
  • value - For input fields
  • style - Inline CSS styles

💡 Security Tip: Use textContent unless you specifically need HTML!

// Update text
  const tempDisplay = document.getElementById('temp');
  tempDisplay.textContent = '26.5°C';

  // Update with HTML
  const status = document.getElementById('status');
  status.innerHTML = '<strong>Connected</strong>';

  // Get/Set input values
  const nameInput = document.getElementById('nameInput');
  console.log(nameInput.value); // Get value
  nameInput.value = 'John'; // Set value

  // Update styles
  tempDisplay.style.color = 'red';
  tempDisplay.style.fontSize = '24px';
  tempDisplay.style.fontWeight = 'bold';

  // Add/remove CSS classes
  tempDisplay.classList.add('highlight');
  tempDisplay.classList.remove('hidden');
  tempDisplay.classList.toggle('active');

Event Listeners: Responding to User Actions

Common Events:

  • 'click' - Mouse click
  • 'input' - Text input changed
  • 'change' - Value changed
  • 'submit' - Form submitted
  • 'keypress' - Key pressed
  • 'load' - Page/image loaded

💡 Tip: Always use addEventListener instead of inline onclick!

// Click event
  const button = document.getElementById('myBtn');
  button.addEventListener('click', () => {
      console.log('Button clicked!');
  });

  // With event object
  button.addEventListener('click', (event) => {
      console.log('Clicked element:', event.target);
  });

  // Input event (fires as user types)
  const searchBox = document.getElementById('search');
  searchBox.addEventListener('input', (e) => {
      console.log('Current value:', e.target.value);
  });

  // Multiple event listeners
  const refreshBtn = document.getElementById('refresh');
  refreshBtn.addEventListener('click', fetchData);
  refreshBtn.addEventListener('click', updateUI);

  // Remove event listener
  const handler = () => console.log('Clicked');
  button.addEventListener('click', handler);
  button.removeEventListener('click', handler);

Working with Arrays

Arrays store multiple values in a single variable.

Common Array Methods:

  • push() - Add to end
  • pop() - Remove from end
  • shift() - Remove from start
  • unshift() - Add to start
  • forEach() - Loop through items
  • map() - Transform items
  • filter() - Filter items
// Create array
  const temps = [25.5, 26.0, 25.8, 26.2];

  // Add/remove items
  temps.push(26.5);     // Add to end: [25.5, 26.0, 25.8, 26.2, 26.5]
  temps.pop();          // Remove from end: [25.5, 26.0, 25.8, 26.2]
  temps.shift();        // Remove from start: [26.0, 25.8, 26.2]
  temps.unshift(25.5);  // Add to start: [25.5, 26.0, 25.8, 26.2]

  // Loop through array
  temps.forEach((temp) => {
      console.log(temp + '°C');
  });

  // Transform array (convert to Fahrenheit)
  const fahrenheit = temps.map((c) => c * 9/5 + 32);

  // Filter array (only temps above 26)
  const hot = temps.filter((temp) => temp > 26);

  // Get array length
  console.log('Total readings:', temps.length);

Working with Objects

Objects store related data as key-value pairs.

Accessing Object Properties:

  • Dot notation: object.property
  • Bracket notation: object['property']

💡 Use Case: Perfect for sensor data with multiple fields!

// Create object
  const sensorData = {
      dht: 25.5,
      mf52: 25.3,
      humidity: 60,
      timestamp: '10:30:00'
  };

  // Access properties
  console.log(sensorData.dht);        // 25.5
  console.log(sensorData['mf52']);    // 25.3

  // Add new property
  sensorData.outdoor = 22.0;

  // Update property
  sensorData.dht = 26.0;

  // Delete property
  delete sensorData.humidity;

  // Check if property exists
  if ('dht' in sensorData) {
      console.log('DHT exists');
  }

  // Loop through properties
  for (const key in sensorData) {
      console.log(key + ':', sensorData[key]);
  }

JSON: JavaScript Object Notation

JSON is a text format for storing and exchanging data.

Why JSON?

  • Standard format for APIs and data exchange
  • Human-readable and easy to parse
  • Language-independent (works with Python, Java, etc.)

Key Methods:

  • JSON.parse() - Convert JSON string to object
  • JSON.stringify() - Convert object to JSON string

💡 Your Project: Arduino sends JSON, JavaScript parses it!

// JavaScript object
  const data = {
      dht: 25.5,
      mf52: 25.3,
      timestamp: '10:30:00'
  };

  // Convert to JSON string
  const jsonString = JSON.stringify(data);
  console.log(jsonString);
  // Output: {"dht":25.5,"mf52":25.3,"timestamp":"10:30:00"}

  // Parse JSON string to object
  const jsonFromServer = '{"dht":26.0,"mf52":25.8}';
  const parsed = JSON.parse(jsonFromServer);
  console.log(parsed.dht); // 26.0

  // Example: Parsing Arduino data
  const arduinoData = '{"dht":25.5,"mf52":25.3}';
  const sensor = JSON.parse(arduinoData);
  document.getElementById('temp').textContent = 
      sensor.dht + '°C';

Conditionals: Making Decisions

If-Else Statements:

Execute code based on conditions.

Comparison Operators:

  • === Equal to (strict)
  • !== Not equal to
  • > Greater than
  • < Less than
  • >= Greater or equal
  • <= Less or equal

💡 Tip: Use === not == for safer comparisons!

const temperature = 28;

  // Simple if
  if (temperature > 30) {
      console.log('Hot!');
  }

  // If-else
  if (temperature > 30) {
      console.log('Hot!');
  } else {
      console.log('Comfortable');
  }

  // If-else-if
  if (temperature > 30) {
      console.log('Hot!');
  } else if (temperature > 20) {
      console.log('Warm');
  } else {
      console.log('Cold');
  }

  // Logical operators
  if (temperature > 25 && temperature < 30) {
      console.log('Perfect!');
  }

  if (temperature < 10 || temperature > 35) {
      console.log('Extreme temperature!');
  }

Timers: Delayed and Repeated Actions

Two Main Functions:

  • setTimeout() - Execute once after delay
  • setInterval() - Execute repeatedly at intervals

Time is in milliseconds:

  • 1000 ms = 1 second
  • 5000 ms = 5 seconds

💡 Tip: Always clear intervals when done to prevent memory leaks!

// Execute once after 3 seconds
  setTimeout(() => {
      console.log('3 seconds passed!');
  }, 3000);

  // Execute every 2 seconds
  const intervalId = setInterval(() => {
      console.log('This runs every 2 seconds');
  }, 2000);

  // Stop the interval after 10 seconds
  setTimeout(() => {
      clearInterval(intervalId);
      console.log('Interval stopped');
  }, 10000);

  // Example: Update clock every second
  function updateClock() {
      const now = new Date();
      document.getElementById('clock').textContent = 
          now.toLocaleTimeString();
  }

  setInterval(updateClock, 1000);

  // Clear timeout
  const timeoutId = setTimeout(() => {}, 5000);
  clearTimeout(timeoutId);

Template Literals: Better Strings

Template literals use backticks (``) and allow:

  • Variable interpolation with ${}
  • Multi-line strings
  • Expression evaluation

💡 Much Cleaner: No more messy string concatenation with +!

const temperature = 25.5;
  const sensor = 'DHT11';

  // Old way (hard to read)
  const message1 = 'Temperature from ' + sensor + ' is ' + temperature + '°C';

  // New way (clean and readable)
  const message2 = `Temperature from ${sensor} is ${temperature}°C`;

  // With expressions
  const fahrenheit = temperature * 9/5 + 32;
  const message3 = `${temperature}°C = ${fahrenheit}°F`;

  // Multi-line strings
  const report = `
  Sensor Report:
  - DHT11: ${temperature}°C
  - Status: Connected
  - Time: ${new Date().toLocaleTimeString()}
  `;

  console.log(report);

  // In DOM manipulation
  document.getElementById('status').innerHTML = `
      <strong>${sensor}</strong>: ${temperature}°C
  `;

JavaScript Patterns in Your Project

You'll Use These Frequently:

  1. Update Display: Receive data → Parse → Update DOM
  2. Array Management: Add new data → Remove old data → Keep fixed size
  3. Event Handling: WebSocket events → Process data → Update UI
  4. Data Validation: Check if data exists → Handle errors gracefully

💡 Key Skills: DOM manipulation, arrays, objects, and event handling!

// Pattern 1: Update display from sensor data
  function updateDisplay(data) {
      document.getElementById('dhtTemp').textContent = 
          `${data.dht.toFixed(1)}°C`;
      document.getElementById('mf52Temp').textContent = 
          `${data.mf52.toFixed(1)}°C`;
  }

  // Pattern 2: Keep array at fixed size
  const readings = [];
  const MAX_SIZE = 50;

  function addReading(value) {
      readings.push(value);
      if (readings.length > MAX_SIZE) {
          readings.shift(); // Remove oldest
      }
  }

  // Pattern 3: Calculate statistics
  function calculateAverage(arr) {
      if (arr.length === 0) return 0;
      const sum = arr.reduce((a, b) => a + b, 0);
      return (sum / arr.length).toFixed(1);
  }

JavaScript Debugging Tips

Common Errors and Solutions:

1. "Cannot read property of undefined"

  • You're trying to access a property that doesn't exist
  • Solution: Check if object exists first: if (obj) { ... }

2. "element is null"

  • getElementById returned null (element not found)
  • Solution: Check spelling, ensure element exists, put script after HTML

3. Nothing happens

  • Check console for errors (F12)
  • Add console.log() to verify code is running
  • Ensure event listeners are attached correctly

💡 Always: Open DevTools (F12) and check Console tab!

JavaScript Best Practices

✅ Do:

  • Use const by default, let when needed
  • Use descriptive variable names: temperature not t
  • Use === instead of == for comparisons
  • Put scripts at the end of <body>
  • Use template literals for string building
  • Add comments to explain complex logic
  • Check if elements exist before manipulating them
  • Use arrow functions for callbacks
  • Handle errors with try-catch

❌ Don't:

  • Use var (use const or let)
  • Forget to check console for errors
  • Use inline event handlers like onclick
  • Modify arrays while looping through them
  • Forget to clear intervals and timeouts
  • Use generic names like data, temp, x

Practice Exercise: Temperature Converter

Build a simple temperature converter!

Requirements:

  1. Create an HTML page with:
    • Input field for Celsius temperature
    • Convert button
    • Display area for Fahrenheit result
  2. When user clicks "Convert":
    • Read the input value
    • Convert to Fahrenheit: F = C × 9/5 + 32
    • Display the result
  3. Add validation: Show error if input is not a number

💡 Bonus: Make it convert automatically as the user types (use 'input' event)!

Skills Used: DOM selection, event listeners, functions, conditionals, template literals

Modern JavaScript Features (ES6+)

Useful Features You'll See:

1. Destructuring: Extract values easily

2. Spread Operator: Copy/combine arrays

3. Default Parameters: Set defaults

💡 These make code cleaner and more readable!

// 1. Destructuring
  const sensor = {dht: 25.5, mf52: 25.3};
  const {dht, mf52} = sensor;
  console.log(dht); // 25.5

  // Array destructuring
  const temps = [25, 26, 24];
  const [first, second] = temps;
  console.log(first); // 25

  // 2. Spread operator
  const arr1 = [1, 2, 3];
  const arr2 = [4, 5, 6];
  const combined = [...arr1, ...arr2];
  // [1, 2, 3, 4, 5, 6]

  // Copy array
  const copy = [...temps];

  // 3. Default parameters
  function greet(name = 'Guest') {
      return `Hello ${name}`;
  }
  console.log(greet()); // "Hello Guest"

Using Chart.js for Visualization

Chart.js is a JavaScript library for creating charts.

Basic Steps:

  1. Include Chart.js library
  2. Create a <canvas> element
  3. Initialize chart with config
  4. Update chart with new data

💡 Your Project: You'll create 3 line charts for temperature data!

<!-- Include Chart.js -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>

  <!-- Canvas element -->
  <canvas id="tempChart"></canvas>

  <script>
  // Create chart
  const ctx = document.getElementById('tempChart').getContext('2d');
  const chart = new Chart(ctx, {
      type: 'line',
      data: {
          labels: ['10:00', '10:01', '10:02'],
          datasets: [{
              label: 'Temperature',
              data: [25, 26, 25.5],
              borderColor: 'rgb(75, 192, 192)'
          }]
      }
  });

  // Update chart with new data
  chart.data.labels.push('10:03');
  chart.data.datasets[0].data.push(26.2);
  chart.update();
  </script>

Example: Plotting Dynamic Sine Wave

Real-Time Chart Animation:

This example demonstrates continuous chart updates by plotting a moving sine wave.

Key Concepts:

  • Generate data points using Math.sin()
  • Update chart every 100ms with setInterval()
  • Maintain sliding window of data
  • Create smooth animation effect

💡 This Pattern: Same approach used for real-time sensor data!

<canvas id="sineChart"></canvas>

  <script>
  const ctx = document.getElementById('sineChart').getContext('2d');
  const chart = new Chart(ctx, {
      type: 'line',
      data: {
          labels: [],
          datasets: [{
              label: 'sin(x)',
              data: [],
              borderColor: 'rgb(75, 192, 192)',
              tension: 0.4
          }]
      }
  });

  let x = 0;
  const MAX_POINTS = 50;

  setInterval(() => {
      const y = Math.sin(x);
      chart.data.labels.push(x.toFixed(2));
      chart.data.datasets[0].data.push(y);
      
      if (chart.data.labels.length > MAX_POINTS) {
          chart.data.labels.shift();
          chart.data.datasets[0].data.shift();
      }
      
      chart.update('none');
      x += 0.1;
  }, 100);
  </script>

JavaScript Date and Time

The Date Object:

Used for timestamps, scheduling, and time-based features.

Common Methods:

  • new Date() - Current date/time
  • toLocaleTimeString() - Format time
  • toLocaleDateString() - Format date
  • getTime() - Milliseconds since 1970

💡 Use Case: Adding timestamps to sensor readings!

// Current date and time
  const now = new Date();
  console.log(now);

  // Format time
  const time = now.toLocaleTimeString();
  console.log(time); // "10:30:45 AM"

  // Format date
  const date = now.toLocaleDateString();
  console.log(date); // "10/29/2025"

  // Get individual components
  console.log(now.getHours());     // 10
  console.log(now.getMinutes());   // 30
  console.log(now.getSeconds());   // 45

  // Create custom timestamp
  const timestamp = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;

  // Calculate time difference
  const start = new Date();
  // ... some operations ...
  const end = new Date();
  const elapsed = end - start; // milliseconds
  console.log(`Took ${elapsed}ms`);

Error Handling: Try-Catch

Handle errors gracefully to prevent crashes.

Why Use Try-Catch?

  • Prevent entire script from stopping
  • Show user-friendly error messages
  • Log errors for debugging
  • Provide fallback behavior

💡 Best Practice: Always wrap risky operations (parsing JSON, API calls) in try-catch!

// Basic try-catch
  try {
      const data = JSON.parse(jsonString);
      console.log(data);
  } catch (error) {
      console.error('Failed to parse:', error);
  }

  // With user feedback
  function updateSensorDisplay(jsonData) {
      try {
          const data = JSON.parse(jsonData);
          document.getElementById('temp').textContent = 
              data.temperature + '°C';
      } catch (error) {
          console.error('Error:', error);
          document.getElementById('temp').textContent = 
              'Error reading sensor';
      }
  }

  // With finally (always executes)
  try {
      fetchData();
  } catch (error) {
      console.error('Error:', error);
  } finally {
      console.log('Cleanup complete');
  }

Local Storage: Saving Data in Browser

Local Storage allows saving data in the browser.

Key Methods:

  • localStorage.setItem(key, value) - Save
  • localStorage.getItem(key) - Retrieve
  • localStorage.removeItem(key) - Delete
  • localStorage.clear() - Clear all

⚠️ Important: Can only store strings, use JSON.stringify/parse for objects!

💡 Use Case: Remember user settings, save data between sessions

// Save string
  localStorage.setItem('username', 'John');

  // Retrieve string
  const username = localStorage.getItem('username');
  console.log(username); // "John"

  // Save object (must stringify)
  const settings = {
      theme: 'dark',
      notifications: true
  };
  localStorage.setItem('settings', JSON.stringify(settings));

  // Retrieve object (must parse)
  const savedSettings = localStorage.getItem('settings');
  const parsed = JSON.parse(savedSettings);
  console.log(parsed.theme); // "dark"

  // Delete item
  localStorage.removeItem('username');

  // Clear all
  localStorage.clear();

  // Check if key exists
  if (localStorage.getItem('username')) {
      console.log('Username found');
  }

Essential Patterns You'll Use

These patterns appear everywhere in web development:

💡 Master These: They're the foundation of interactive web apps!

// Pattern 1: Safe element access
  const element = document.getElementById('temp');
  if (element) {
      element.textContent = '25°C';
  }

  // Pattern 2: Validate before processing
  function processData(data) {
      if (!data || typeof data.temperature !== 'number') {
          console.error('Invalid data');
          return;
      }
      // Process valid data
  }

  // Pattern 3: Array with max size (sliding window)
  function addWithLimit(array, value, maxSize) {
      array.push(value);
      if (array.length > maxSize) {
          array.shift();
      }
  }

  // Pattern 4: Format numbers
  const temp = 25.567;
  console.log(temp.toFixed(1)); // "25.6"
  console.log(temp.toFixed(2)); // "25.57"

JavaScript Learning Resources

Official Documentation:

  • MDN Web Docs: developer.mozilla.org (most comprehensive)
  • JavaScript.info: javascript.info (excellent tutorials)
  • Chart.js Docs: chartjs.org/docs

Interactive Learning:

  • FreeCodeCamp JavaScript course
  • JavaScript30.com (30 day challenge)
  • Codecademy JavaScript course

Practice:

  • Build small projects (calculator, to-do list, timer)
  • Experiment in browser console (F12)
  • Modify examples and see what happens
  • Debug errors yourself before asking for help

💡 Best Way to Learn: Code every day, even for 15 minutes!