This is an example of my database

I am making a website using nodejs, MongoDB, and pug. I have displayed this data in a pug form with the data in the select boxes. Like this but in pug using for loops and all the data-
<!DOCTYPE html>
<html>
<body>
<form>
<select name="Type">
<option value="Electronic">Electronic</option>
</select>
<select name="Brands">
<option value="Apple">Apple</option>
<option value="Dell">Dell</option>
<option value="Samsung">Samsung</option>
</select>
<select name="Products">
<option value="Macbook Pro">Macbook Pro</option>
<option value="Inspioren">Inspioren</option>
<option value="Galaxy S20">Galaxy S20</option>
</select>
</form>
</body>
</html>
What I want to do is, change the select box options based on what the user has selected in other select options.
For example:- If a user selects "Type: "Electronic", and "Brand: Apple",I want to display only Apple products as the options.
Or if a user selects "Type: "Electronic" it should automaticly display brands list in the select box for brands.
The data will be added from the database (it will not be hardcodded).
One possibility could be to modify your Pug view to include select tag id's and leave the downstream selects blank and then add a script at the end of your view to add event listeners and do some DOM manipulation using JQuery or just javascript after the view is loaded. The event handlers would then allow you to conditionally fill in your next select tag based on whatever you choose in the current tag.
Something along the lines of:
script.
document.addEventListener("DOMContentLoaded",
function(e) {
const typeSelect = document.getElementById('type')
typeSelect.onchange = function(e) {
const brandSelect = document.getElementById('brand')
if (typeSelect.options[typeSelect.selectedIndex].text === 'Apple') {
['MacBook Pro', 'MacBook Air', 'MacBook Mini'].forEach(function(product) {
let newOption = createElement('option')
newOption.textContent = product
brandSelect.appendChild(newOption
}
else if ( // etc... ) {}
else {
// functionality to clear out the downstream select tags.
}
}
const brandSelect = document.getElementById('brand')
brandSelect.onchange = // etc, etc....
})
I am answering my own question here. What I did was add the onchange function on the Type select box. And created a script inside my file, with the following code-
function change() {
var Type_name = document.getElementById("type").value;
var Brand= document.getElementById('brands');
var Product = document.getElementById('products');
Brand.options.length = 0;
Product.options.length = 0;
var DefaultBrand = new Option("Brand", "Null");
var DefaultProduct = new Option ("Product", "Null");
Brand.add(DefaultBrand, undefined);
Product.add(DefaultProduct, undefined);
var product_master = !{JSON.stringify(product_names)};
for (const brands of product_master) {
if (brands.Type == Type_name){
const BrandOption = new Option(brands.Brand, brands.Brand);
Brand.add(BrandOption, undefined);
}
}
And another function similar to this to add products.
This worked for me. But if anyone wants to improve this code, I would appreciate the help.
Server side code, with some test data:
app.get("/avi", (req, res) => {
res.render("avi", { Types: [ "Electronic"], data:
[ { Type: "Electronic", Brand: "Apple", Products: [ "MacBook Pro", "MacBook Air", "Mac Mini"]},
{ Type: "Electronic", Brand: "Dell", Products: [ "Inspioren", "Latitude"]},
{ Type: "Electronic", Brand: "Samsung", Products: [ "Galaxy S20", "Galaxy S10"]}
]
});
});
You should include a Types list, otherwise your Pug script will have to go through the raw data to identify the number of unique Types.
avi.pug:
html
head
body
p Linked Dropdowns
form
p Type:
select#types(onchange="typeChanged()")
option(value="") Select Type
each item of Types
option(value=item)=item
p Brand:
select#brands(onchange="brandChanged()")
option(value="") Select Brand
p Product:
select#products()
option(value="") Select Product
script.
const data = JSON.parse(`!{JSON.stringify(data)}`);
const types = document.getElementById("types")
const brands = document.getElementById("brands")
const products = document.getElementById("products")
const typeChanged = () => {
clearBrands(); clearProducts();
if (types.selectedIndex!==0) {
const selectedType = types.options[types.selectedIndex].text;
data.forEach(d => {
if (d.Type===selectedType) {
const newBrand = document.createElement("option")
newBrand.value = newBrand.innerText = d.Brand;
brands.appendChild(newBrand);
}
});
}
}
const brandChanged = () => {
clearProducts();
if (brands.selectedIndex!==0) {
const selectedType = types.options[types.selectedIndex].text;
const selectedBrand = brands.options[brands.selectedIndex].text;
data.forEach(d => {
if (d.Type===selectedType && d.Brand===selectedBrand) {
d.Products.forEach(p => {
const newProd = document.createElement("option")
newProd.value = newProd.innerText = p;
products.appendChild(newProd);
});
}
})
}
}
const clearBrands = () => {
const item0 = brands.childNodes[0];
brands.textContent = "";
brands.appendChild(item0);
}
const clearProducts = () => {
const item0 = products.childNodes[0];
products.textContent = "";
products.appendChild(item0);
}
The data at the server is injected into the client side Javascript with:
const data = JSON.parse(`!{JSON.stringify(data)}`);
This method is not very robust. There will be problems if anywhere in the data there is a backtick ` character.