This commit is contained in:
Philippe Torrel
2026-07-23 14:56:15 +02:00
parent 702443e90e
commit c118892017
7 changed files with 199 additions and 13 deletions

View File

@@ -0,0 +1,24 @@
# Optionale Übungen
## 1. Integration eines weiteren Moduls
- Intergriere ein weiteres Modul deiner Wahl in die Webseite. (Splide, GlideJS, photoswipe, tiny-slider)
## 2. Tooltip als Modul verwenden
Intergriere das Plugin [`popper.js`](https://popper.js.org/docs/v2/) oder die neuere Version [`floating-ui`](https://floating-ui.com/)
in die Webseite.
## 3. Formularvalidierung als Modul
Erstelle ein Modul für die Validierung von einem Formular (`FormValidator`) mit folgenden Feldern
- Vor- und Nachname
- E-Mail
- Adresse bestehend aus:
- Strasse, Hausnummer
- PLZ, Ort
- Land
- Nachricht
Die Validierung soll direkt während (`input`) oder nach der Eingabe (`blur`) der Felder stattfinden. Die Verwendung von Validierungsmodulen wie `validator` dürfen dabei verwenden werden.

View File

@@ -53,6 +53,7 @@ const ProductModel = () => {
}; };
const update = (product) => { const update = (product) => {
console.log(product);
const foundIdx = products.findIndex((obj) => { const foundIdx = products.findIndex((obj) => {
return obj._id === product._id; return obj._id === product._id;
}); });

View File

@@ -61,7 +61,7 @@ app.post('/api/products', (req, res) => {
return res.status(400).send({ msg: 'Could not add product', status: 400, success: false }); return res.status(400).send({ msg: 'Could not add product', status: 400, success: false });
} }
res.send({ msg: 'Product added', status: 200, success: true, data: product }); return res.send({ msg: 'Product added', status: 200, success: true, data: product });
}); });
// HTTP - Methode - GET // HTTP - Methode - GET
@@ -69,7 +69,7 @@ app.post('/api/products', (req, res) => {
// (B)READ - browse // (B)READ - browse
app.get('/api/products', (req, res) => { app.get('/api/products', (req, res) => {
const data = products.getAll(); const data = products.getAll();
res.send(data); return res.send(data);
}); });
// HTTP - Methode - GET // HTTP - Methode - GET
@@ -83,7 +83,7 @@ app.get('/api/products/:id', (req, res) => {
return res.status(400).send({ msg: 'Could not get product', status: 400, success: false }); return res.status(400).send({ msg: 'Could not get product', status: 400, success: false });
} }
res.send(product); return res.send(product);
}); });
// HTTP - Methode - PUT/PATCH // HTTP - Methode - PUT/PATCH
@@ -98,7 +98,7 @@ app.put('/api/products', (req, res) => {
return res.status(400).send({ msg: 'Could not update product', status: 400, success: false }); return res.status(400).send({ msg: 'Could not update product', status: 400, success: false });
} }
res.send({ msg: 'Product updated', status: 200, success: true, data: product }); return res.send({ msg: 'Product updated', status: 200, success: true, data: product });
}); });
// HTTP - Methode - DELETE // HTTP - Methode - DELETE
@@ -111,7 +111,7 @@ app.delete('/api/products/:id', (req, res) => {
return res.status(400).send({ msg: 'Could not delete product', status: 400, success: false }); return res.status(400).send({ msg: 'Could not delete product', status: 400, success: false });
} }
res.send({ msg: 'Product deleted', status: 200, success: true, data: id }); return res.send({ msg: 'Product deleted', status: 200, success: true, data: id });
}); });
// ========= // =========

View File

