I am having a problem to convert the following Ejs to pug - node.js

I am having a problem to convert the following Ejs to pug
in admin/edit-product.ejs
we can make changes with product already we have it
but But I want to transfer ejs to pug
any solutions
<form class="product-form" action="/admin/<% if (editing) { %>edit-product<% } else { %>add-product<% } %>" method="POST">
in admin.js controller
exports.getAddProduct = (req, res, next) => {
res.render('admin/edit-product', {
pageTitle: 'Add Product',
path: '/admin/add-product',
editing: false
});
};
exports.postAddProduct=(req, res, next) => {
const title=req.body.title;
const imageUrl=req.body.imageUrl;
const price=req.body.price;
const description=req.body.description;
const product=new Product(title,imageUrl,description,price);
product.save();
res.redirect('/');
};
exports.getEditProduct = (req, res, next) => {
const editMode = req.query.edit;
if (!editMode) {
return res.redirect('/');
}
const prodId = req.params.productId;
Product.findById(prodId, product => {
if (!product) {
return res.redirect('/');
}
res.render('admin/edit-product', {
pageTitle: 'Edit Product',
path: '/admin/edit-product',
editing: editMode,
product: product
});
});
};

Pug supports inline JavaScript code, so you could use a ternary conditional within some attribute interpolation like this:
form.product-form(action='/admin/' + (editing ? 'edit' : 'add') + '-product', method='POST')
Or for a more readable approach, construct the action path beforehand in a code block and store it in a variable:
-
let action = editing ? 'edit' : 'add'
let actionPath = `/admin/${action}-product`
form.product-form(action= actionPath, method='POST')

Related

How to upload multiple images to Cloudinary?

