onSelect not triggering for React dropdown - node.js

I am very new to React so I am still learning a lot. No matter what I do, the onSelect just does not seem to work. I made a simple function that it should call. You can tell it's been called via the console.log but in the browser when I look at the console it just does nothing.
Here is the code for the dropdown:
import React,{useState} from 'react';
import SEPractices from "../dummydata/SEPractices"
const optionItems = SEPractices.map((SEPractice) =>
<option key={SEPractice.practice}>{SEPractice.practice}</option>
);
const Dropdown = () => {
const handleSelect=(e)=>{
console.log("Inside");
}
return (
<div>
<select onSelect={handleSelect}>
<option Default hidden>
Select an SE Practice
</option>
{optionItems}
</select>
</div>
)
}
export default Dropdown;

Try using onChange
<select value={selectValue} onChange={handleSelect}>
<option Default hidden>
Select an SE Practice
</option>
{optionItems}
</select>
And handleSelect like this:
const [selectValue, setValue] = useState("")
cosnt handleSelect = (e) => {
setValue(e.target.value);
}

<select value={selectValue} onChange={handleSelect}>
<option value="dummyData">
Select an SE Practice
</option>
{optionItems}
</select>
and don't use the Default and hidden, React will take care of default value why specifying value={selectValue} in element.
Also, we need to pass the value to the <option>, it will track based on the value.

Related

Unable to search MongoDB by searching by params MERN stack

I'm trying to make a filtering system for my website and was wondering how I could filter a GET request by specifying what to filter from the frontend.
Here is what I'm trying to do:
If someone selects the filter options "SDG 2: Zero Hunger", "1: Discussion Project", and "Demographic", the user will click submit and then only the first card that has all those things will show up on the right of it, not the second one underneath it.
I've tried using URLSearchParams but I haven't been able to get it to work. I'm not sure how to go about this problem as the other stackoverflow forums for similar questions use that. This is the react frontend code I have (the only parts that matter are handleSubmit and componentDidUpdate), right now I just want to console.log the object that I got from the database which I filtered:
import React, { useEffect, useState } from 'react'
class Dropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
sdg: 'SDG 1: No Poverty',
assignment_type: 1,
theme: 'Demographic'
};
this.handleSDGChange = this.handleSDGChange.bind(this);
this.handleAssignmentChange = this.handleAssignmentChange.bind(this);
this.handleThemeChange = this.handleThemeChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
// Handling all 3 input changes
handleSDGChange(event) {
this.setState({sdg: event.target.value});
}
handleAssignmentChange(event) {
this.setState({assignment_type: event.target.value});
}
handleThemeChange(event) {
this.setState({theme: event.target.value});
}
componentDidUpdate() {
const fetchProjects = async () => {
const response = await fetch('/api/projects' + URLSearchParams({ sdg: this.state.sdg})) // Will add other 2 later, testing out 1 first
const json = await response.json() // contains array of projects
if (response.ok) {
console.log(json)
}
else {
console.log(json.error)
}
}
fetchProjects()
}
// Handling all 3 input submissions
handleSubmit(event) {
console.log(this.state.sdg)
alert(this.state.sdg + '--- Assignment Type: ' + this.state.assignment_type + '--- Theme: ' + this.state.theme);
event.preventDefault();
this.componentDidUpdate()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>SDG:</label>
<select value={this.state.sdg} onChange={this.handleSDGChange}>
{/* <option>Select SDG</option> */}
<option value="SDG 1: No Poverty">SDG 1: No Poverty</option>
<option value="SDG 2: Zero Hunger">SDG 2: Zero Hunger</option>
<option value="SDG 3: Good Health & Well Being">SDG 3: Good Health & Well Being</option>
</select>
<label>Assignment Type:</label>
<select value={this.state.assignment_type} onChange={this.handleAssignmentChange}>
<option value="1">1: Discussion Project</option>
<option value="2">2: PDF Case study</option>
<option value="3">3: Community Project</option>
</select>
<label>Theme:</label>
<select value={this.state.theme} onChange={this.handleThemeChange}>
<option value="Demographic">Demographic</option>
<option value="Economical">Economical</option>
<option value="Socio-cultural">Socio-cultural</option>
<option value="Technological">Technological</option>
<option value="Ecological">Ecological</option>
<option value="Poltical">Poltical</option>
</select>
<input type="submit" value="Submit" />
</form>
);
}
}
export default Dropdown
I'm also unsure how I can access this data in my express.js backend, here is what my GET route looks like:
const getProjects = async (req, res) => {
const projects = await Project.find({}).sort({ createdAt: -1 })
res.status(200).json(projects)
}
How do I send my parameters for the GET request from my class component to the backend which then can query the MongoDB and get only the filtered objects?