@@ -5179,6 +5179,7 @@
templateRow: module.querySelector(".template-row"), templateRow: module.querySelector(".template-row"),
// Modal // Modal
modalEdit: module.querySelector(".modal-edit"), modalEdit: module.querySelector(".modal-edit"),
formEdit: module.querySelector(".form-product-edit"),
inputEditName: module.querySelector(".input-edit-name"), inputEditName: module.querySelector(".input-edit-name"),
inputEditPrice: module.querySelector(".input-edit-price"), inputEditPrice: module.querySelector(".input-edit-price"),
inputEditId: module.querySelector(".input-edit-id"), inputEditId: module.querySelector(".input-edit-id"),
@@ -5194,6 +5195,23 @@
console.log("init"); console.log("init");
initProducts(); initProducts();
DOM.btnAdd.addEventListener("click", onClickAdd); DOM.btnAdd.addEventListener("click", onClickAdd);
DOM.formEdit.addEventListener("submit", onSubmitEdit);
};
const onSubmitEdit = (e) => {
e.preventDefault();
const product = {
name: DOM.inputEditName.value,
price: Number(DOM.inputEditPrice.value),
_id: DOM.inputEditId.value,
position: DOM.inputEditPosition.value
};
updateProduct(product).then((data) => {
console.log(data);
if (data.success) {
loadProducts();
bsModalEdit.hide();
}
});
}; };
const onClickAdd = (e) => { const onClickAdd = (e) => {
console.log("click"); console.log("click");
@@ -5201,7 +5219,13 @@
name: DOM.inputName.value, name: DOM.inputName.value,
price: Number(DOM.inputPrice.value) price: Number(DOM.inputPrice.value)
}; };
addProduct(product); createProduct(product).then((data) => {
console.log(data);
if (data.success) {
console.log("add");
loadProducts();
}
});
disableNonFunctionalButtons(); disableNonFunctionalButtons();
}; };
const onClickEdit = (e) => { const onClickEdit = (e) => {
@@ -5268,7 +5292,26 @@
} }
disableNonFunctionalButtons(); disableNonFunctionalButtons();
}; };
const fetchProducts = async () => { const createProduct = async (product) => {
try {
const response = await fetch(`${BASE_URL}/api/products`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(product)
});
if (!response.ok) {
throw new Error("Fetch went wrong.");
}
const data = await response.json();
return data;
} catch (error) {
console.error(error);
return error;
}
};
const getProducts = async () => {
try { try {
const response = await fetch(`${BASE_URL}/api/products`); const response = await fetch(`${BASE_URL}/api/products`);
if (!response.ok) { if (!response.ok) {
@@ -5294,14 +5337,42 @@
return error; return error;
} }
}; };
const updateProduct = async (product) => {
try {
const response = await fetch(`${BASE_URL}/api/products`, {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(product)
});
if (!response.ok) {
throw new Error("Fetch went wrong.");
}
const data = await response.json();
return data;
} catch (error) {
console.error(error);
return error;
}
};
const initProducts = () => { const initProducts = () => {
fetchProducts().then((products) => { getProducts().then((products) => {
products.forEach((product) => { products.forEach((product) => {
addProduct(product); addProduct(product);
}); });
disableNonFunctionalButtons(); disableNonFunctionalButtons();
}); });
}; };
const loadProducts = () => {
DOM.tBody.innerHTML = "";
getProducts().then((data) => {
data.forEach((product) => {
addProduct(product);
});
disableNonFunctionalButtons();
});
};
const addProduct = (product) => { const addProduct = (product) => {
const { name, price, _id: id, position } = product; const { name, price, _id: id, position } = product;
const trEl = DOM.templateRow.content.firstElementChild.cloneNode(true); const trEl = DOM.templateRow.content.firstElementChild.cloneNode(true);

File diff suppressed because one or more lines are too long

View File

@@ -24,6 +24,7 @@ const ProductManager = (el = null) => {
// Modal // Modal
modalEdit: module.querySelector('.modal-edit'), modalEdit: module.querySelector('.modal-edit'),
formEdit: module.querySelector('.form-product-edit'),
inputEditName: module.querySelector('.input-edit-name'), inputEditName: module.querySelector('.input-edit-name'),
inputEditPrice: module.querySelector('.input-edit-price'), inputEditPrice: module.querySelector('.input-edit-price'),
inputEditId: module.querySelector('.input-edit-id'), inputEditId: module.querySelector('.input-edit-id'),
@@ -45,9 +46,30 @@ const ProductManager = (el = null) => {
// Event-Lauscher zu beginn der Anwendung // Event-Lauscher zu beginn der Anwendung
DOM.btnAdd.addEventListener('click', onClickAdd); DOM.btnAdd.addEventListener('click', onClickAdd);
DOM.formEdit.addEventListener('submit', onSubmitEdit);
}; };
// === EVENTHANDLER ===== // === EVENTHANDLER =====
const onSubmitEdit = (e) => {
e.preventDefault(); // Standardverhalten unterbinden (Formular nicht an action versenden)
const product = {
name: DOM.inputEditName.value,
price: Number(DOM.inputEditPrice.value),
_id: DOM.inputEditId.value,
position: DOM.inputEditPosition.value,
};
// update async process
updateProduct(product).then((data) => {
console.log(data);
if (data.success) {
loadProducts(); // All Produkte auslesen
bsModalEdit.hide();
}
});
};
const onClickAdd = (e) => { const onClickAdd = (e) => {
console.log('click'); console.log('click');
@@ -56,7 +78,15 @@ const ProductManager = (el = null) => {
price: Number(DOM.inputPrice.value), price: Number(DOM.inputPrice.value),
}; };
addProduct(product); createProduct(product).then((data) => {
console.log(data);
if (data.success) {
console.log('add');
loadProducts();
}
});
// addProduct(product);
disableNonFunctionalButtons(); disableNonFunctionalButtons();
}; };
@@ -171,10 +201,34 @@ const ProductManager = (el = null) => {
// === XHR/FETCH ======== // === XHR/FETCH ========
// HTTP - Methode - POST
// (C)RUD - create
// BRE(A)D - add - neues Produkt hinzufügen
const createProduct = async (product) => {
try {
const response = await fetch(`${BASE_URL}/api/products`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(product),
}); // HTTP Request URL
if (!response.ok) {
throw new Error('Fetch went wrong.');
}
const data = await response.json(); // HTTP-Response
return data;
} catch (error) {
console.error(error);
return error;
}
};
// HTTP - Methode - GET // HTTP - Methode - GET
// C(R)UD - Read // C(R)UD - Read
// (B)READ - Browse - auslesen aller Produkte // (B)READ - Browse - auslesen aller Produkte
const fetchProducts = async () => { const getProducts = async () => {
try { try {
const response = await fetch(`${BASE_URL}/api/products`); // HTTP Request URL const response = await fetch(`${BASE_URL}/api/products`); // HTTP Request URL
if (!response.ok) { if (!response.ok) {
@@ -207,10 +261,34 @@ const ProductManager = (el = null) => {
} }
}; };
// HTTP - Methode - PUT
// CR(U)D - update
// BR(E)AD - edit - Produkt aktualisieren
const updateProduct = async (product) => {
try {
const response = await fetch(`${BASE_URL}/api/products`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(product),
}); // HTTP Request URL
if (!response.ok) {
throw new Error('Fetch went wrong.');
}
const data = await response.json(); // HTTP-Response
return data;
} catch (error) {
console.error(error);
return error;
}
};
// === FUNCTIONS ======== // === FUNCTIONS ========
const initProducts = () => { const initProducts = () => {
fetchProducts().then((products) => { getProducts().then((products) => {
products.forEach((product) => { products.forEach((product) => {
addProduct(product); addProduct(product);
}); });
@@ -224,6 +302,16 @@ const ProductManager = (el = null) => {
// PRODUCTS.forEach(addProduct); // PRODUCTS.forEach(addProduct);
}; };
const loadProducts = () => {
DOM.tBody.innerHTML = '';
getProducts().then((data) => {
data.forEach((product) => {
addProduct(product);
});
disableNonFunctionalButtons();
});
};
const addProduct = (product) => { const addProduct = (product) => {
const { name, price, _id: id, position } = product; const { name, price, _id: id, position } = product;

View File

@@ -165,6 +165,8 @@
type="number" type="number"
name="price" name="price"
id="input-edit-price" id="input-edit-price"
min="0"
step="0.01"
class="form-control input-edit-price" /> class="form-control input-edit-price" />
<span class="input-group-text">&euro;</span> <span class="input-group-text">&euro;</span>
</div> </div>