I've implemented a working post route that uploads a single image to cloudinary on submit.
What needs to be changed to enable multiple image upload? Any help is appreciated.
My post route:
app.post("/portfolio/new", upload.single('image'), function(req, res) {
cloudinary.v2.uploader.upload(req.file.path, function(err, result) {
if (err) {
console.log(err);
}
req.body.image = result.secure_url;
console.log(req.body.image);
Portfolio.create(req.body.project, function(err, newProject) {]
if (err) {
console.log(err);
}
res.redirect("/portfolio");
});
});
});
My HTML (with EJS):
<form action="/portfolio/new" enctype="multipart/form-data" method="POST">
<div>
Select images:
<input type="file" id="image" name="image" accept="image/*" required>
</div>
</form>
const cloudinaryImageUploadMethod = async file => {
return new Promise(resolve => {
cloudinary.uploader.upload( file , (err, res) => {
if (err) return res.status(500).send("upload image error")
resolve({
res: res.secure_url
})
}
)
})
}
router.post("/", upload.array("img", 3 ), async (req, res) => {
const urls = [];
const files = req.files;
for (const file of files) {
const { path } = file;
const newPath = await cloudinaryImageUploadMethod(path);
urls.push(newPath);
}
const product = new Product({
name: req.body.name,
productImages: urls.map( url => url.res ),
});
}
To add to the above, you can use this pen for a simple javascript multiple image uploader: codepen.io/team/Cloudinary/pen/QgpyOK
Here's a very fancy uploader widget with a ton of options built-in: codepen.io/dzeitman/pen/EwgjJV
Hope this helps others trying to do something similar and just want to see something working.
in input tag, you should write ... multiple.
and in post route, one should write
upload.array("image")
instead of
upload.single()
and in the schema file, you should define the image as an array of objects
i.e. image:[
{
URL: String,
filename: String
}
]

Unable to create or edit new Post (Node & Mongo)

I already solved the problem but now IT is back. I want to save new artist to the website or edit them but now its like the application doesnt connect to the DB but it is! I checked.
const
express = require('express'),
router = express.Router(),
Post = require('../models/post');
// Define which ImageTypes are avaiable to upload
const imageMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'];
// All admin Routes
router.get('/', async (req, res) => {
renderNewPage(res, new Post())
})
// New Route
router.get('/create', (req, res) => {
res.render('admin/createPost/index', {
layout: 'layouts/admin',
// Defined in models/post, gets variables
post: new Post()
});
})
// New Post create
router.post('/', async (req, res) => {
const post = new Post({
// get information from sended new Post (above) and defines variables to use in ejs files
surname: req.body.surname,
name: req.body.name,
bio: req.body.bio,
birthday: req.body.birthday,
technic: req.body.technic,
techPricerangeFrom: req.body.techPricerangeFrom,
techPricerangeTo: req.body.techPricerangeTo
})
// set FilePond saving files to DB
saveProfilpic(post, req.body.profilpic)
try { // await for new post to safe
const newPost = await post.save();
res.redirect('admin');
} catch {
renderNewPage(res, post, true)
}
})
//? Singe Artist Show, Edit, Upate, Delete
// Create single artists page
router.get('/:id', (req, res) => {
res.send('Show Artist' + req.params.id)
})
// Edit artist
router.get('/:id/edit', async (req, res) => {
try {
const findPost = await Post.findById(req.params.id)
res.render('admin/edit', {
layout: 'layouts/admin',
post: findPost
})
} catch {
res.redirect('/admin')
}
})
// Update artist text
router.put('/:id', async (req, res) => {
let post;
try {
post = await Post.findById(req.params.id)
post.surname = req.body.surname,
post.name = req.body.name,
post.bio = req.body.bio,
post.birthday = req.body.birthday,
post.technic = req.body.technic,
post.techPricerangeFrom = req.body.techPricerangeFrom,
post.techPricerangeTo = req.body.techPricerangeTo,
post.profilpic = req.body.profilpic
await post.save();
res.redirect(`/admin`);
} catch {
if (post == null) {
res.redirect('/admin')
}
else {
res.render('admin/edit', {
layout: 'layouts/admin',
post: post,
})
}
}
})
// Define functions
async function renderNewPage(res, post, hasError = false) {
// Implement all Posts (artists) in the DB
try {
const posts = await Post.find({}).collation({ locale: 'en', strength: 2 }).sort({ name: 1 }) // wait and find all post and sort my name
const params = {
layout: 'layouts/admin',
posts: posts, // take all posts from await Post.find({}) and overrides the updates the posts
}
if (hasError) params.errorMessage = 'Ein Fehler ist aufgetreten'
res.render('admin/index', params);
} catch (err) {
res.redirect('/');
}
}
// func for dave files via filepond
function saveProfilpic(post, profilpictureEncoded) {
if (profilpictureEncoded == null) return
const profpic = JSON.parse(profilpictureEncoded);
if (profpic != null && imageMimeTypes.includes(profpic.type)) { // If the file is a json obj & from the type image (jpg, png)
post.profilpic = new Buffer.from(profpic.data, 'base64') // Buffer.from(where, how)
post.profilpicType = profpic.type
}
}
module.exports = router;
all types in the model/post file are Strings.If I want to change something it redirects me to /admin, what means its a error. I got all latest packages (express, mongoose, ...)
I found your answer as I was working on the same tutorial, so I'm still quite new to this, but in my case the problem was related to having a missing '=' in the index page view.
Do you have the '=' character within the <% %> part so that the id is actually included in the link? If not, the link won't include the actual id, since the '=' is needed to not just access a variable but also display it.
<% artists.forEach(Artist=> { %>
<div><%= Artist.last_name %></div>
View
<% }) %>
Hope this helps, and feel free to correct me, as I'm also just starting to learn the basics.

Indexing user query with Appbaseio and ReactiveSearch

I'm attempting to index a user's query using ReactiveSearch's DataSearch component and appbase-js.
So I've made my Node/Express app for appbase-js interaction with appbaseio.
in app.js:
...
const search = require('./routes/search');
...
app.use('/api/search', search);
Then here is my search.js
const express = require('express');
const Appbase = require('appbase-js');
// create an appbase.io app's instance
const appbaseRef = new Appbase({
url: "https://scalr.api.appbase.io",
app: "index-query",
credentials: "####-####"
});
const router = express.Router();
/* GET search. */
router.get('/test', (req, res, next) => {
res.send('This is the SEARCH route - and it WORKS!');
});
router.post('/query', (req, res, next) => {
appbaseRef.index({
type: "autocomplete",
body: value
}).then('data', response => {
console.log("#index success: ", response);
}),('error', error => {
console.log("#index error: ", error);
});
});
module.exports = router;
Then here is my DataSearch component:
<DataSearch
componentId="SearchSensor"
dataField={["suggestions"]}
className="search-bar"
iconPosition="right"
innerclassName={{
list: "text-item"
}}
onValueSelected{
(value) => {
????
}
}
/>
I was advised in another question not do this:
onValueSelected={(value) => {
fetch('YOUR_SERVER_URL' or 'Elasticsearch URL', { method: 'POST', body: {...} })
}
So as not to expose sensitive information on the client
I'm not sure how to get value (the user's query) from my React front end to my Node/Express backend so that it can be indexed to ES app on Appbaseio?
Say your server is hosted at 'SERVER_URL', the key is to send the data from the frontend to the server via a fetch request:
<DataSearch
...
onValueSelected={(value) => {
fetch('SERVER_URL/api/search/query', {
method: 'POST',
body: JSON.stringify({ value })
}).then(() => handle response client side))
}}
/>
Then you can add the body-parser middleware in express.
app.use(bodyParser.json())
In your route you can use the value from body and index it to elasticsearch. You can use the index method from appbase-js which you're using here.
router.post('/query', (req, res, next) => {
appbaseRef.index({
type: "autocomplete",
body: { value: req.body.value }
}).then('data', response => {
console.log("#index success: ", response);
}),('error', error => {
console.log("#index error: ", error);
});
});

Error: Route.get() requires a callback function but got a [object Undefined]