Issues populating dynamic dropdown with React Hooks

I've never had any issue with this before but I've been struggling to get this to work so I'm hoping someone can notice something that I'm just missing. I'm pulling data from an API to populate a dropdown in my form. The data gets returned just fine and I assign in to my state using useState with no issues. However, when I try to map my results to options for my dropdown it never populates.
Here is my state and my useEffect function that I'm calling once when the page loads.
const [users, setUsers] = useState([]);
useEffect(() => {
axios.get("/api/v1/users/find").then(res => {
setUsers(res.data)
})
}, [])
Like I said this all works with no issues. However this is where the issue is, my form:
<div className="relative">
<h3 className="text-2xl text-center font-bold mb-6">Create Item</h3>
<select className="h-full w-full border-gray-300 px-2 transition-all border-blue rounded-sm" name="owner" onChange={(e) => props.handleChange(e, 'owner')}>
<option selected value=''>Owner</option>
{users.map((i) => {
<option value={i.name}>{i.name}</option>
})}
</select>
</div>
Once again I've never had any issues with this so I'm not sure why it doesn't seem to be populating. Appreciate the help in advance!
Currently the function passed to .map() doesn't return anything. You can fix this by replacing the curly braces with parentheses:
{users.map((i) => (
<option value={i.name}>{i.name}</option>
))}
When curly braces are used in an arrow function you need an explicit return statement to return a value. Without curly braces there is an implicit return on the one line of the function body. (In this case parentheses just help define that one line since it includes carriage returns.)

Storing select option input value in React component inside MongoDB - MERN fail. Stores it as empty string

I am working with MERN and trying to store select option input values in my MongoDb database using mongoose. Like this
import React, {Component} from 'react';
import axios from 'axios';
class Admin extends Component {
constructor(props) {
super(props)
//setting initial states
this.state= {
college: ''
}
}
onChangeCollege=(event)=>{
this.setState({college: event.target.value})
}
onSubmit =(event) =>{
event.preventDefault()
console.log('Form Submitted')
const newCourse = {
college:this.state.college
}
axios.post('http://localhost:8000/courses/admin', newCourse)
.then(response => console.log(response.data))
.catch(() => console.log('Error creating new course'))
this.setState({
college: ''
})
}
render(){
return (
<div className="space3">
<h3>Add a Course to the Database</h3>
<form autoComplete="on" onSubmit={this.onSubmit} className="space">
<div className="form-group">
<label htmlFor="exampleInputEmail1">COLLEGE</label>
<select className="custom-select" id="inputGroupSelect01" >
<option defaultValue>Choose...</option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of
Agricultural and Environmental Sciences </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Humanities and Social Sciences </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Education and External Studies </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Health Sciences </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Natural Sciences </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Business and Management Studies </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Engineering, Design, Art and Technology </option>
<option value={this.state.college} onChange={this.onChangeCollege} > College of Veterinary Medicine, Animal Resources and Bio-Security </option>
<option value={this.state.college} onChange={this.onChangeCollege} > School of Law </option>
</select>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
)
}
}
export default Admin;
my backend is Nodejs which looks like this.
THE MODEL
const mongoose = require('mongoose')
const Courses = new mongoose.Schema({
college: {
type:String
}
})
module.exports = mongoose.model('coursesmodel', Courses)
THE API
const express = require ('express')
const router = express.Router()
const coursedb = require('../models/coursedb')
//add new todo to list
router.post('/admin', (request, response) => {
const list = new coursedb({
college: request.body.college
})
list.save()
.then(courses => {response.json(courses)})
.catch(error => {response.json(error)})
})
module.exports = router
As you can see in my console, that last console.log returns an empty string for the COLLEGE value.
And this is what it looks like in my MongoDB.
How do i store that COLLEGE input select option in my db as a String, like the rest, and not an empty String. Need help!
In the state, college is an empty string and in the JSX code, value of each options is this.state.college, i.e. an empty string and this is where your problem is.
Whenever onChangeCollege() is triggered, event.target.value is the value of the value attribute of the option element that triggered the onChange event, and in your case, it is this.state.college, i.e. an empty string and that is what you are sending to the server when form is submitted.
value attribute of the option element should be equal to the value of the option that is visible to the user. For example, you need to change
<option
value={this.state.college}
onChange={this.onChangeCollege}
>
College of Humanities and Social Sciences
</option>
to
<option
value="College of Humanities and Social Sciences"
onChange={this.onChangeCollege}
>
College of Humanities and Social Sciences
</option>
You need to do this for all of the option elements.
Side note: You don't need to add a separate onChange listener on each option, adding onChange event listener on the select element will achieve the same result.
<select
className="custom-select"
id="inputGroupSelect01"
onChange={this.onChangeCollege}
>
...
</select>
If you want to know why this works, see: MDN - Event Bubbling

