How to fix this function, to retrieve data contain search keywords? - node.js

I'm developing website using MERN stack technologies. In that application I want to provide search facility. There is text box search button next to it. I want to open search results in new page. For example,
Data table contains products. If some user type 'milk' and click on search new page should show all milk product details.
when I click on search button it updated browser URL to this,
http://localhost:3000/search_result/this_is_search_string
This is the frontend code,
<form className="form-inline">
<input type="text"
className="form-control"
value={this.state.name}
onChange={this.on_change_name}/>
<Link to={'/search_result/'+this.state.name} className="btn btn-primary">Search</Link>
</form>
First problem is URL updated when click on button, but it not redirect to new page.
In search_result page componentDidMount() method looks like this,
componentDidMount(){
axios.get('http://localhost:4000/item/')
.then(response => {
this.setState({ search_result: response.data });
})
.catch(function (error) {
console.log(error);
})
}
I want to pass url appended value to above function' 2nd line,
axios.get('http://localhost:4000/item/') end of /item/. So I could load retrieved values to table.
Also in the backend controller file' method look like this.
export const get_items_by_name=(req,res)=>{
//Item.find(req.params.id,(err,item)=>{{name: "Renato"}
Item.find({name: "a"},(err,item)=>{
if(err){
res.send(err);
}
res.json(item);
});
};
In SQL there is a way to perform select query with LIKE. But I'm new to MERN stack. So how could I update above method to search and retrieve values as URL appended.
I need your help guys how to figure out this. Thank for your help specially with implementation support.

In your problem you need to change your controller something like this try it,
export const get_items_by_name=(req,res)=>{
//Item.find(req.params.id,(err,item)=>{{name: "Renato"}
Item.find({name:`/.*${req.body.name}.*/` },(err,item)=>{
if(err){
res.send(err);
}
res.json(item);
});
};
I tested this via postman and it works. You need to find way to do your page rendering part.

Related

Button in Node.js project works properly after two clicks not one

