Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
⚡ Days 15–22 – Advanced & Async JavaScript  ·  Day 22

Day 22: Useful Browser APIs

⏱ 95 min📶 Intermediate → Pro🎯 100% self-study
Day 22 / 30

✅ Today you will learn

  • URL and URLSearchParams for shareable filters
  • History API: pushState, popstate
  • IntersectionObserver: lazy loading, infinite scroll, reveal animations
  • Clipboard, Web Share and WhatsApp deep links
  • Geolocation and permissions – used responsibly

🏢 In the real world

The shop owner asks: “When I send a customer a link to milk sweets under ₹700, it should open with that filter already on.” “Can customers copy the coupon in one tap and share a product on WhatsApp?” “Can we tell how far the customer is from the shop?” All of this is built into the browser – no libraries needed.

URL and URLSearchParams

JavaScript
const link = new URL('https://sharmasweets.in/menu?category=milk&max=700&sort=price#list');
console.log(link.hostname, link.pathname, link.hash);
console.log(link.searchParams.get('category'), Number(link.searchParams.get('max')));
console.log(link.searchParams.has('veg'));

link.searchParams.set('max', 900);          // update
link.searchParams.append('tag', 'sugar-free');
link.searchParams.delete('sort');
console.log(link.toString());

const p = new URLSearchParams({ q: 'kaju katli', city: 'Jaipur' });
console.log(p.toString());                  // spaces and special characters encoded safely
sharmasweets.in /menu #list milk 700 false https://sharmasweets.in/menu?category=milk&max=900&tag=sugar-free#list q=kaju+katli&city=Jaipur

Shareable filters with the History API

HTML + JavaScript
<label>Category <select id="cat"><option value="">All</option><option value="milk">Milk</option><option value="dry">Dry</option></select></label>
<label>Max ₹ <input id="max" type="number" step="100" value="1000" style="width:90px"></label>
<p>Address bar would show: <code id="addr"></code></p>
<ul id="list"></ul>

<script>
const products = [
  { name: 'Kaju Katli', category: 'dry', price: 900 }, { name: 'Ghewar', category: 'milk', price: 650 },
  { name: 'Rasmalai', category: 'milk', price: 700 }, { name: 'Ladoo', category: 'dry', price: 500 },
];
const cat = document.querySelector('#cat'), max = document.querySelector('#max');

function render() {
  const list = products.filter(p => (!cat.value || p.category === cat.value) && p.price <= Number(max.value));
  document.querySelector('#list').innerHTML = list.map(p => `<li>${p.name} – ₹${p.price}</li>`).join('') || '<li>None</li>';
}
function updateUrl() {
  const params = new URLSearchParams();
  if (cat.value) params.set('category', cat.value);
  if (max.value !== '1000') params.set('max', max.value);
  const url = location.pathname + (params.toString() ? '?' + params : '');
  try { history.pushState({ category: cat.value, max: max.value }, '', url); } catch (e) { /* sandboxed preview */ }
  document.querySelector('#addr').textContent = '/menu' + (params.toString() ? '?' + params : '');
}
// read filters from the URL on load (works on a real page)
const start = new URLSearchParams(location.search);
if (start.get('category')) cat.value = start.get('category');
if (start.get('max')) max.value = start.get('max');

[cat, max].forEach(el => el.addEventListener('input', () => { updateUrl(); render(); }));
window.addEventListener('popstate', (e) => {          // Back / Forward buttons
  cat.value = e.state?.category ?? ''; max.value = e.state?.max ?? '1000'; render();
});
updateUrl(); render();
</script>
▶  Change the filters – the URL updates so the exact view can be shared or bookmarked

IntersectionObserver: react when things scroll into view

