Sixteen modules that take you from an empty VS Code window to a page that validates a form, answers a click and rewrites itself — with every single line running in front of you, next to the code that made it. No prior JavaScript assumed. None at all.
Module 9 teaches you to write this. Module 10 covers every rule the exam has ever asked for.The web worked exactly like that until 1995. You filled a form, pressed submit, and the entire page went away and came back. Wrong pincode? The whole page reloads to tell you. Every field you typed, gone.
Every “Add to cart” that updates the number in the corner, every search box that suggests as you type, every form that turns a field red before you submit — all of it is the thing you are about to learn.
Because of marketing. In 1995 Java was the exciting thing, and Netscape had a deal with Sun, the company that owned Java. The language was called Mocha, then LiveScript, and then — three months before release — renamed JavaScript to ride Java's popularity.
null that reports itself as an object. Every one of them traces back to a decision made in a hurry in 1995, and by then the whole web was using it and it was too late to fix. Module 13 is built entirely out of these, and the exam asks about them every single year.Your course is called Full Stack Web Development, and the stack is MERN. Here is the thing worth noticing:
I read the last four question papers. The topics are not spread evenly — some come up almost every time, and those are the ones this course spends its hours on.
<input> existsYou type an address, press enter, and a page appears. Five things happen in between, and knowing them makes Module 11 familiar instead of mysterious.
null. That is the most common first error in JavaScript, and Module 2 shows it happening on purpose so it never confuses you.You finished a whole unit of Java. That is an advantage here, and a trap. The names are similar and a few things look alike, but underneath they are different in ways that get examined.
javac into bytecodeint x = 5; and x is forever a numberlet x = 5; then x = "five" is allowedpublic static void main is the way inmain — the script runs, top to bottom1. A page shows a red error under a field the moment you type. Which of the three languages is doing that, and why can it not be the other two?
2. You change a heading with JavaScript, then press refresh. The old heading is back. Why?
3. Name one thing Java checks that JavaScript will not.
javac refuses to build a program with a misspelled variable. JavaScript runs it happily and goes wrong later. That trade — freedom now, mistakes later — is the single biggest difference in how the two languages feel.Module 0 writes no code — it is the twenty minutes that makes the rest make sense. From Module 1 onward every chunk adds a file, and this tree is redrawn at the end of each module so you always know where you are.
FSWD-Unit2. Inside it, another called 01-skeleton. Every module in this course gets its own folder, and by Module 15 you will have a real project.FSWD-Unit2. The Explorer panel on the left is now your project.01-skeleton and type the name with the extension: index.htmlindex and VS Code treats it as plain text — no colours, no autocomplete, and the browser will show it as text rather than a page. Save it as index.html and everything wakes up. If your file looks grey and lifeless, this is why.index.html and not page.html? index.html is the name every web server looks for by default. Open a folder and the server serves index.html without being asked. Any name works while you are learning — but this is the habit that matters later.Folder on the left, file open in the middle, blue bar along the bottom with Go Live on the right. If your window looks like this, you are ready.
.html file, type a single ! and press Tab. VS Code writes the whole skeleton for you. Type it out by hand once so you know what it made — then use ! forever after.<!DOCTYPE html><html lang="en"><head><meta charset><title><body><h1> lives in the body127.0.0.1:5500/01-skeleton/index.html.javac here.You can, and it opens. But look at the address bar — it says file:///C:/Users/... instead of 127.0.0.1:5500. That difference matters later: some things a browser can do over http are blocked over file. Getting into the Live Server habit now saves a confusing hour in Unit 4.
Rules stick better when you have seen them broken. Here is the same heading written twice — once in the head, once in the body.
bodylabeldisplay: block puts each label on its own lineinputbutton.error.error is the only new punctuation here. A plain word like button styles every button on the page. A word with a dot in front styles only the elements you have marked with class="error". That is the whole difference, and it is all the CSS you need for this unit.<style> goes in the head, because it is information about the page rather than content on it. Same rule as always.id — who, go, msg. That is the handle JavaScript grabs it by. Give things ids from the start and your life gets easier.<p id="msg"> is deliberate. It sits there doing nothing until JavaScript puts a message in it. Almost every validation answer in the papers uses exactly this.input rule; a page with no error message does not need .error. Later modules show a <style> block with two or three of these rules in it — that is not a different stylesheet, it is this one with the unused lines removed. Keep the full five somewhere you can copy from.Two files. By Module 15 this tree has fifteen folders and around forty files, and every one of them runs.
02-practice and a file bus.html inside it. Build a page titled Bus pass with a heading, two text boxes labelled Roll number and Route, and a button reading Apply. Run it with Live Server.<input> inside the <label> means clicking the words focuses the box — free, and better for everyone. And the button still does nothing, which is still correct.
<h1>Hello</h1> instead of a heading. Give two possible reasons..html. Saved as page or page.txt, the browser treats it as plain text and prints the tags instead of obeying them. Check the tab in VS Code: no syntax colours means no .html.<!DOCTYPE html> line is missing or misspelled and the page is being read in a legacy mode. Less likely than the first, but worth a look.<p>Welcome</p> inside <head> and nothing appears. Explain why, in the wording an examiner would want.<script> tag. Where you put that tag decides whether your code works — and getting it wrong produces no warning at all, only a page that ignores you.<p id="box"> did not exist yet. The script asked for something that was not there and gave up quietly.</body>. By then the whole page exists and your code can reach any part of it.innerHTMLconsole.logalertdocument.write#outnull means nothing was found. You asked for an element and got nothing back.outt; the paragraph is out. One letter.>, type 2 + 2, press enter. It answers. Type document.title and it tells you the page title. It is a live JavaScript scratchpad sitting inside every browser, and it costs nothing to experiment in.document.getElementById("go") hands you the button..onclick = () => { ... } hands the browser a set of instructions to keep.innerHTML becomes new text, and the page updates. No reload.Uncaught TypeError: Cannot set properties of null. Without seeing their code, what are the two most likely causes?getElementById("..."), or the element has a different id, or a class where they meant an id. Nothing was found, so they got null.<head> or above the element. The id is spelt perfectly; it has not been built yet.console.log("hello") show nothing on the page, and when would you still want it?innerHTML for the user, console.log for you.
03-variables inside FSWD-Unit2 · new files box.html · types.html · leak.html · join.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Serverlet student = "Asha"; makes the box, labels it student, and puts "Asha" in it. The word let is what makes a new box.student on its own reads the box. Line 11 does not print the word “student” — it prints what is inside, which is Asha.student = "Ravi"; replaces what is inside. No let this time — the box already exists, you are only changing its contents.+= adds to what is already there rather than replacing it, which is why the paragraph ends up with both names.let student = "Ravi"; on line 13. That tries to make a second box with the same label, and the browser refuses — SyntaxError: Identifier 'student' has already been declared. Use let once, when the box is born.let. Changing what is in it does not.typeof will tell you what it thinks it is holding.string"Asha" or 'Asha'number74 8.5 -3booleantrue falseundefinedlet absent;nulltypeof says "object", a 1995 bug (Module 13)let winner = null;symbolSymbol("id")bigintnumber9007199254740993nobject{ roll: 733 }grades is a listtypeof says object — see the note belowgrades reported. It is a list, but typeof said object. That is not a mistake in your code — JavaScript genuinely treats a list as a kind of object. It surprises everybody, and it is one of the quirks Module 13 traces back to 1995.int, no double, no char, no float. JavaScript has one number type for everything, and you never write the type when you make a box. The box works out what it is holding by itself.var. 2. Both are block scoped — they exist only inside the { } they were made in. 3. let can be reassigned; const cannot. 4. const must be given a value immediately. Add one line of code for each and the four marks are safe.var. It still works, you will see it in old code and in your question papers — and it behaves in a way that catches people out.letconst by default. Use let when it has to change.var at all.+Count the quotes. Count the spaces. Miss one + and it breaks; miss a space and words run together. Works everywhere, but it is fiddly.${ }. A space stays a space. This is what you should use.`, not an apostrophe. On most keyboards it is the key left of 1, sharing with ~.${...} means “put the value here”. Anything can go inside the braces — a variable, a sum, a function call.+ in the papers, because the questions predate ES6 in places. Both are correct and both earn full marks. Read + fluently; write backticks.const values — a price of 60, a quantity of 3, and the total. Show the sentence 3 dosas at ₹60 each = ₹180 using backticks.total is a const too. It is worked out once and never changed, so it does not need let. That is the habit: reach for const first and only downgrade when you find you must.
const marks = [74, 81];
marks.push(66);
console.log(marks.length);const?const does not mean the value cannot change — it means the box cannot be pointed at something else. The list is still the same list; you have added to it. What const forbids is marks = [1, 2], which would try to put a different list in the box.typeof reports for a list — and why that is surprising."Asha" · Number 74 · Boolean true · Object { roll: 733 }. Undefined and Null are the other two worth mentioning.typeof [74, 81] reports "object". Surprising because a list feels like its own kind of thing — but in JavaScript a list is a kind of object, with numbered keys instead of named ones.Array.isArray(grades) answers properly. Module 6 uses it.
04-functions inside FSWD-Unit2 · new files greet.html · four.html · arrows.html · this.html · fare.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Serverfunction greet(name) { writes the recipe down and names it greet. Nothing runs yet — a written recipe is not a meal.name is the ingredient slot. Whatever you hand in when you call it lands in name for the length of that one run.return hands a value back to whoever called it. Line 14 does not print anything itself — it returns a piece of text, and the caller decides what to do with it.greet("Asha") cooks it. This is the moment the instructions actually run. Three calls, three separate runs, no interference between them.String greet(...), only function greet(...). And there is no class to put it in. A function can sit on its own in a file, which in Java it never could.function comes first, then the name. This shape is hoisted, which means you can call it on a line above where it is written. The other three cannot do that.areaB holds a function the same way a box could hold a number.function deleted and => added after the brackets. That is the entire change.return go. What is left is almost the maths itself.function area(s) { }const area = function (s) { }const area = (s) => { }const area = s => s * sReferenceError: Cannot access 'areaD' before initialization. Write your functions before you call them and this never comes up.;. A declaration is not an assignment, so it does not. Nothing breaks if you get it wrong, but it is the kind of detail a marker notices.name => ... is the same as (name) => .... Both are correct; the short one is more common.() => "OI!". You cannot leave them out entirely.return. s => s * s returns automatically. Add braces and you must write return yourself.(amount, rate = 0.05) — leave rate out when calling and it uses 0.05....marks collects however many arrive. Call it with four numbers or forty; they arrive as a list called marks.const greet = name => `Hello, ${name}!`;
console.log(greet("Asha")); // Hello, Asha!const total = marks => marks.reduce((a, b) => a + b, 0);
console.log(total([74, 81, 66])); // 2210 at the end matters — it is the starting total, and without it an empty list throws an error. reduce is covered properly in Module 6; a plain for loop earns the same marks if you prefer it.greet() is a normal method. Inside it, this is whatever sits before the dot — student — so it hands back Asha.greetArrow prints undefined, with no error. An arrow function does not get its own this, so use a normal method when you need the object.fare knows one thing — how to turn kilometres into rupees. It does not know about buttons, pages or text boxes, and that is why it is quick to test and ready to reuse.Number(...) matters. A text box always hands back text, even when it looks like a number. Without it, "12" * 2.5 happens to work, but "12" + 2.5 would give you "122.5". Module 13 explains why.() => { ... } — no parameters, several statements, so braces are needed. This is the shape you will write hundreds of times.isEven that takes a number and returns true or false. Use the shortest form that works.n, no braces, no return. n % 2 gives the remainder; === 0 turns that into true or false. Three equals signs, not two — Module 13 explains why that matters more than it looks.
const square = n => { n * n };
console.log(square(5));undefined.return. n * n is calculated and thrown away. No error is raised, which is what makes this one nasty — it silently gives you nothing.n => n * n — or keep them and write return n * n;.const fee = (amount, rate = 0.05) => amount * rate;
console.log(fee(2000)); // 100 — uses the default
console.log(fee(2000, 0.12)); // 240 — overrides itundefined. Pass 0 and you get 0, not the default — which is usually what you want, and occasionally a surprise.
05-objects inside FSWD-Unit2 · new files student.html · edit.html · record.html · average.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Servername2, roll2, city2, marks2. Then a third.{ } for an object, [ ] for an array. Two different brackets, two different shapes of container.label: value. A colon between them, a comma at the end — except the last, where the comma is optional.student.name reaches into the drawer. The drawer name, a dot, then the compartment label. Read it as “the name of the student”.user.city = "Hyderabad"; adds a compartment. It did not exist a line earlier. No declaration, no announcement — assign to a label that is not there and it appears.user.age = 22; changes one. Identical syntax. JavaScript works out which you meant by whether the label already exists.delete user.name; removes one. The compartment is gone, not emptied — asking for user.name now gives undefined.JSON.stringify(user) turns the whole drawer into readable text so you can see it in one go — handy for checking your work. "city" in user asks whether a label exists and answers true or false.Object.keys(user) lists the labels. Useful when you want to walk through an object without knowing in advance what is in it.user.city = "Hyderabad";
// or, when the label is in a variable:
user["city"] = "Hyderabad";console.log(user); to show the result, and mention that assigning to a label that does not exist creates it. Examiners are looking for that sentence.const, and we changed the object anyway. This is the point Module 3 made: const stops you pointing the box at a different object. It does not freeze what is inside. user = { } would fail; user.age = 22 is fine.name, and city,. When the label and the variable have the same name, write it once. It means exactly name: name.grades: [74, 81, 66]. Reach into it with student.grades[1] — the drawer, then the shelf, then the position. Counting starts at 0, so that gives 81.average() belongs to this student and is called with student.average().this means “the drawer I am in”. Inside average, this.grades is that student’s grades. Without this the method would not know whose marks to add up.this worth knowing now: write average() as a normal method, not as an arrow function. An arrow does not get its own this, so this.grades inside an arrow would not find the student. It is the one place in this unit where the old shape is the right one..split(",") turns "74, 81, 66" into three pieces of text — it cuts a string wherever it finds the character you name. Module 7 covers it properly; for now, take it as the tool that turns one string into a list..map(Number) turns each piece into a real number. It runs Number over every item and hands back a new list. Module 6 covers it properly. Without it you would be adding text together and getting "748166" rather than 221.average takes the whole student rather than a loose list. That is the habit the question is testing: pass one thing, not three..toFixed(1) rounds a number to one decimal place, so you get 73.7 rather than 73.66666666666667.Number(...).split(",").map(Number)"748166"title, author and copies. Add a method issue() that reduces the copies by one and reports how many are left — refusing when there are none.return is the important bit. Check the impossible case first and leave; then the rest of the method can assume things are fine. It reads better than wrapping everything in an else, and it is a habit worth building now.
const a = { marks: 74 };
const b = a;
b.marks = 90;
console.log(a.marks);const b = a did not make a second drawer. It made a second label on the same drawer. Change it through b and a shows the change, because there was only ever one object.const b = { ...a }; — the three dots spread the contents into a new drawer.student.average and student.average() — what is the difference, and what does each give you?student.average hands back the function itself — printing it shows the source code. student.average() runs it and hands back the answer.innerHTML = student.average, which puts the function's source text on the page. If your page shows something starting with function or containing =>, you forgot the brackets.
06-arrays inside FSWD-Unit2 · new files shelf.html · change.html · sort.html · typo.html · walk.html · filter.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server["Swift", "Nexon"] — items separated by commas.cars[0] is Swift. This trips up everybody at first, and it is the same in Java, so you have met it before..length counts the items — 4 here. So the last one is always at length - 1, which is 3.undefined, not an error. JavaScript shrugs. In Java that same line would throw ArrayIndexOutOfBoundsException and stop the program.const cars = ["Swift", "Nexon", "Creta", "Thar"];
console.log(cars.length); // 4cars[0] or the length. A bare declaration with nothing done to it often gets one mark.push(x) adds · pop() removes and hands the item back. Fast, and what you will use most.unshift(x) adds · shift() removes. Everything after it has to shuffle along, so use these only when order demands it.push and unshift add. Push at the back of the queue, unshift at the front.pop and shift remove and hand the item back. That is why line 16 can catch it in last. If you do not want it, ignore the return.splice(1, 0, "Kavya") reads as: at position 1, remove 0 items, insert Kavya. Change the middle number to remove instead. It is the one that does everything, and the one people look up every time.const and this all still works — same rule as objects: const stops reassignment, not modification.sort() on its own treats everything as text. It compares "10" and "2" the way a dictionary would — character by character. "1" comes before "2", so 10 lands before 2. It is not broken; it is doing exactly what it was told, which is the least helpful kind of wrong.sort a rule and it obeys you. (a, b) => a - b means: hand me two, and I will tell you which goes first.a - b puts small numbers first — ascending. Swap it to b - a and you get descending.[...nums] makes a copy first. Without it, sort would rearrange the original — and the three examples would interfere with each other. Same three dots you met in Module 5.let nums = [5, 10, 2, 8];
nums.sort((a, b) => b - a);
console.log(nums); // [10, 8, 5, 2]nums.sort().reverse() looks clever and gives [8, 5, 2, 10] — wrong, for the reason above. Say in one line why the comparator is needed and the second mark is safe.srot, so there is nothing to call — correct it to sort and the red line goes away. Lines 8 to 12 only copy the console’s message onto the page so you can read it here.sort() sorts like a dictionary, not like a calculator.undefined — nothing.map().filter().join()[79, 86, 71]marks.filter(m => m >= 50)marks.find(m => m >= 80)marks.reduce((a, b) => a + b, 0)filter narrows it to two items, sort orders them by price, map turns each into a line of HTML, join("") glues those lines into one string.map is useful and forEach is not — you could not chain anything after a forEach.join("") with empty quotes means no separator. Leave it out entirely and you get commas between your list items, which shows up on the page.[74, 81, 66, 90, 45]: the passes (50 and above), the highest, the first mark of 80 or more, and the average. One line each.Math.max(...marks) uses the three dots again — Math.max wants separate numbers, not a list, and the dots spread the list into separate arguments. Math.max(marks) without them gives NaN.
[1, 10, 2, 20, 3], and what is the fix?
const n = [10, 2, 1, 20, 3];
console.log(n.sort());sort() compares them as text. It turns each number into a string and orders them the way a dictionary would — "1", then "10", then "2". Character by character, "1" beats "2", so 10 lands before 2.n.sort((a, b) => a - b).sort has to work on names and dates too, so text order is the only rule that fits everything. Another decision from 1995 you cannot change now.
forEach and map would you choose, and why?map is cleaner.map: cars.map(c => `<li>${c}</li>`).join("") builds the whole string in one expression and hands it to you.forEach you need a variable outside the loop to collect into: let html = ""; cars.forEach(c => html += ...);. Three lines instead of one, and an extra let to keep track of.07-strings inside FSWD-Unit2 · new files row.html · methods.html · compare.html · names.html · shout.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Servername[0] is the first character, name.length - 1 the last. You already know this shape from Module 6."Asha Reddy" is ten long, not nine. This matters enormously when you are counting what somebody typed.s, which is why the last line can still print the original with its spaces intact.split(" ") is the odd one out. It hands back an array, not a string — three items here. Everything else on this list gives you text or true/false.trim()toUpperCase()slice(a, b)indexOf(x)split(x)replace(a, b)includes(x)true or falsestartsWith(x)true or falseindexOf returns −1 when it finds nothing — not 0, not false. And replace only swaps the first match; to change all of them you need replaceAll.trim() first, every single time. A user who types a trailing space has typed something different from what they think. Almost every "my validation rejects a correct answer" complaint comes down to a space nobody can see.charAt(i) vs s[i]s.charAt(0) s[0]"A"; past the end, "" against undefinedslice(a, b) vs substring(a, b)s.slice(-5) s.substring(-5)slice counts from the end ("Reddy"), substring treats it as 0 ("Asha Reddy")concat vs + vs backtickss.concat("!") s + "!" `${s}!`"Asha Reddy!" — write backticksindexOf(x)s.indexOf("d") s.indexOf("z")7, and −1 when it is missinglastIndexOf(x)s.lastIndexOf("d")8 — the search starts from the endrepeat(n)"-".repeat(10)"----------"s is "Asha Reddy"fullName trims both halves before joining. Without that, a stray space in the first-name box gives you "asha reddy" with a double gap.salutation splits on the space and takes piece 0. "Dr. Kanetkar" becomes ["Dr.", "Kanetkar"], and position 0 is the candidate title.titles.includes(first) — the array method from Module 6 doing string work. This is better than checking for a full stop, because "A. Kanetkar" would fool that.? : is a compact if-else. test ? valueIfTrue : valueIfFalse. It fits in a return line, which is the only reason to prefer it. A normal if earns identical marks.<br> inside the backticks on line 43. Because we are setting innerHTML, the browser reads that as a real line break. A \n would do nothing here — that only works inside a <pre>, which is what the earlier examples used.hello123 in the frame./[0-9]/.test(text) asks "is there any digit in here?" The slashes make a pattern, and [0-9] means any single digit. Module 9 teaches patterns properly — for now, read it as a question that answers true or false.BAD.some(c => text.includes(c)) asks "is any of these three in here?" some is an array method — true if at least one item passes. A cousin of filter from Module 6.return on line 36 stops there. Show the error, clear the old result, leave. Without it the code would carry on and shout the bad text anyway..value.trim()hasDigit, hasSymbolif (hasDigit || hasSymbol)|| means or — either one is enough to refusereturn;err.innerHTML = ""hello123"1602-24-733-001@vce.ac.in", pull out the roll number and the domain separately. Do it two ways.slice needs you to find the @ first; split does both jobs in one call and hands back both halves. For a single separator, split is almost always the shorter answer — but slice is what you need when the cut point is a count rather than a character.
false, and what are two ways to fix it?
const typed = " ASHA ";
console.log(typed === "Asha");typed.trim().toLowerCase() === "asha"typed.trim().toLowerCase().includes("asha")name.toUpperCase(); on its own line and wonders why the name is still lower case. Explain.toUpperCase() did its work perfectly — it made a capitalised copy and handed it back. Nobody caught it, so it was thrown away.name = name.toUpperCase(); — or store it somewhere new. This applies to every string method: trim, slice, replace, all of them.marks.push(5) genuinely changes the array. name.toUpperCase() cannot change the string. That difference catches everybody once.
onclick you wrote was an event handler. Here is what was actually going on.08-events inside FSWD-Unit2 · new files bell.html · three.html · typo.html · watch.html · form.html · target.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Servercount lives outside the handler. That is why it remembers. If it were declared inside, it would be created fresh at 0 on every single click.let count = 0addEventListener(...)console.log(...) on line 23count lives outside<button onclick="say()">btn.onclick = fnbtn.addEventListener("click", fn)btn.onclick = fn is an ordinary assignment into a box, so writing it twice throws the first away — silently. If two people add a handler to the same button, one of them loses. addEventListener stacks them instead, which is the entire reason it exists.onclick = because it is shorter under exam pressure and marks the same. Use addEventListener in the lab, where two handlers on one element eventually happens.btn.onclick = say() with brackets and you have called say immediately and stored whatever it returned — usually undefined. Then nothing happens when you click. No brackets when handing a function over; brackets only when you want it to run now. Same lesson as student.average in Module 5.getElementById("buton") finds no element and hands back null, and null has no addEventListener — that is all the red line is saying. Match the spelling to the HTML and the bell works. Lines 9 to 13 only copy the console’s message onto the page so you can read it here.clickinputblurchangesubmitloadinput and keyup both fire per keywindow, not document. A page finishing loading happens to the tab, not to any element inside it. Module 12 covers the window object properly.blur is the one the papers name without naming. Whenever a question says “immediately after the control is moved from the last name” or “when the user leaves the field”, that is blur. Module 9 answers exactly that question.clickbtn.addEventListener("click", ring)dblclickphoto.addEventListener("dblclick", zoom)inputbox.addEventListener("input", check)changecourse.addEventListener("change", price)submitform.addEventListener("submit", send)focus / blurlast.addEventListener("blur", join)keydown / keyupbox.addEventListener("keyup", count)mouseover / mouseoutcard.addEventListener("mouseover", glow)loadwindow.addEventListener("load", start)input and keyup arrive for every keyevent. The browser hands it in automatically, every time. It carries details about what just happened — which key, which element, where the mouse was.event.preventDefault() cancels what the browser would normally do. For a form, that is sending it away and reloading. Take that line out and the page blanks the instant you press Send.return, or clear the error and do the job.submit is on the form, not the button. That way pressing Enter in the text box works too — which is what people actually do.preventDefault(), every time. It is the single most common bug in form-validation answers.event.targetevent.target says which one started it.div, instead of three on the buttons. The click lands on a button, rises to the div, and the handler runs there.event.target is where the click started — the button itself — and textContent reads its label.div, not a BUTTON.event.stopPropagation() stops the rise. Called inside a handler, it keeps that click from reaching the boxes further out.change?box.addEventListener("input", () => {
out.innerHTML = box.value;
});input fires on every keystroke. change on a text box only fires when you leave it, so nothing would happen while typing. On a dropdown they behave much the same; on a text box they are very different.
btn.onclick = a and the other btn.onclick = b. What happens, and how should they have done it?b runs. The second assignment overwrote the first, silently — no error, no warning. a is gone.btn.addEventListener("click", a) and btn.addEventListener("click", b). Listeners stack; both run, in the order they were added.event.preventDefault().event into the handler and call event.preventDefault() as the first line, or move the handler to the button’s click instead of the form’s submit. The first is better — it keeps Enter working.
09-validation inside FSWD-Unit2 · new files blank.html · password.html · fullname.html · pattern.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server@, a date of birth in the future. Once that reaches the server it is somebody else’s problem, and usually a permanent one..value gets what was typed. .trim() removes the invisible spaces — without it, a single space would count as a name.who === "". In the next chunks it will be a comparison, a length, a pattern — but always one clear question.return. The return is what stops the good path running anyway.<p class="error">. One shared message box cannot tell the user which field is wrong, and the papers mark you down for that.min-height: 16px on the error line. Without it the page jumps up and down as messages appear and vanish. A small thing that makes a form feel finished.show helper does two jobs. It writes the message, and it hands back true when the message is empty — meaning that field passed. Writing and answering in one call keeps the checks short.? : reads as a list of rules. Empty? that message. Too short? that one. Otherwise empty string, meaning fine. Rules are tested in order, and the first one that matches wins.okNm && okAg — both must pass. && means and. Note both checks run before this line, so every wrong field shows its message at once, not one at a time.min-heightshow(id, msg).trim()Number(ag)"9" < "17" is false — the check silently misfiresifif (nm === "") { show(...); return; } for each field means the user fixes one error, presses Submit, and is told about the next one. Three fields, three rounds. Check them all, then decide.Number(ag) < 17, not ag < 17. A text box hands back text, and comparing text to a number gives answers you did not expect — "9" < 17 happens to be true, but "9" < "17" is false. Convert first, every time. Module 13 explains why.if (p1 !== p2) is half an answer..trim() here, and that is deliberate. A space is a perfectly legal password character. Trimming would quietly change what the user chose — the one place in this unit where trimming is wrong.type="password" hides the characters as dots. It changes nothing about how you read the value; it only stops somebody behind them reading the screen.p1 !== p2 uses three characters, not two. !== is “not exactly equal”. Module 13 explains why the two-character version would be a bad idea here.abc twicevasavi2026 then vasavi2025blur. No button anywhere in this question — the work happens when focus leaves the field. That is the mark most answers lose.blur fires when focus leaves a field — pressing Tab, or clicking elsewhere. Module 8 showed it in the event log; this is what it is for.readonly on the full-name box. The user should not type there; only the script fills it. It still looks like a field and its value can still be read and submitted./^[A-Za-z]+$/ is a pattern, and the next chunk takes it apart properly. For now: ^ means start, $ means end, [A-Za-z] means one letter, + means one or more. Together: letters from beginning to end, nothing else.checkOne is written once and used twice. Two fields with the same rule should not mean two copies of the rule — that is what a function is for, and markers notice.blur handler, not only the last name. The question only mentions the last name, but a user who fixes the first name and tabs away expects the full name to update. Handling both is more correct and costs one line..test(value) asks “does this fit?” and answers true or false.^$[A-Za-z][0-9]{6} {2,5}+ *Asha1^ and $ and the rule stops being a rule. /[0-9]{6}/ without them says “six digits somewhere inside”, so abc123456xyz passes. With them it says “six digits and nothing else”. Almost every wrong pattern answer is a missing anchor.for (const name in RULES) walks the labels. The in loop hands you each key in turn — the same Object.keys idea from Module 5, in loop form.test() is called once at the end, on line 33. Without that the panel would be blank until the first keystroke, which looks broken.Asha passes letters-only. 500031 passes digits-only and exactly-six. Asha1 fails letters-only but passes has-a-digit and starts-with-a-letter.1602-24-733-001 — four digits, two, three, three, joined by hyphens.^ start, [0-9]{4} four digits, - a literal hyphen, [0-9]{2} two digits, and so on to $. A hyphen outside square brackets means an actual hyphen — no escaping needed.
/[0-9]{5}/ and it accepts my pin is 500031 ok. Why, and what is the fix?/^[0-9]{5}$/. Now it means “from the very start to the very end, exactly five digits and nothing else”.if (a bad) { show; return; } if (b bad) { show; return; } — the first return stops everything, so the user never learns about field two until field one is fixed.const okA = show("eA", ruleA());
const okB = show("eB", ruleB());
if (okA && okB) { /* accept */ }10-registration inside FSWD-Unit2 · one file register.html, grown across all five chunks · Ctrl+N then Ctrl+S, name it with .html · keep it open — every chunk adds to the same file@yahoo.com and nothing after it.^[A-Za-z] — the very first character must be a letter. That is “must start with an alphabet”.[A-Za-z0-9]{1,4} — then one to four more, letters or digits. One plus four gives the range 2 to 5 the question asks for.{1,4} to {2,5} — and state which reading you used.@yahoo\.com$ — then exactly that text, and $ means nothing may follow.. in a pattern means any character, so yahooXcom would pass. \. means a real full stop.<a> is new: its href is rewritten by the script every time the address changes.1602- and the 7 are fixed in the question, so they are typed exactly; only the Y positions become [0-9]. That gives /^1602-[0-9]{2}-7[0-9]{2}-[0-9]{3}@vce\.ac\.in$/. 1602-24-733-015@vce.ac.in passes. 9999-24-133-001@vce.ac.in is refused — a pattern of four digits, two, three and three would have let it through.mailto: in an href opens the mail program with the address already filled in. It is not JavaScript sending an email — nothing in a browser can do that. It hands the job to Outlook or Gmail.?subject= after the address pre-fills the subject line. Optional, but it is the sort of detail that turns three marks into four.# when the address is wrong — so a broken address can never be mailed.mailto: address and the operating system hands it to whatever mail program is installed. Actually sending mail needs a server — which is Unit 4./^5[0-9]{4}$/ reads as: starts with 5, then four more digits. One plus four is five in total. Writing [0-9]{5} and checking the first character separately works too and earns the same marks./^[0-9]{4}-[0-9]{2}-[0-9]{2}$/ only proves it looks like a date. 9999-99-99 passes it.new Date(text) turns the text into a real date the browser can do arithmetic with. new Date() with nothing inside means today.14-06-20052010-01-0140003150003500031^ and $ are not decoration.* means zero or more, + means one or more. Here * is right: _a is a legal username under the question’s wording, with nothing in the middle at all._asha24 and it is rejected. Underscore, correct. Middle, correct. But it ends in a digit, and the question said it must end with an alphabet./^_[A-Za-z0-9]+[A-Za-z]$/ with a + instead of a *. It rejects _a, because + demands at least one character in the middle before the final letter. The question never said that. One character, one mark.NEEDED and add two more boxes.class="course". That is the handle for finding them all at once. Ids are for one element; a class is for a group.querySelectorAll(".course") finds all of them. The dot means “by class”, the same dot you met in the stylesheet in Module 1. Module 11 covers this properly — here, read it as “give me every element with that class”.b.checked is true or false. Not the value, not the text — only whether it is ticked. Reading .value on an unticked box still gives you its value, which is why counting must use .checked.[...boxes] turns the result into a real array so filter works on it. querySelectorAll hands back something array-like that does not have every array method. The three dots from Module 5 solve it.<label> lines and change NEEDED to 4. Nothing else moves. Say that in the exam — showing you noticed the two questions are the same question is worth more than writing it out twice.const NEEDED = 4; // was 2
<label><input type="checkbox" class="course" value="C++"> C++</label><br>
<label><input type="checkbox" class="course" value="Go"> Go</label>/^5[0-9]{5}$/ and the valid value 50003 is rejected. What went wrong?{5} asks for five more digits after the 5 — six in total. 50003 has only four after the 5, so it fails.{4}: /^5[0-9]{4}$/.new Date() and a subtraction. And it cannot compare two values, so a password match needs p1 === p2.11-dom inside FSWD-Unit2 · new files tree.html · find.html · change.html · boxes.html · missing.html · calc.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live ServergetElementById. Now it gets its name and its full set of tools.document is the whole tree. Every DOM instruction starts there. It is handed to you by the browser — you never make one.document directly rather than inside the body.getElementByIdnullidgetElementsByClassNamegetElementsByTagNamequerySelectornullquerySelectorAllquerySelectorAll(".note")getElementsByClassNamequerySelector(".note") uses a class, querySelector("#head") an id, querySelector("p") a tag. Anything you can write in a stylesheet you can write here — which is why these two replaced the others.null, not an error. Line 26 proves it. The error only comes on the next line, when you try to use that nothing — which is the message Module 2 taught you to read.getElementsByClassName grows by itself if you add a matching element later. querySelectorAll hands you a snapshot that does not. The snapshot is easier to reason about, which is another reason to prefer it..length and you can index it, but not every array method works. [...boxes] turns it into a real one — the three dots again.getElementById when you named it, querySelectorAll when you want a group. The other three appear in your papers, so recognise them — but you never need to write them.<b>bold</b>..innerHTML.textContent.valueinnerHTML does nothing to an <input>.style.color.classList.addstyle, yellow background from the classinnerHTML means any tags they typed are obeyed — including a <script>. Use textContent for anything that came from a person, and innerHTML only for text you wrote yourself. It costs nothing and it is the habit real work depends on.innerHTML on an input does nothing at all — no error, no change. An <input> has no inside; its text lives in value. If a box refuses to fill from your script, this is almost always why.classList.add, .remove, .toggle. Three methods, and toggle is the useful one — it adds the class if it is missing and removes it if it is there, which is one line for a show/hide button.background-color; JavaScript says style.backgroundColor. A hyphen would be read as a minus sign.createElement makes an element that is not on the page. It exists in memory, nothing more. You can set it up as much as you like before anyone sees it.appendChild puts it into the tree, as the last child of whatever you called it on. That is the moment it appears.holder.querySelectorAll("input") asks how many are actually there. Keeping a separate counter works until Remove is pressed and the two disagree..remove() takes an element out of the tree. Called on the element itself — no need to find its parent first.<div id="holder"> is deliberate. New boxes need somewhere to go. Appending to document.body would work but would put them after the error message, which looks wrong.getElementById("lits") found nothing and handed back null, and null has no appendChild. Fix the id to list and Item 1 appears. Lines 9 to 13 only copy the console’s message onto the page so you can read it here.total and pending live outside the handler. Same reason the doorbell count did in Module 8 — declared inside, they would reset to their starting values on every press.pending holds which button was pressed last time. That is the trick the question is really asking about. When you press +, the page cannot add anything yet — it has one number. It stores the sign and waits.pending === null means this is the first press. Nothing to add to, so the total becomes the number typed.box.value = total writes the answer back into the same box — which is what “generate the result in the same text box” means. Then the next number typed replaces it.isNaN(Number(typed)) catches anything that is not a number. Number("abc") gives NaN, and isNaN asks whether it did. Module 13 explains why NaN needs its own test.<ul> each time it is pressed, numbered “Item 1”, “Item 2” and so on. Write the handler.document.getElementById("go").onclick = () => {
const list = document.getElementById("list");
const n = list.querySelectorAll("li").length + 1;
const li = document.createElement("li");
li.textContent = "Item " + n;
list.appendChild(li);
};querySelectorAll("li").length — so removing an item never leaves the numbering wrong.
const p = document.createElement("p");
p.textContent = "Hello";document.body.appendChild(p); or append it to a specific holder.textContent instead of innerHTML, and what is the risk of getting it wrong?textContent for anything a user typed. Use innerHTML only when you wrote the text yourself and it genuinely contains tags you want obeyed.innerHTML obeys tags. Put a user’s input through it and whatever tags they typed become part of your page — a <script> among them. The name for this is cross-site scripting, and it is one of the oldest problems on the web.textContent. It costs nothing and removes the question entirely.
12-window inside FSWD-Unit2 · new files room.html · dialogs.html · glance.html · onload.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Serverdocument itself. It is handed to you already made, and it is the outermost thing you can reach.window.document === document is true. They are one object with two names. Everything on window can be written without the window. in front — which is why you have never had to type it.alert(...) is really window.alert(...). Same for setTimeout, location, and every dialog in the next chunk.innerWidth and innerHeight are the visible area in pixels. Resize the browser and they change. This is how a page reacts to a phone without CSS.location.href is the address bar. Read it to see where you are; assign to it and the browser navigates. It is the one property that does something when you set it.true or false.null if they cancelled.setTimeout is the same but runs once.prompt can give you three different things: the text they typed, an empty string if they pressed OK with an empty box, or null if they cancelled. Checking only for empty misses the cancel.prompt pre-fills the box. prompt("Your name?", "Asha") — small, and it makes a demo much smoother.setInterval hands back a ticket. Line 40 keeps it in ticker. Without that ticket you cannot ever stop it — clearInterval needs it.setInterval(fn, 1000) is once a second. Write 1 instead of 1000 and it runs a thousand times a second, which will freeze the tab. If your page locks up after adding a timer, check that number first.alert(msg)undefinedconfirm(msg)true / falseif (yes) { ... }prompt(msg, start)nullif (name === null) for cancelsetTimeout(fn, ms)clearTimeout(ticket)setInterval(fn, ms)clearInterval(ticket)location.hreflocation.href → "http://127.0.0.1:5500/glance.html"location.reload()history.back()navigator.languagenavigator.userAgent gives its name and versionnavigator.language → "en-IN"screen.widthscreen.width → 1366window.innerWidthwindow.open() / close()open("result.html") → a new tab. The frames on this page are not allowed to open one; Live Server is.scrollTo(0, 0)window. location.href is short for window.location.href, the same way alert was.about:srcdoc, not an address. The preview has no address of its own. Open the file with Live Server and the same line prints http://127.0.0.1:5500/....window is the top-level object for the browser tab; document, the dialogs and the timers all belong to it.location (the address), history, navigator (the browser), screen, innerWidth and innerHeight.alert, confirm, prompt, setTimeout, setInterval, open, close, scrollTo.alert(location.href); shows the address; setTimeout(() => alert("hi"), 1000); says hi after one second.window.onload is an event handler, exactly like the button handlers in Module 8. It installs instantly and runs later — when the page has finished building.onload when you cannot move the script — which in this unit is almost never.window object and the document object, with one example of something each can do that the other cannot.window is the browser tab; document is the page inside it. document is a property of window, which is why window.document === document.innerWidth, read or change the address with location, show a dialog, or set a timer.getElementById, createElement, innerHTML.setInterval. A user presses it four times. What happens, and how do you prevent it?clearInterval only stops the last one because each earlier ticket was overwritten. The other three keep running with no way to reach them.if (ticker !== null) return;clearInterval(ticker); as the first line of the handler. Either works; the guard is clearer about the intent.
const a = prompt("Name?"); // user presses Cancel
const b = prompt("Name?"); // user presses OK with an empty box
const c = prompt("Name?"); // user types Ashanull — they refused. b is "" — an empty string; they agreed but gave nothing. c is "Asha".if (!name) treats a and b the same, which is often what you want. But if you need to tell “cancelled” apart from “left it blank” — and a real form usually does — you must test name === null separately.null and "" are falsy, which is exactly why !name cannot tell them apart.
13-quirks inside FSWD-Unit2 · new files falsy.html · equals.html · hoist.html · with.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Servertrue when JavaScript needs a yes or no — inside an if, for instance. Almost everything is truthy.false. Learning these six is easier than learning the infinite list of truthy ones."0" is truthy. It is a string with a character in it. Only the number zero is falsy.[] and {} are truthy. An empty list is still a list. To ask whether it has anything in it, use .length." " is not "". This is exactly why every validation in Modules 9 and 10 calls .trim() before testing.NaN means “not a number” and comes from arithmetic that failed — Number("abc"), for instance. It is the only falsy value that is technically of type number.=== throughout this course without being told why the third character is there. Here it is: == converts before comparing, and the conversions are not what anyone would guess.true false.if ([]) — an empty array is truthy, so the if branch runs and the word printed is "true". Second: [] === true — an object against a boolean, different types, so false.if and as not-equal-to-true by ===. Both are correct, and noticing that is the question.=====1 and "1"0 and false"" and falsenull and undefined[] and false"", then 0NaN and NaNNaN is not equal to itself. Not with two equals, not with three. It is the one value for which x === x is false. That is why Module 11's calculator used isNaN(...) — there is nothing you could usefully compare it against.var is broken and pointed here. This is the second half of why. Before your code runs, the browser reads the whole file and files some things away in advance — and what it files, and how, differs by keyword.var hoists the name but not the value. So line 12 finds early, sees undefined, and prints it. No error. A typo can look exactly like this.let and const hoist the name but keep it locked until execution reaches their line. Touching it before that throws a ReferenceError. The gap has a name — the temporal dead zone — and it exists so mistakes are noisy.var gives you undefined and says nothing.let stops you. That is the whole improvement.1.with (obj) tells JavaScript: inside this block, look in obj first for any name you meet. obj has an x, so x inside the block means 10. But obj has no y — so the search moves outward and finds the ordinary y, which is 1.x. The question shows you x being shadowed to make you expect something clever from y. Nothing clever happens to y at all.with is forbidden in strict mode, and has been discouraged for twenty years. Adding "use strict"; to the top of a file makes this exact program refuse to run. Never write it. Know it only because your paper asks about it — which it did, in December 2024.typeof null"object"typeof []"object"Array.isArray() insteadtypeof NaN"number"0.1 + 0.20.30000000000000004typeof (() => 1)"function"typeof gives them their own label: "function"if ("0") console.log("A");
if (0 == "") console.log("B");
if ([] == false) console.log("C");
if ([] === false) console.log("D");"0" is a string with a character in it, so truthy.== turns both into 0."", then 0; false becomes 0.=== compares types first, and an object is not a boolean.==. Use === and none of them happen.
undefined rather than throwing, and what would let have done?
console.log(total);
var total = 100;var hoists the name but not the value. Before the code runs, the browser files away “there is a variable called total” and gives it undefined. Line 1 finds it and prints that.let it throws — ReferenceError: Cannot access 'total' before initialization. The name is reserved but locked until its own line.var looks exactly like this and gives you undefined with no clue where it came from.
if (score = 0) and their code always takes that branch. Two things are wrong — name both.= assigns, it does not compare. That line sets score to 0 and then asks whether 0 is truthy.if (score === 0). And this is a good argument for const wherever possible — assigning to a const by accident throws immediately.
14-bridge inside FSWD-Unit2 · new files classes.html · promise.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Serverconstructor runs once, when you say new. Its job is to fill in what makes this object different from the others.this means “the object being built right now”. Inside asha.report(), this.name is Asha. Inside ravi.report(), the same line gives Ravi.http://, and the tag must be <script type="module">. Open the file directly and you get “Cross origin requests are only supported for protocol schemes: http…” — which sounds like a security problem and is really the wrong way of opening it. Use Live Server and it works. There is no live frame here for the same reason: the preview is not served from a real address.await means “hold here until it does”.setTimeout here is standing in for a real server. Asking a server for data takes time; this pretends to take 1.5 seconds so you can see the waiting.await pauses that function only. The rest of the page keeps working — buttons still respond, nothing freezes. That is the whole difference from alert, which stops everything.async is required before you may write await. One marks the function as one that waits; the other does the waiting.let, const, arrow functions, template strings and classes.const for a value that will not be reassigned, let when it will. Never var — it leaks out of its block and hoists as undefined.const stops reassignment, not modification.push and pop at the end; map makes a new list, filter a shorter one, reduce a single value. sort() alone compares as text.trim() first, always.addEventListener stacks; onclick = replaces. On a form, event.preventDefault() stops the page reloading.document is the page; window is the tab it sits in. Find with getElementById or querySelectorAll; change with innerHTML, textContent, value, classList. Create with createElement then appendChild.let / constconst price = 60; let qty = 3;const square = n => n * n;`${qty} dosas`(amount, rate = 0.05) => amount * rate(...marks) => marks.length [...nums]const { name, city } = student;class Student { constructor(name) { this.name = name; } }export const fee = 60; import { fee } from "./fee.js";const by default, let when reassignedvar leaks and hoists as undefined===, never ==.trim() before testing anything typedNumber(...) before comparing"9" < "17" is falsetextContent for anything a person typedinnerHTML obeys tags they may have typed[], "0" and " " are truthy.false, 0, "", null, undefined, NaN.[] is an object, "0" is a string with a character in it, and " " is a string with a space in it./^7[0-9]{3}$/{4} after the 7 would demand five./7[0-9]{3}/ means “a 7 followed by three digits somewhere inside”, so xx7123yy passes.const v = document.getElementById("box").value.trim(); // read
const msg = v === "" ? "Required"
: !RULE.test(v) ? "Wrong format" : ""; // test
document.getElementById("err").innerHTML = msg; // report
if (msg === "") { /* accept */ } // decideRULE. Learn the skeleton and the rule is the only thing left to work out in the exam hall.
p1 === p2.new Date() and a subtraction, with the month-and-day check.querySelectorAll then filter(b => b.checked).15-selftest inside FSWD-Unit2
· one file per question you answer in code —
q1.html through q8.html
· Ctrl+N then Ctrl+S,
name it with .html
· questions 2 and 3 are written answers — paper is fineconst and the other let.function A(arg) {
if (arg) console.log("true", arg === true);
else console.log("false", arg === false);
}
A("");console.log(count);
var count = 5;
console.log(typeof null, [] == false);const n = [12, 3, 25, 8]; write one line each to get the values above 10, the total, and the list sorted smallest first. Say what n.sort() alone would give." Ms. Kavya Rao ", produce the salutation and the last name. Then say why name.toUpperCase(); on its own line changes nothing.<ul> each time a button is pressed, numbered Item 1, Item 2 and so on, to a maximum of four, with an error message beyond that.price never changes, so const. qty is reassigned on line 9, so it must be let — assigning to a const throws TypeError: Assignment to constant variable. Say that sentence and the second mark is safe.A("")false false"" is one of the six falsy values, so the if fails and the else runs. The word printed is "false"."" === false? A string against a boolean. Different types, so === says false without looking further.else ran because "" is falsy, which makes it feel like "" === false ought to be true. It is not. Being falsy is not the same as being false. Only false itself is === false — the other five falsy values are all something else.A([]) gives true false because an empty array is truthy. Same function, opposite first word, and false both times for the second.undefined
object trueundefined. var hoists the name but not the value, so count exists and holds undefined. With let this would throw instead.typeof null is "object" — a bug from 1995 that can never be fixed because too much code depends on it.[] == false is true — loose equality turns the array into "", then into 0, and false into 0. With === it would be false.sort() answer. A bare n.sort() gives [12, 25, 3, 8] — it compares as text, so "12" comes before "3" the way a dictionary would order them. The comparator (a, b) => a - b is what makes it numeric.[...n] copies first so the original is left alone.trim() first, or the leading spaces make split(" ") hand you an empty first piece.name.toUpperCase(); on its own line changes nothing because strings cannot be edited in place. The method made a capitalised copy and handed it back, and nobody caught it, so it was thrown away. You need name = name.toUpperCase();.var hoists as undefined — that is the entire syllabus for Q4.5 then five more — {5}, not {6}. Off-by-one in a quantifier is the most common mistake in this question..trim() and the empty check are each worth a mark on their own in most marking schemes.input, not change. “As the user types” means every keystroke. change on a text box only fires when focus leaves it, so nothing would happen while typing — this is the mark the question is testing.Number(...) on both. Without it you get "7" + "5" = "75", which is the classic wrong answer.add() once at the start so the paragraph is not blank before the first keystroke.createElement, set it up, appendChild. Miss the third and nothing appears — and nothing complains.list.querySelectorAll("li").length stays right even if items are removed later. A separate counter drifts.isNaN does not catch an empty box. Number("") is 0, not NaN, so an empty box counts as zero. Add a v === "" check if that should be refused.items.length + 1 reads the list as it stands, so it stays correct however the list was reached.{6} instead of {5} after the leading 5.trim() and an empty checkalert instead — the question said below the boxcity to an existing user object@ # $map() against forEach(); filter objects by price, sort, displayA([]) with ===1602-YY-7YY-YYY@vce.ac.in, mail on link clickblur; alphabets only, not blank+ and −with(obj) { alert(y) }let and const in ES6change rather than input, that is the whole question missed. Not a small slip: the phrase “as the user types” is the examiner pointing at input.querySelectorAll(...).length cannot drift. A counter you maintain yourself can.