I'm trying to create a recipe search app using Express as my backend, and am getting the error message in the title from my Router file when I start my server up. I've made projects before where my Router follows the same as it does here, but for some reason I keep getting the error and I can't figure out why. Below I've pasted the code to my controller, helper, and route files:
Controller:
// import model and users controller
const Recipe = require('../models/recipe');
const usersController = require('../controllers/users-controller');
// initiate controller object
const recipesController = {}
// send API data
recipesController.sendApiRecipe = (req, res) => {
res.json({
message: `recipe returned`,
recipe: res.locals.recipe,
})
}
// show all favorited recipes
recipesController.index = (req, res, next) => {
Recipe.findByUser(req.user.id)
.then(recipe => {
res.json({
message: 'rendering favorites',
data: { recipe },
})
}).catch(next)
}
// create favorite recipe
recipesController.create = (req, res) => {
console.log(req.body, 'from create/recipesController')
Recipe.create({
title: req.body.title,
diet: req.body.diet,
calories: req.body.calories,
servings: req.body.servings,
health: req.body.health,
ingredient: req.body.ingredient,
img: req.body.img,
link: req.body.link,
user_id: req.user.id,
}).then(recipe => {
res.json({
message: 'successfully added',
data: { recipe }
})
}).catch(err => {
console.log(err)
res.status(500).json({error: err})
})
}
// delete favorite recipe
recipesController.delete = (req, res, next) => {
Recipe.destroy(req.params.id)
.then(() => {
res.json({
message: 'successfully deleted recipe',
})
}).catch(next)
}
export default recipesController;
Helper:
// import dependencies
require('isomorphic-fetch')
require('dotenv').config()
function getRecipes(req, res, next) {
// fetch URL
fetch(`https://api.edamam.com/search?q=${req.params.search}&app_id=${process.env.APP_ID}&app_key=${process.env.APP_KEY}&from=0&to=30`)
.then(res => res.json())
// use res.locals to attach data to repsonse object
.then(fetchRes => {
// set fetched results to res.locals
res.locals.recipe = fetchRes
next()
})
}
// export function
module.exports = {
getRecipes: getRecipes,
}
Routes:
// import dependencies
const express = require('express')
const recipeHelpers = require('../services/recipes/recipe-helpers')
const recipesController = require('../controllers/recipes-controller')
const recipesRouter = express.Router()
recipesRouter.get('/:search', recipeHelpers.getRecipes, recipesController.sendApiRecipe)
recipesRouter.post('/create', recipesController.create)
module.exports = recipesRouter;
Please let me know if there's any additional information I should provide, and I'll be certain to follow up with any findings I come across as I troubleshoot further. Thanks in advance for any help!
I just realized I didn't export my controller properly, and fixing that resolved the issue. Thanks!

Unable to get params Node and Angular

I have a list of todos that are fetched from MongoDB and they are displayed on one page and when I click on one it opens on another page with URL that equals clicked todo. Now I am trying to get the id from URL and send it to node server but I can't get it.
ngOnInit() {
this.route.params
.subscribe(
(params: Params) => {
let todoId = params['userId'];
console.log(todoId);
}
);
}
console returns undefined.
I found one solution where id is fetched by this line of code, but it only gets id once and when I click on another todo it doesn't log anything.
let id = this.route.snapshot.paramMap.get('id');
console.log(id)
And when I want to send request to server with this:
let id = this.route.snapshot.paramMap.get('id');
this.todoService.getSingleTodo(id)
.subscribe(
(todo: Todo) => {
this.todo = todo;
console.log(todo);
}
);
I got this error in console "message":"Cast to ObjectId failed for value \":id\" at path \"_id\"
Service looks like this:
getSingleTodo(id) {
return this.http.get('http://localhost:3000/todos/:id')
.map( response => response.json().obj)
.map( todo => todo.map(todo => new Todo(todo.todoHeadline,
todo.todoDescription, todo._id)));
}
And node file:
router.get('/:id', (req, res, next) => {
console.log(req.params.id);
Todo.findById(req.params.id, (err, singleTodo) => {
if (err) {
return res.status(500).json({
title: 'An error occured',
error:err
});
}
res.status(201).json({
message: 'Success',
obj: singleTodo
});
});
});
Also this console prints :id.
Main routing file
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/auth', pathMatch: 'full' },
{ path: 'todos', component: TodoComponent, children: TODO_ROUTES},
{ path: 'auth', component: AuthenticationComponent, children: AUTH_ROUTES }
];
And children routes for todos
export const TODO_ROUTES: Routes = [
{path: 'todo/add', component: TodoAddComponent},
{path: ':id', component: TodoListComponent},
{path: 'edit', component: TodoEditComponent}
];
HTML where all todos are displayed lools like this
<ul class="list-group">
<li class="list-group-item"
*ngFor="let todo of todos;"
[routerLink]="['/todos', todo.todoId]">{{todo.todoHeadline}}
</li>
</ul>
What could be the problem?
It's this line right here that's wrong:
let todoId = params['userId'];
In your Routing, you defined that the path variable would be named "id":
{path: ':id', component: TodoListComponent},
So when you try to access a path variable userId, it obviously returns undefined.

Resources