HTML + JavaScript
<style>
.reveal { padding: 18px; margin: 8px 0; background: #fef3c7; border-radius: 10px; opacity: 0; transform: translateY(16px); transition: .5s; }
.reveal.show { opacity: 1; transform: none; }
</style>

<p>Scroll inside this box ↓</p>
<div id="feed" style="height:260px;overflow:auto;border:1px solid #e5e7eb;border-radius:10px;padding:10px"></div>

<script>
const feed = document.querySelector('#feed');
let page = 0;
const names = ['Kaju Katli', 'Ghewar', 'Rasmalai', 'Ladoo', 'Kalakand', 'Soan Papdi', 'Peda', 'Jalebi'];

const sentinel = document.createElement('p');      // invisible marker at the bottom
sentinel.textContent = 'Loading more…';

function addPage() {
  page++;
  for (let i = 0; i < 4; i++) {
    const card = document.createElement('div');
    card.className = 'reveal';
    card.textContent = `#${(page - 1) * 4 + i + 1} ${names[((page - 1) * 4 + i) % names.length]}`;
    feed.insertBefore(card, sentinel);
    revealObserver.observe(card);
  }
  if (page >= 5) { sentinel.textContent = 'That’s all 🍬'; moreObserver.disconnect(); }
}

// 1. Reveal animation when a card enters the box
const revealObserver = new IntersectionObserver((entries) => {
  entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('show'); revealObserver.unobserve(e.target); } });
}, { root: feed, threshold: 0.3 });

// 2. Infinite scroll: load the next page when the sentinel appears
const moreObserver = new IntersectionObserver((entries) => {
  if (entries[0].isIntersecting) addPage();
}, { root: feed, rootMargin: '80px' });

feed.append(sentinel);
moreObserver.observe(sentinel);
</script>
▶  Cards fade in and new pages load automatically – no scroll events
Use caseHow
Lazy-load imagesObserve img[data-src]; when visible set src (or simply use loading="lazy")
Infinite scrollObserve a sentinel at the end of the list, fetch the next page
Scroll reveal animationsAdd a class when an element enters the viewport
Analytics “seen” eventsCount a banner as viewed when 50% visible for 1 s
Pause videosPause when the video leaves the screen
💡 Why not the scroll event?

scroll fires dozens of times per second and measuring positions forces layout calculations – janky on cheap phones. IntersectionObserver is calculated by the browser efficiently and only calls you when visibility actually changes.

Clipboard, Web Share and WhatsApp links

HTML + JavaScript
<p>Coupon: <code id="code">SWEET10</code> <button id="copy">Copy</button></p>
<p><button id="share">Share this product</button>
<a id="wa" target="_blank" rel="noopener">Order on WhatsApp</a></p>
<p id="msg" role="status"></p>

<script>
const msg = document.querySelector('#msg');

document.querySelector('#copy').addEventListener('click', async () => {
  const code = document.querySelector('#code').textContent;
  try {
    await navigator.clipboard.writeText(code);          // needs HTTPS and a user click
    msg.textContent = 'Copied ✅';
  } catch (err) {
    msg.textContent = 'Copy blocked here – select and copy manually: ' + code;
  }
});

document.querySelector('#share').addEventListener('click', async () => {
  const data = { title: 'Kaju Katli – Sharma Sweets', text: 'Fresh kaju katli ₹900/kg 🍬', url: 'https://sharmasweets.in/menu#kaju' };
  if (navigator.share) {
    try { await navigator.share(data); msg.textContent = 'Shared!'; }
    catch (err) { msg.textContent = 'Share cancelled'; }
  } else {
    msg.textContent = 'Web Share is not available on this device – use the WhatsApp link.';
  }
});

const text = 'Namaste! I want to order 1 kg Kaju Katli for delivery tomorrow.';
document.querySelector('#wa').href = 'https://wa.me/919829012345?text=' + encodeURIComponent(text);
</script>
▶  Copy to clipboard, native share sheet on phones and a pre-filled WhatsApp order
🧠 encodeURIComponent

Spaces, &, ? and Hindi text must be encoded inside URLs. encodeURIComponent turns “1 kg Kaju & Ghewar” into a safe string – forgetting it breaks WhatsApp messages at the first &.

Geolocation: distance to the shop

HTML + JavaScript
<button id="locate">How far am I from the shop?</button>
<p id="dist" role="status"></p>

<script>
const SHOP = { lat: 26.9196, lon: 75.8235 };        // Johari Bazaar, Jaipur

function km(a, b) {                                  // Haversine formula
  const R = 6371, rad = d => d * Math.PI / 180;
  const dLat = rad(b.lat - a.lat), dLon = rad(b.lon - a.lon);
  const h = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2;
  return 2 * R * Math.asin(Math.sqrt(h));
}

