I am having the following problem in my project. I am trying to delete an added product but unfortunately, it cannot be deleted. So let me show you my code.
First I have the Product.js model.
static deleteById(prodId){
const db = getDb();
return db
.collection('products')
.deleteOne({_id: new mongodb.ObjectId(prodId) })
.then(result => {
console.log('Deleted');
})
.catch(err => {
console.log(err);
});
}
Then I use deleteById function in my controller Admin.js file.
exports.postDeleteProduct = (req, res, next) => {
const prodId = req.params.productId;
Product.deleteById(prodId)
.then(() => {
console.log('DESTROYED PRODUCT');
res.redirect('/admin/products');
})
.catch(err => console.log(err));
};
After doing that I am creating the necessary route in the routes->admin.js file.
const path = require('path');
const express = require('express');
const adminController = require('../controllers/admin');
const router = express.Router();
// /admin/add-product => GET
router.get('/add-product', adminController.getAddProduct);
// admin/products => GET
router.get('/products', adminController.getProducts);
// /admin/add-product => POST
router.post('/add-product', adminController.postAddProduct);
router.get('/edit-product/:productId', adminController.getEditProduct);
router.post('/edit-product', adminController.postEditProduct);
router.post('/delete-product', adminController.postDeleteProduct);
module.exports = router;
Finally, there is the HTML file which contains the delete button.
<main>
<% if (prods.length > 0) { %>
<div class="grid">
<% for (let product of prods) { %>
<article class="card product-item">
<header class="card__header">
<h1 class="product__title">
<%= product.title %>
</h1>
</header>
<div class="card__image">
<img src="<%= product.imageUrl %>" alt="<%= product.title %>">
</div>
<div class="card__content">
<h2 class="product__price">$
<%= product.price %>
</h2>
<p class="product__description">
<%= product.description %>
</p>
</div>
<div class="card__actions">
Edit
<form action="/admin/delete-product" method="POST">
<input type="hidden" value="<%= product._id %>" name="productId">
<button class="btn" type="submit">Delete</button>
</form>
</div>
</article>
<% } %>
</div>
<% } else { %>
<h1>No Products Found!</h1>
<% } %>
</main>
<%- include('../includes/end.ejs') %>
Here is my repo.
How can the delete problem be fixed?
Related
Am getting this error when google auth redirects to my secrets page. And also in the secrets page I can't post secrets as they aren't posted in my database. I don't know which elements I have called wrongly.
<%- include('partials/header') %>
<div class="jumbotron text-center">
<div class="container">
<i class="fas fa-key fa-6x"></i>
<h1 class="display-3">You've Discovered My Secret!</h1>
<% usersWithSecrets.forEach(function(foundUsers){ %>
<p class="secret-text"><%=foundUsers.secret%></p>
<% }) %>
<hr>
<a class="btn btn-light btn-lg" href="/logout" role="button">Log Out</a>
<a class="btn btn-dark btn-lg" href="/submit" role="button">Submit a Secret</a>
</div>
</div>
<%- include('partials/footer') %>
app.get("/secrets", function(req,res){
if (req.isAuthenticated()) {
User.find({"secret": {$ne: null}}, function(err, foundUsers){
if(foundUsers){
res.render("secrets", {usersWithSecrets: foundUsers});
}else {
console.log(err);
}
});
app.post("/submit", function(req, res){
const submittedSecret = req.body.secret;
User.findById(req.user.id, function(err, foundUser){
if (err) {
console.log(err);
}else{
if (foundUser) {
foundUser.secret=submittedSecret;
submittedSecret.save(function(){
res.redirect("/secrets");
});
}
}
});
});
The first block of code should catch the user and redirect them to the app.get(secrets)
The second block is a user can post a secret and caught in the database but the page keeps loading infinitely.
I'm trying to upload (update acutally) an image to a db and then redirect to profile page, i tried everything and the photo is updated successfully in the db but page wont redirect.
If i dont attach an image everything is ok and user gets redirected.
If i do attach an image user just stays on form page, no errors pop up, page just gets refreshed (photo gets updated in db successfully)
post route
var store = require("./multer");
router.post("/:username/edit", isUser, personalContent, store.single("profilePic"), async (req, res) => {
try {
if (req.file) {
await User.updateOne(
{ username: req.user.username },
{
username: req.params.username,
dateOfBirth: req.body.date,
filename: req.file.originalname,
contentType: req.file.mimetype,
imageBase64: fs.readFileSync(req.file.path).toString("base64"),
},
{ upsert: true }
);
} else {
await User.updateOne(
{ username: req.user.username },
{
username: req.params.username,
dateOfBirth: req.body.date,
},
{ upsert: true }
);
}
res.redirect("/profile/" + req.params.username + "?msg=Profile updated successfully");
} catch (err) {
console.log(err);
res.redirect("/profile/" + req.params.username + "?msg=Error while updating profile");
}
});
ejs form
<form action="/profile/<%= user.username %>/edit" enctype="multipart/form-data" method="POST">
<% if(error){ %> <%= error %> <% } %> <% if(msg){ %> <%= msg %> <% } %>
<div>
<label for="username">Username: </label>
<input type="text" name="username" value="<%= user.username %>" disabled />
</div>
<div>
<label for="date">Date of birth: </label>
<input type="date" name="date" required value="<%= user.dateOfBirth.toISOString().split("T")[0] %>" />
</div>
<div>
<label for="profpic">Profile picture:</label>
<input type="file" name="profilePic" />
<div>
<% if(user.imageBase64){ %>
<img src="data:<%=user.contentType%>;base64,<%=user.imageBase64%>" alt="" style="height: 3rem" />
<% }else{ %> Add profile picture <% } %>
</div>
</div>
<button type="submit">Submit</button>
</form>
multer.js
const multer = require("multer");
//set storage
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "uploads");
},
filename: (req, file, cb) => {
cb(null, file.fieldname + "-" + Date.now());
},
});
module.exports = store = multer({ storage: storage });
The issue was with LiveServer chrome extension, it was messing something up with redirects. Now this question seems stupid to me but if someone stumbled upon this I hope I could help
I'm trying to upload a file to a directory. The following code worked for me
CONTROLLER
[HttpPost]
public ActionResult Index(HttpPostedFileBase uploadFile)
{
//string path = #"C:\Users\thomas\Desktop";
if (uploadFile != null)
{
string filePath = Path.Combine(Server.MapPath("/files"), Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(filePath);
}
return RedirectToAction("Index");
}
HTML PAGE
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<form action="/Post/Index" method="post" enctype="multipart/form-data">
<label for="uploadFile">Upload file: </label>
<input name="uploadFile" id="uploadFile" type="file" />
<input value="uploadFile" type="submit" />
</form>
Now i'm trying to implement this in a function where i create a message which is created by a model that is containing a message and an item class. When i submit the form the model is passed to my savecontroller but the file is null in my parameter controller.
HTML PAGE
Create new message
#model GeoCitytroopers.Models.MessageItemModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Event</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Message.MessagePicture)
</div>
<div>
<label for="uploadFile">Upload file: </label>
<input name="uploadFile" id="uploadFile" type="file" />
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Message.MessagePicture)
#Html.ValidationMessageFor(model => model.Message.MessagePicture)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item.ItemTitle)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.ItemTitle)
#Html.ValidationMessageFor(model => model.Item.ItemTitle)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item.ItemDescription)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.ItemDescription)
#Html.ValidationMessageFor(model => model.Item.ItemDescription)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
CONTROLLER
[HttpPost]
public ActionResult Create(HttpPostedFileBase uploadFile, MessageItemModel ViewModel)
{
if (ModelState.IsValid)
{
Utility ut = new Utility();
Item viewItem = ViewModel.Item;
Message viewMessage = ViewModel.Message;
if (uploadFile != null)
{
string filePath = Path.Combine(Server.MapPath("/files"), Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(filePath);
}
//ADD USER TO ITEM
viewItem = ut.AddUserToItem(viewItem);
//ADD ITEM
viewItem.ItemCreateddate = DateTime.Now;
//ADD DISTRICT TO ITEM
viewItem.DistrictID = ut.GetUserDistrict();
db.Items.Add(viewItem);
//ADD LINK
viewMessage.Item = viewItem;
db.Messages.Add(viewMessage);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(ViewModel);
}
How can i pass the uploading file to my controller?
Thanks in advance!
You forgot set the correct enctype to the form. You cannot upload files without that:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" })) {
...
}
Now the upload will work and your uploadFile parameter will not be null.
My initial guess is that the you created using Html helper doesn't have the necessary encrypt on it.
try using
using(#Html.BeginForm("action-name","controller-name",
FormMethod.Post, new { enctype="multipart/form-data"}){
}
with appropriate values for action-name and controller-name
I've got two DropDownLists in a form on a page that contain the same values (a list of languages). I want to ensure that the user doesn't select the same value in each of the drop downs.
I've tried using JavaScript to ensure the selected values aren't the same, it works fine but the form submits anyway.
What's the best way to accomplish this?
Here's the code from my View:
<script type="text/javascript">
function CheckLanguageDDL()
{
var form = document.getElementById("form0");
var sourceLangIndex = form.SourceLanguage.selectedIndex;
var targetLangIndex = form.TargetLanguage.selectedIndex;
var strSourceLanguage = form.SourceLanguage.options[sourceLangIndex].text;
var strTargetLanguage = form.TargetLanguage.options[targetLangIndex].text;
if (strSourceLanguage == strTargetLanguage)
{
alert("Source Language and Target Language must be different!");
return;
}
}
</script>
<% Html.BeginForm("Index", "Translate", FormMethod.Post, new { enctype = "multipart/form-data" }); %>
<fieldset>
<legend>Request</legend>
<br />
<div class="editor-label">
<%: Html.LabelFor(m => m.SourceLanguage) %>:
</div>
<div class="editor-field">
<%: Html.DropDownList("SourceLanguage", (IEnumerable<SelectListItem>)ViewData["SourceLanguages"]) %>
<%: Html.ValidationMessageFor(m => m.SourceLanguage) %>
</div>
<br />
<div class="editor-label">
<%: Html.LabelFor(m => m.TargetLanguage) %>:
</div>
<div class="editor-field">
<%: Html.DropDownList("TargetLanguage", (IEnumerable<SelectListItem>)ViewData["TargetLanguages"]) %>
<%: Html.ValidationMessageFor(m => m.TargetLanguage) %>
</div>
<input type="submit" value="Submit Request" onclick="CheckLanguageDDL();" />
</p>
</fieldset>
Thanks.
Make the function return a true/false value that the form submit use that return value
function CheckLanguageDDL()
{
var form = document.getElementById("form0");
var sourceLangIndex = form.SourceLanguage.selectedIndex;
var targetLangIndex = form.TargetLanguage.selectedIndex;
var strSourceLanguage = form.SourceLanguage.options[sourceLangIndex].text;
var strTargetLanguage = form.TargetLanguage.options[targetLangIndex].text;
if (strSourceLanguage == strTargetLanguage)
{
return false;
}
return true;
}
And on the button:
onclick="return CheckLanguageDDL();"
I gotta the following code in controller and view. The problem is that the model(Photo is an Entity Framework entity) is empty(all fields are nulled). Why?
// GET: /Admin/Photo/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Admin/Photo/Create
[HttpPost]
public ActionResult Create(int id, FormCollection collection)
{
try
{
var file = (HttpPostedFileBase) Request.Files[0];
if (file != null && file.FileName != null)
{
var filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Photos/Product/", Path.GetFileName(file.FileName));
file.SaveAs(filename);
var photo = new Photo();
photo.Description = collection["Description"];
photo.Main = collection["Main"].Contains("true");
photo.Filename = Path.GetFileName(file.FileName);
photo.Product_Id = id;
Entities.AddToPhotos(photo);
Entities.SaveChanges();
}
else
{
ModelState.AddModelError("", "Plik musi zostać załadowany.");
return View();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
<h2>Create</h2>
<% using (Html.BeginForm(null, null, null, FormMethod.Post, new {enctype = "multipart/form-data" })) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Description) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Description) %>
<%: Html.ValidationMessageFor(model => model.Description) %>
</div>
<div class="editor-label">
<label for="MainContent_file">Plik: </label>
</div>
<div class="editor-field">
<asp:FileUpload ID="file" runat="server" />
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Main) %>
</div>
<div class="editor-field">
<%: Html.CheckBoxFor(model => model.Main) %>
<%: Html.ValidationMessageFor(model => model.Main) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
Update: I checked and the collection is populated with proper fields, but they are all nulled.
Check to make sure that the name attributes in the resulting html match your collection name. You could also change your public ActionResult Create(int id, FormCollection collection) to public ActionResult Create(int id, YourViewModel model) to automagically map the post values to the model.
Check the html source in the browser.
It might be sending them as: "Photo.Description"