Module 70 : Using JavaScript Libraries (e.g., jQuery, Chart.js).
0) Foundation Concepts
0.1 Library vs Framework vs Plugin
Library: A toolbox of functions/components you call (e.g., jQuery, Chart.js). You control the flow.
Framework: Inversion of control; the framework calls your code (e.g., React, Vue, Angular).
Plugin: Extends a host library (e.g., a jQuery plugin adds a new $.fn.* method).
0.2 Versioning & Compatibility (SemVer)
MAJOR.MINOR.PATCH → Breaking features, new features, bug fixes respectively.
Pin exact versions for reproducible builds. Test upgrades deliberately.
0.3 Installation Options
CDN: Quick start in HTML via <script> tags. Good for prototypes, demos, or when build tools are not used.
npm: npm i jquery chart.js for production/apps with bundlers (Vite, Webpack). Enables tree-shaking, code splitting, and lockfiles.
1) Using jQuery Effectively
1.1 Loading jQuery
CDN (quick demo)
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
Use the full build (not the “slim” build) if you need AJAX/effects.
npm
npm i jquery
Then in modules/bundlers:
import $ from 'jquery';
1.2 Core Ideas
Selector engine: $(".card[data-id='7']") → returns a jQuery collection.
Chaining:
$('li').addClass('todo').attr('role','listitem').
Each: $('li').each((i, el) => console.log(i, el));
1.3 DOM Selection & Traversal
const $items = $('ul#tasks > li');
$items.first().text('First task!');
$items.eq(2).addClass('highlight');
$items.parent().addClass('has-tasks');
$items.filter('.done').hide();
$items.not('.done').show();
1.4 Events & Delegation (Performance & Dynamic Content)
// Bad: binds to each button individually
$('.remove').on('click', function(){ /* ... */ });
// Good: delegate to a static parent
$('#task-list').on('click', '.remove', function(){
$(this).closest('li').remove();
});
Why delegation? Future items added dynamically also work; fewer listeners → faster.
1.5 DOM Manipulation & Effects
$('#add').on('click', function(){
const text = $('#newTask').val().trim();
if (!text) return;
$('#task-list').append(`<li>${text} <button class="remove">×</button></li>`);
$('#newTask').val('').focus();
});
$('#task-list').on('mouseenter', 'li', function(){ $(this).addClass('hover'); });
$('#task-list').on('mouseleave', 'li', function(){ $(this).removeClass('hover'); });
1.6 AJAX with jQuery vs fetch
// jQuery
$.getJSON('/api/todos').done(data => {
$('#task-count').text(data.length);
});
// Native fetch (modern standard)
fetch('/api/todos')
.then(res => res.json())
.then(data => $('#task-count').text(data.length));
prefer fetch for new code; jQuery AJAX is handy when you’re already in jQuery land.
1.7 Writing a Tiny jQuery Plugin
(function($){
$.fn.highlight = function(color = '#fffbcc'){
return this.each(function(){
const $el = $(this);
const original = $el.css('backgroundColor');
$el.css('backgroundColor', color);
setTimeout(() => $el.css('backgroundColor', original), 600);
});
};
})(jQuery);
// Usage:
$('li.new').highlight('#d1ffd1');
1.8 Pitfalls
Cache selections: const $rows = $('tr'); then reuse.
Use delegation for dynamic lists.
Don’t mix raw nodes and jQuery objects accidentally: $(el) vs el.
Keep logic (data) separate from presentation (DOM) as much as feasible.
2) Chart.js for Data Visualization
2.1 Loading Chart.js
CDN
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
npm
npm i chart.js
import { Chart } from 'chart.js';
2.2 Basic Line Chart
<canvas id="salesChart" width="400" height="220"></canvas>
<script>
const ctx = document.getElementById('salesChart').getContext('2d');
const salesChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan','Feb','Mar','Apr','May','Jun'],
datasets: [{
label: 'Revenue ($k)',
data: [12, 19, 13, 25, 22, 30],
fill: false,
tension: 0.25
}]
},
options: {
responsive: true,
plugins: {
title: { display: true, text: 'Half-Year Revenue' },
legend: { position: 'bottom' },
tooltip: { enabled: true }
},
scales: {
y: { beginAtZero: true }
}
}
});
</script>
2.3 Updating Data Dynamically
function pushPoint(chart, label, value){
chart.data.labels.push(label);
chart.data.datasets[0].data.push(value);
chart.update();
}
// Example
pushPoint(salesChart, 'Jul', 28);
2.4 Destroy/Recreate to Avoid Duplicates
if (window._chart) window._chart.destroy();
window._chart = new Chart(ctx, config);
2.5 Time-Series (with Luxon adapter)
<script src="https://cdn.jsdelivr.net/npm/luxon"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon"></script>
const timeChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'CPU %',
data: [
{ x: '2025-01-01T00:00:00Z', y: 42 },
{ x: '2025-01-01T01:00:00Z', y: 51 }
]
}]
},
options: {
parsing: false,
scales: {
x: { type: 'time', time: { unit: 'hour' } },
y: { beginAtZero: true, max: 100 }
}
}
});
2.6 Performance Tips
Prefer fewer points or enable decimation (built-in).
Turn off animations for very large datasets.
Use parsing: false when your data already has {x,y} pairs.
Keep one Chart instance; update data instead of recreating frequently.
2.7 Accessibility
Provide a text/table fallback or downloadable CSV.
Use descriptive titles and labels.
Ensure sufficient color contrast (don’t rely on color alone).
3) jQuery + Chart.js Together (Mini App)
Goal: A simple “Scores Dashboard” where a form (jQuery) feeds a live chart (Chart.js).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scores Dashboard</title>
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; }
form, canvas { max-width: 680px; }
.row { display: flex; gap: .5rem; margin-block: .5rem; }
label { min-width: 6rem; }
</style>
</head>
<body>
<h1>Scores Dashboard</h1>
<form id="scoreForm">
<div class="row"><label>Label</label><input id="label" required /></div>
<div class="row"><label>Score</label><input id="value" type="number" min="0" max="100" required /></div>
<button type="submit">Add</button>
<button type="button" id="reset">Reset</button>
</form>
<canvas id="scoreChart" height="240"></canvas>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('scoreChart').getContext('2d');
const config = {
type: 'bar',
data: { labels: [], datasets: [{ label: 'Score', data: [] }] },
options: { scales: { y: { beginAtZero: true, max: 100 } } }
};
const chart = new Chart(ctx, config);
$('#scoreForm').on('submit', function(e){
4) Exercises
Exercise A — DOM & Events with jQuery
Build a To-Do list where items can be added, marked done, filtered (All/Active/Done), and removed. Use event delegation.
Key Points: Cache selectors, separate state (array of todos) from DOM, update efficiently.
Hint:
const todos = [];
$('#add').on('click', () => { /* push to array, render() */ });
$('#list').on('click', '.toggle', (e) => { /* find by id, flip done */ });
Exercise B — Line Chart with Live Updates
Create a Chart.js line chart that appends a random point every second for 30 seconds.
Key Points: Keep a single Chart instance; call chart.update(); stop timer afterward.
Exercise C — Tooltips & Legend Customization
Add custom tooltip callbacks that show label: value%. Move legend to the bottom.
Key Points: options.plugins.tooltip.callbacks, options.plugins.legend.position.
Exercise D — Mixed Chart
Create a chart with two datasets: bars for quantity and a line for average price. Use a secondary axis for price.
Key Points: scales: { y: {...}, y1: { position: 'right' } } and set dataset.yAxisID.
Exercise E — Form + Chart Integration
Extend the “Scores Dashboard” to allow editing existing labels/values by clicking a bar.
Key Points: Use chart events: read active elements via chart.getElementsAtEventForMode.
5) (Capstone)
Title: Weather Trends Mini-Portal (jQuery + Chart.js)
Build a small web app that displays the next 7 days of temperature highs/lows for a chosen city. Provide both a data table (for accessibility) and a chart. Compare two data-loading approaches: (1) direct API call via fetch, (2) loading from a local JSON file (offline mode).