document.querySelector('#locate').addEventListener('click', () => {
  const out = document.querySelector('#dist');
  if (!('geolocation' in navigator)) { out.textContent = 'Location not supported'; return; }
  out.textContent = 'Asking for permission…';
  navigator.geolocation.getCurrentPosition(
    pos => {
      const d = km(SHOP, { lat: pos.coords.latitude, lon: pos.coords.longitude });
      out.textContent = `You are about ${d.toFixed(1)} km away. ${d <= 15 ? 'We deliver to you 🛵' : 'Courier for dry sweets 📦'}`;
    },
    err => { out.textContent = 'Location unavailable (' + err.message + '). Enter your PIN code instead.'; },
    { enableHighAccuracy: false, timeout: 8000, maximumAge: 600000 }
  );
});
</script>
▶  Uses permission – in this sandboxed preview it falls back to the error path
APINeedsGood practice
GeolocationHTTPS + permissionAsk only after a click, explain why, offer a PIN-code fallback
Clipboard writeHTTPS + user gestureShow a “Copied” confirmation
Web ShareHTTPS, mainly mobileFeature-detect and offer a fallback link
NotificationsPermissionAsk only after the user opts in (e.g. “Notify me when ghewar is back”)
Page VisibilityNothingPause timers/polling when document.hidden

🏅 Job skills unlocked today

✔ Read and write URL parameters and keep filters in the address bar✔ Use IntersectionObserver for lazy loading, infinite scroll and reveals✔ Add copy, share and WhatsApp features✔ Use geolocation and permissions responsibly with fallbacks

Practice tasks

🏋️ Practice – do it yourself

Task 1: Build a WhatsApp order link from a cart array [{name, qty}] with each item on a new line.
Show solution
JavaScript
const cart = [{ name: 'Kaju Katli', qty: 2 }, { name: 'Ghewar', qty: 1 }, { name: 'Ladoo & Peda box', qty: 1 }];
const lines = ['Namaste Sharma Sweets 🙏', 'My order:', ...cart.map(i => `• ${i.name} × ${i.qty}`), 'Please confirm.'];
const url = 'https://wa.me/919829012345?text=' + encodeURIComponent(lines.join('\n'));
console.log(url);
https://wa.me/919829012345?text=Namaste%20Sharma%20Sweets%20%F0%9F%99%8F%0AMy%20order%3A%0A%E2%80%A2%20Kaju%20Katli%20%C3%97%202%0A%E2%80%A2%20Ghewar%20%C3%97%201%0A%E2%80%A2%20Ladoo%20%26%20Peda%20box%20%C3%97%201%0APlease%20confirm.
Task 2: Read ?lang=hi from the URL and switch a heading between English and Hindi.
Task 3: Pause a countdown timer when the tab is hidden using document.visibilityState.

Quick quiz

🧠 Quick Quiz – test yourself

1. new URLSearchParams('a=1&b=2').get('b') is…
Always strings.
2. history.pushState…
Listen to popstate for Back.
3. Best tool for infinite scroll?
Efficient visibility checks.
4. Text in a wa.me link must be…
Safe characters.
5. When should you ask for location permission?
Context builds trust.

Interview corner

💼 Interview Corner

How would you implement infinite scroll?

Render the first page, place a sentinel element after the list and observe it with IntersectionObserver (with rootMargin for prefetch). When it intersects, fetch the next page (guarding against duplicate requests), append items, and stop observing at the end. Keep URLs/state for back navigation and consider virtualisation for very long lists.

Why keep filters in the URL?

URLs are shareable, bookmarkable, work with Back/Forward, survive refreshes and help SEO and analytics. URLSearchParams + history.pushState/replaceState keep UI state and URL in sync without reloads.

Summary

  • URL/URLSearchParams parse and build query strings safely.
  • pushState + popstate keep filters shareable without reloads.
  • IntersectionObserver for lazy load, infinite scroll and reveals.
  • Clipboard, Share, WhatsApp links and geolocation – with HTTPS, permission and fallbacks.
➡️ Next

Day 23: regular expressions – validate mobile numbers, PIN codes, GSTIN, e-mail and passwords properly.

Frequently Asked Questions

Why did some demos say “blocked here”?
Lesson previews run in a sandboxed frame for safety, where clipboard, location and history changes are restricted. The same code works on a normal HTTPS page.
Can I get the user’s address from geolocation?
Geolocation gives coordinates only. Turning them into an address needs a geocoding service (e.g. Google Maps API) – and clear consent.
← JavaScript (30 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 23: Regular Expressions for Real Validation Your progress: 22 / 30 (73%) · Lesson 23 / 30 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free