I'm making a simple project with node.js, express, mongodb, express session etc. It is a travel type site and a user in the database has a username, password and a list of destinations he wants to go to. Each destination page has a button to add that destination to the list and there is also a page which shows the current user's list. The proper functionality is that on the first button press the destination should be added to the users list in the database and the ejs view for the list page should be updated and on the second button press an alert should come up saying that the current destination is already on the user's list. However, seemingly randomly the button sometimes only works properly after two button presses and the alert and ejs view update of the list page occur on the third button press. Here are some code snippets:
This is my get request for the list page where I pass the current session user's want to go list as a parameter:
function isAuthenticated (req, res, next) {
if (req.session.user) next()
else res.redirect('/');
}
app.get('/wanttogo',isAuthenticated,function(req,res){
res.render('wanttogo',{dests:req.session.user.wantgo})
});
I update this list both in the session and in my database in each page's post request. This is an example for one of the pages:
app.post('/inca',function(req,res){
if((req.session.user.wantgo.length === 0) || !(req.session.user.wantgo.includes("Inca Trail to Machu Picchu"))){
req.session.user.wantgo.push("Inca Trail to Machu Picchu");
req.session.save();
db.collection("myCollection").updateOne({username:req.session.user.username},{$set:{wantgo:req.session.user.wantgo}});
db.collection("myCollection").findOne({username: req.session.user.username},(err,result)=>{
req.session.user.wantgo = result.wantgo;
req.session.user=result;
req.session.save();
});
}
else{
alert('This destination is already on your Want-To-Go List');
}
res.redirect('/inca');
and this is the part of the ejs view of the list page where I loop over the user's list and print it using the parameter I passed earlier:
<div>
<% for(var i=0; i < dests.length; i++) { %>
<h1><%= dests[i] %></h1>
<% } %>
</div>
Any help is appreciated!
This could be due to the fact "updateOne" and "findOne" are async functions and thus the database is not updated before you do the second button press.
Since this depends on time when the async operation is completed it sometimes works and sometimes doesn't.
Try using async await like this
app.post('/inca',async function(req,res){
if((req.session.user.wantgo.length === 0) || !(req.session.user.wantgo.includes("Inca Trail to Machu Picchu"))){
req.session.user.wantgo.push("Inca Trail to Machu Picchu");
req.session.save();
await db.collection("myCollection").updateOne({username:req.session.user.username},{$set:{wantgo:req.session.user.wantgo}});
await db.collection("myCollection").findOne({username: req.session.user.username},(err,result)=>{
req.session.user.wantgo = result.wantgo;
req.session.user=result;
req.session.save();
});
}
else{
alert('This destination is already on your Want-To-Go List');
}
res.redirect('/inca');

POST FORM in node and receive data response back to same webpage

I have a webpage that takes form details, POSTS the data and should then show the results. I'm using express for my routing.
This all works fine by resending the data with the HTML template after the POST but I think there must be a better way by hiding the "results" HTML section then just showing it once the data is known from the form. I've shown a cutdown version of my pages below.
On first load, the page says "your result is undefined", which I would expect but is ugly.
I could remove the "result" section and create a 2nd HTML page to resend from the POST route with it in which would work but I think there must be a better way.
I want to hide the result section on 1st page load then make it appear on the button submit with the result data. I can get the section hide/unhide but I can't get the data results back to display them. On button submit the form results just appear in the weburl www.mywebsite.com/?data almost like a GET request
I have tried using FormData and npm 'form-data' in a POST but can't get it working following these examples https://javascript.info/formdata and https://www.npmjs.com/package/form-data.
My structure in Node is
Router.js file
return res.send(htmlFormTemplate({}));
});
router.post('/css',
[],
async (req, res) => {
let {data} = req.body;
///
result= do some calculation on {data}
///
return res.send(htmlFormTemplate({result}));
});
The htmlFormTemplate is a js file
module.exports = ({result}) => {
return `
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form class="box" method ="POST">
<inputname="data" />
<button>Submit</button>
</form>
<script>
///tried form processing here
</script>
<section id="Results">
<ul><li>Your result is ${result}</li></ul>
</section>
</body>
</html>
`;
};
I'm self-taught and new so hope this makes sense and thanks for any help/ideas
You can check if the result variable is null before it gets to the section div:
${ result === null ? '' :
`<section id="Results">
<ul><li>Your result is ${result}</li></ul>
</section>`}
Like this, it wont show the result div if result if null.
There is a very simple to solve this problem,
just use some templating engine for ex EJS, its very easy to use and will help you better,
and your result is undefined because your using a promise and it might have happened that the response might have not come and you loaded the page. Just use await
return await res.send(htmlFormTemplate({result}));

How can I grab the correct object from the database via the id given on mongoDB?

I have a link like so:
const SpotIndexItem = ({ spot }) => (
<Link to={`/spots/${spot._id}`}>
<li>
<p>Put image here</p>
<p>{spot.name}</p>
</li>
</Link>
);
And it leads to the detail page of the index item. In the container component of the detail page, I have this:
const mapStateToProps = (state, ownProps) => ({
spot: state.entities.spots[ownProps.match.params.spotId]
});
And I'm rendering the item detail component like so in my app.js file:
<Route exact path="/spots/:spotId" component={SpotDetail} />
And this is in my route/api/spots.js file:
router.get('/:id', (req, res) => {
Spot.findById(req.params.id)
.then(spot => res.json(spot))
.catch(err =>
res.status(404).json({ nospotfound: 'No spot found with that ID' })
);
});
But I keep getting this error message:
The output errors:
Is there a way of doing this with the spot._id? Are there any built in find methods that I could use here to get the object with a specific _id?
UPDATE:
Out of curiosity, I also tried these routes in Postman and the index
route works perfectly fine. However, when I try to do a route like
this: localhost:5000/api/spots/5e4317871c9d440000b1613f, I get
null instead of the object.
I also found this post:
mongoose 'findById' returns null with valid id,
which solved the problem via connecting to the right database. I'm
new to mongoDB, but I'm fairly sure that I've set up my database
correctly. My app is connected to the test database (I don't have the ability on here to add images yet, but
here's a link to what my database looks like):
enter image description here

Scrape background-images using X-Ray-Scraper

I've been using X-Ray to scrape website which has been working really well. I can use it bring in images very easily. The one item I run into is I don't see an easy way to scrape a background image. Say I have a div where they are setting a style attribute on that dev and then setting the URL im not sure how to get the background-image url from this. I don't think I can just pass the featured image attribute the css property such as
.featured-image.attr('background-image');
const getWebsiteContent = async (blogURL, selector) => {
try {
return await x(blogURL, selector, [{
slug: 'a#href',
featuredImage: 'img#src'
}])
.paginate(`${pagi}#href`)
.limit(200)
.then((response) => {
spinner.succeed('Got the data');
return response;
})
} catch (error) {
throw new Error('Cannot get Data from website, try checking your URL');
}
};
For anyone that wants a solution to this with X-ray scraper what I ended up doing is pulling the attribute from the selector you pass into the object.Given the html looks like the following.
<div class="img" style="background-image: url('../path-to-img.jpg')"></div>
Instead of writing .img#src you could write .img#style and this would return to you the style attribute. From there you would need to use a regex to remove the rest of the un-needed data that is not the URL of the image.

How do you post data to CouchDB both with and without using JavaScript

I have a show which displays a form with fields populated from a document. I'd like to change the values in the field and then save the updated document.
I'm having trouble finding a clear, concise example of how to do this.
Seriously, just finishing this example would work wonders for so many people (I'm going to leave a lot of stuff out to make this concise).
Install Couchapp
This is outside the scope of my question, but here are the instructions for completeness.
Create a couchapp
Again, this is kind outside the scope of my question. Here is a perfectly concise tutorial on how to create a couchapp.
Create a template
Create a folder in the root of your couchapp called templates. Within the templates folder create an HTML page called myname.html. Put the following in it.
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<form method='post' action='#'>
<fieldset>
Hello <input type='text' name='name' value='{{ name }}'>
<input type='submit' name='submit' value='submit'>
</form>
</body>
</html>
Create a show
See the tutorial above for hwo to do this.
Add this code to a show called myname.
function(doc, req) {
if (doc) {
var ddoc = this
var Mustache = require("vendor/couchapp/lib/mustache");
var data = {
title: "The Name",
name: "Bobbert"
}
return Mustache.to_html(ddoc.templates.myname, data)
} else {
return ('nothing here baby')
}
}
Update the document with a new name by ...
So who can complete this step via both the client side and the server side?
Please don't point me to the guide, I need to read it in your words.
Thanks.
Edit:
Although the return value isn't pretty, just posting a form to the update handler will update the document.
You will probably want to look into update handler functions.
An update handler handles granular document transformations. So you can take 1 form, that has one distinct purpose, and only update the relevant fields in your document via the update handler.
Your update handler will need to take a PUT request from your form. A browser can't do this directly, so you'll need some javascript to handle this for you. If you're using jQuery, this plugin can take your form and submit it seamlessly via AJAX using PUT for you.
Inside the function, you can take the fields you are accepting, in this case name and apply that directly to the document. (input validation can be handled via the validate_doc_update function)
Update Handler (in your Design Document)
{
"updates": {
"name": function (doc, req) {
doc.name = req.form.name;
return [doc, "Name has been updated"];
}
}
}
HTML
<form id="myForm" action="/db/_design/ddoc/_update/name/doc_id">...</form>
JavaScript
$(document).ready(function() {
$('#myForm').ajaxForm({
type: "PUT",
success: function () {
alert("Thank you");
}
});
});
Once you've gotten this basic example up and running, it's not much more difficult to add some more advanced features to your update handlers. :)

Resources