Getting Flask to alter selected value in HTML drop down

I'm writing a prototype front end for a home heating control system and when the user selects the room and day of the week from the drop down box, I want to be able to query the Redis database and retrieve the currently set temperatures for each hour and use this to set the selected value in the temperature drop down boxes. The user can then change a value or values and submit them. I have the submit and write working, just trying to get my head around setting the selected.
Here's the HTML:
{% extends "bootstrap/base.html" %}
{% block title %}Setting Room Temperatures{% endblock %}
{% block navbar %}
<div class="navbar navbar-fixed-top">
<!-- ... -->
</div>
{% endblock %}
{% block content %}
</head>
<body>
<h1>Room temperature configuration</h1>
<form action="{{ url_for('heating_config_form')}}" method="post" class="form-inline">
<div class="form-group">
<label for="roomselect">Room:</label>
<select class="form-control" name="roomselect">
<option value="dining">Dining</option>
<option value="kitchen">Kitchen</option>
<option value="lounge">Lounge</option>
<option value="study">Study</option>
</select>
</div>
<br>
<br>
<div class="form-group">
<label for="dayselect">Day :</label>
<select class="form-control" name="dayselect">
<option value="monday">Monday</option>
<option value="tuesday">Tuesday</option>
<option value="wednesday">Wednesday</option>
<option value="thursday">Thursday</option>
<option value="friday">Friday</option>
<option value="saturday">Saturday</option>
<option value="sunday">Sunday</option>
</select>
</div>
<br>
<br>
<div class="form-group">
<label for="1AM">1AM :</label>
<select class="form-control" name="1AM">
<option value="5">5</option>
<option value="6">6</option>
</select>
<label for="2AM">2AM :</label>
<select class="form-control" name="2AM">
<option value="5">5</option>
<option value="6">6</option>
</select>
</div>
<br>
<br>
<button type="submit" value="submitted" name="update">Update temperature </button><br>
<br>
</form>
<br>
</body></html>
{% endblock %}<html><head>
And here's the Python Flask code
from flask import Flask
from flask import request
from flask import render_template
from flask_bootstrap import Bootstrap
import redis
app = Flask(__name__)
app.debug = True
bootstrap = Bootstrap(app)
db = redis.Redis('localhost')
#app.route('/', methods=['GET','POST'])
def heating_config_form():
error=""
if request.method == 'POST' and request.form['update'] == 'submitted':
Room = (request.form.get('roomselect'))
Day = (request.form.get('dayselect'))
AM1 = (request.form.get('1AM'))
AM2 = (request.form.get('2AM'))
key = (Room + "_" + Day)
db.hset(key, "1:00", AM1)
db.hset(key, "2:00", AM2)
return render_template('set-room-tempv5.html')
else :
return render_template('set-room-tempv5.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
I'm aware there are probably better ways of approaching this (WTForms?) but wanted to get a simple setting interface that I understand so I can prototype the system while developing a better front end, as I'm new to Flask and don't want the whole heating system to be dependent on my ability to pick this up :)
Adding the temperature to the database works fine, this is a typical monitor output from the redis-cli monitor
127.0.0.1:6379> monitor
OK
1482336847.287342 [0 127.0.0.1:34180] "HSET" "kitchen_tuesday" "1:00" "5"
1482336847.288042 [0 127.0.0.1:34180] "HSET" "kitchen_tuesday" "2:00" "5"
I was thinking that maybe something like the following context processor could help?
#app.context_processor
def utility_processor():
def retrieve_temp(sroom, sday, stime):
skey= (sroom + "_" + sday)
stemp = db.hget(skey, stime)
return stemp
return dict(retrieve_temp=retrieve_temp)
which would make the function retrieve_temp available to all templates - I think!
Then somehow, once the template is rendered, the default room and day is used to set the "selected" option on the time drop downs, and then every time the room and day drop downs are moved, the same happens again.
So if the default is dining and Monday given they are the first in the select options, the temperatures for 1AM and 2AM are retrieved and set as selected for these drop downs (there are more times and more temps, these have been deleted for brevity). If the room and/or the day is changed, it happens again.
OK - So just wanted to be sure on your question before I gave you information to solve the problem. The approach you've outline as an alternative in the comments is the easiest way to get this to work (e.g. intermediary page to make the first selection).
It's important to remember that any python or jinja2 code is only going to executed 1 time. Jinja2 uses some logic to render the HTML output and then Flask responds with a static HTML page to the browser, so you can use a context_processor to pass specific logic to jinja2, but once Flask renders the page any interactivity would need to be managed by javascript.
It looks like you are using Bootstrap, which includes jQuery javascript library. jQuery is great (in my opinion) because it handles some browser quirks for you in terms of how it interacts with and manipulates the DOM (e.g. the Document Object Model, javascript's representation of your HTML elements).
So, if you want to dynamically populate the second select you can design some code to asynchronously (e.g. without making another HTTP request or "reloading" the page) send data from the browser to a Flask endpoint to fetch the required options then update the front end. I'll give you an example:
HTML looks like this (I'm just adding ID's. The for tag is suppose to reference the ID field, not the name, and it also makes the javascript selection easier):
<div class="form-group">
<label for="roomselect">Room:</label>
<select class="form-control" name="roomselect" id="roomselect">
<option value="dining">Dining</option>
<option value="kitchen">Kitchen</option>
<option value="lounge">Lounge</option>
<option value="study">Study</option>
</select>
</div>
<div class="form-group">
<label for="dayselect">Day:</label>
<select class="form-control" name="dayselect" id="dayselect">
<option value="monday">Monday</option>
<option value="tuesday">Tuesday</option>
<option value="wednesday">Wednesday</option>
<option value="thursday">Thursday</option>
<option value="friday">Friday</option>
<option value="saturday">Saturday</option>
<option value="sunday">Sunday</option>
</select>
</div>
<div class="form-group">
<label for="1AM">1AM:</label>
<select class="form-control" name="1AM" id="1AM">
<option value="5">5</option>
<option value="6">6</option>
</select>
<label for="2AM">2AM:</label>
<select class="form-control" name="2AM" id="2AM" disabled>
<option value="5">5</option>
<option value="6">6</option>
</select>
</div>
Then, you need to add a javascript event listener and AJAX method, usually you do this in the bottom of the body of your HTML or in a linked file:
<script charset="utf-8" type="text/javascript">
// this is called a javascript closure. it also wont run the code until the page is finished loading
// and it protects the scope of your variables from other code you may later add to the page
$(function() {
var select_room = $('#roomselect'),
select_day = $('#dayselect'),
select_1am = $('#1am'),
select_2am = $('#2am');
select_room.on('change', function() {
// fires when room selection changes
getUpdatedSettings();
});
select_day.on('change', function() {
// fires when day selection changes
getUpdatedSettings();
});
function getUpdatedSettings() {
// data to send back to the server
var send = {
room: select_room.val(),
day: select_day.val()
};
// make the selections disabled while fetching new data
select_1am.attr('disabled', true);
select_2am.attr('disabled', true);
$.getJSON("/_get_updated_settings", send, function(response) {
// this send the room and the day select vals to the URL specified
// we will need to add a handler for this in Flask
// for the purpose of the example I am assuming the response will be
// a JSON object that has a dictionary of elements ("am_1" and "am_2")
// each of which is a list of values for the selects....
console.log(response); // good for QA!
// populate 1am
select_1am.empty();
$.each(response.am_1, function (index, value) {
select_1am.append(
$('<option>', {
value: value,
text: value
}, '</option>'))
});
// populate 2am
select_2am.empty();
$.each(response.am_2, function (index, value) {
select_2am.append(
$('<option>', {
value: value,
text: value
}, '</option>'))
});
// remove disabled now
select_1am.removeAttr('disabled');
select_2am.removeAttr('disabled');
});
}
});
</script>
Now, you need to add some Flask logic to handle this AJAX request:
from flask import jsonify
#app.route('/_get_updated_settings')
def get_updated_settings():
# good for debug, make sure args were sent
print request.args
day = request.args.get('day', 'default_if_none')
room = request.args.get('room', 'default_if_none')
key = (room + "_" + day)
output = {}
# I have no idea what this returns...just doing a list generator here assuming we get a list of values
output['am_1'] = [x for x in db.hget(skey, '1am')]
output['am_2'] = [x for x in db.hget(skey, '1am')]
return jsonify(output)
Ha...turned out a bit longer than I expected, but this should at the very least provide you with a straw man to get functionality like this working. Javascript definitely provides for a better user experience, but you can generally accomplish the same thing by having a series of intermediary forms that populate static pages.

Dynamic Dropdown in Node.js

Newbie to Node.js here:
What is an easy way to make dynamic dropdowns in node.js?
Basically, I have two tables: Skill and Skill_Category .
I want to select from the Skill_Category and be presented with the associated Skill.
I would assume I would need to use some template engine (to render in a webpage).
I tried researching a good amount on google, but didn't turn up anything that helped me.
If anyone can point me in the right direction?
Thank you!
So one dropdown will cause the other to show. Unless the second dropdown has hundreds of options you won't want to make a separate server side request to get it in. This means your logic should all be in the browser/client side.
This means you want your "Skill_Category" select box to have a JS function called to hide the current "Skill" select box and show the newly chosen "Skill" select box. They will all be rendered in html by your templating, but only one will ever be shown (display:block) while the others are hidden (display:none).
Sample HTML:
<select id="skill_category">
<option value="communication">Communication</option>
<option value="teamwork">Team Work</option>
<option value="technical">Technical</option>
</select>
<select class="skill" id="communciation">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<select class="skill" id="teamwork">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<select class="skill" id="technical">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
Sample Jquery code:
$('#skill_category').on('change',function(){
$('.skill').hide()
$('#'+this.value).show()
});
Update:
If you have a large list of options for the secondary select box then you can make an ajax (HTTP GET) request, and returning the lsit of dropdowns from your server as JSON.
You will probably have one of two scenarios: all of you skills in a static JSON file, or saved in a database.
Your node code will look like:
app.get('/skill_category/:skill', function(req, res){
//JSON file in the /public/skills directory
res.sendFile(__dirname + '/public/skills/'+req.params.skill+".json");
//or some database lookup followed by a json send:
var skills = someDatabaseLookup();
res.json(skills);
});
HTML
<select id="skill_category">
<option value="communication">Communication</option>
<option value="teamwork">Team Work</option>
<option value="technical">Technical</option>
</select>
<select id="skill">
</select>
while the jquery will now be:
$('#skill_category').on('change',function(){
$.get('skill_category/'+this.value,function(data){
for(var j = 0; j < length; j++)
{
$('#skill').contents().remove();
var newOption = $('<option/>');
newOption.attr('text', data[j].text);
newOption.attr('value', data[j].value);
$('#skill').append(newOption);
}
});
});
Do note this code is untested but should work

Resources