Display (map) list of messages nested in an object (MERN) - node.js

I am learning MERN and would like to display the list of messages from Mongo Database in React UI.
My UserSchema in Mongo:
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
messages: [
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
message: {
type: String,
required: true,
},
},
],
tokens: [
{
token: {
type: String,
required: true,
},
},
],
});
Code in Home.js in React:
import React, { useState, useEffect } from "react";
const Home = () => {
const [userName, setUserName] = useState({});
const [show, setShow] = useState(false);
const userHome = async () => {
try {
const res = await fetch("/userdata", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const data = await res.json(); //successfully getting complete json data in console.
console.log(data);
setUserName(data);
setShow(true);
} catch (err) {
console.log(err);
}
};
useEffect(() => {
userHome();
}, []);
return (
<>
<div className="page-wrap d-flex flex-row align-items-center">
<div className="container">
<div className="row justify-content-center">
<div className="col-md-12 text-center">
<span className="display-1 d-block">
<p> Welcome {show ? "Back!" : ""} </p>
<h1>{userName.name}</h1>
<h2>
{show
? "What you want to do today?"
: "Your own Portal.."}
</h2>
</span>
<div className="mb-4 lead">
{show
? ""
: "You need to register and login for accessing your profile."}
</div>
<div>
<div>Messages:{userName[0].message}</div>
{/* wants to display list of all message here */}
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default Home;
My approach to try fetching the list of all messages
I tried map method but not succeeded and tried below code still no success. Kindly advise. I want to display all the messages Message 1, Messag 2 etc. upon loading.
<div>Messages:{userName[0].message}</div>
Error Message in Browser:
TypeError: Cannot read properties of undefined (reading 'message')
I got it solved as below
Removed
<div>Messages:{userName[0].message}</div>
{/* wants to display list of all message here */}
</div>
Added:
<div>
{userName.messages?.map((msg1) => (
<li key={msg1._id}>{msg1.message}</li> ))}
</div>

can you delete this part:
<div>
<div>Messages:{userName[0].message}</div>
{/* wants to display list of all message here */}
</div>
and add this instead:
<div>{
data.map(result => (
<div key={result._id}>
<h2>{result.name}</h2>
<p>Some text: {result.messages}</p>
</div>
))
}</div>
If above code works, then you can tweak it to display your desired message which i think is this:
<p>Some text: {result.messages[0].message}</p>
Please let me know if it works.

Related

Vue Vee-validate select (dropdown list)

So I am using this input template I got from a tutorial #logaretm created, which works great for just about anything I need. I would like to know if there is a way to modify this template to validate as a Select (drop-down) and how would I populate the option values?
I looked at vee-validation documentation but haven't been able to figure this out on my own. Any help would with this is greatly appreciated.
<template>
<div
class="TextInput"
:class="{ 'has-error': !!errorMessage, success: meta.valid }"
>
<label :for="name">{{ label }}</label>
<input
:name="name"
:id="name"
:type="type"
:value="inputValue"
:placeholder="placeholder"
#input="handleChange"
#blur="handleBlur"
/>
<p class="help-message" v-show="errorMessage || meta.valid">
{{ errorMessage || successMessage }}
</p>
</div>
</template>
<script>
import { toRef } from "vue";
import { useField } from "vee-validate";
export default {
props: {
type: {
type: String,
default: "text",
},
value: {
type: String,
default: "",
},
name: {
type: String,
required: true,
},
label: {
type: String,
required: true,
},
successMessage: {
type: String,
default: "",
},
placeholder: {
type: String,
default: "",
},
},
setup(props) {
// use `toRef` to create reactive references to `name` prop which is passed to `useField`
// this is important because vee-validte needs to know if the field name changes
// https://vee-validate.logaretm.com/v4/guide/composition-api/caveats
const name = toRef(props, "name");
// we don't provide any rules here because we are using form-level validation
// https://vee-validate.logaretm.com/v4/guide/validation#form-level-validation
const {
value: inputValue,
errorMessage,
handleBlur,
handleChange,
meta,
} = useField(name, undefined, {
initialValue: props.value,
});
return {
handleChange,
handleBlur,
errorMessage,
inputValue,
meta,
};
},
};
</script>

Node JS | TypeError: Cannot read property 'p_nome' of undefined

Good afternoon, I am new to react and node.js and I have a problem.
I have a table on a web page where you will receive the data for a trip. The columns (Id locales, name, date, time) are present in the travel_order model, but the column "localities name" is intended to list the name of the localities using the id. The ids for this location are listed in the "Localities Id" column. However, when listing, it gives me the error: "TypeError: Cannot read property 'designacao' of undefined".
For a better understanding of the table, in the first line of data, 1 is the departure id and 124 is the arrival id. I've uploaded a photo of the table as well as the controller and models.
the insertion of the data in the table is done in the function loadFillData () present in this code:
import React from 'react';
import '../../../assets/css/Pagamentos.css'
import 'js-datepicker/dist/datepicker.min.css';
import '../../../assets/css/bootstrap.css';
import axios from 'axios';
import { data } from 'jquery';
const datepicker = require('js-datepicker');
class Pagina extends React.Component {
constructor(props) {
super(props);
this.state = {
pag_pendentes: []
}
}
componentDidMount() {
const picker = datepicker('#calendario', {
formatter: (input, date, instance) => {
input.value = new Intl.DateTimeFormat('en-GB').format(date)
}
});
const url = "http://localhost:3001/operadora/pendente";
axios.get(url)
.then(res=>{
if(res.data.success){
const data = res.data.data;
this.setState({pag_pendentes:data});
}else{
alert("Erro");
}
})
.catch(error=>{
alert(error)
});
}
render() {
return (
<div>
<div id="div-filtragem">
<label className="Label_DatePicker">Data inicio:</label>
<input placeholder="Selecione uma data" type="text" id="calendario" className="form-control DatePicker datepicker" style={{ width: "auto" }} />
<label className="Label_DatePicker">Data fim:</label>
<input placeholder="Selecione uma data" type="text" id="calendario" className="form-control DatePicker datepicker" style={{ width: "auto" }} />
<button type="button" className="ButtonFilter ">Filtrar</button>
</div>
<div className="div_tabela">
<table className="table tabela" >
<thead>
<tr>
<th scope="col">IDs localidades</th>
<th scope ="col">nome localidades</th>
<th scope="col">Nome</th>
<th scope="col">Data</th>
<th scope="col">Hora</th>
<th scope="col">Valor</th>
</tr>
</thead>
<tbody>
{this.loadFillData()}
</tbody>
</table>
</div>
</div>
);
}
loadFillData(){
console.log(this.state.pag_pendentes);
return this.state.pag_pendentes.map((data, index) => {
return (
<tr key ={index}>
<td className="td_viagem">{data.partida + "-"+data.chegada}</td>
<td>{data.pp.designacao + "-"+data.pc.designacao}</td>
<td>{data.pessoa.p_nome + " " +data.pessoa.u_nome}</td>
<td>{data.data_viagem}</td>
<td>{data.hora_viagem}</td>
<td>10€</td>
</tr>
)
});
}
}
export default Pagina;
The controller:
var Viagem = require('../../model/viagem');
var Pedido_viagem = require('../../model/pedido_viagem');
var Estado = require('../../model/estado');
var Pessoa = require('../../model/pessoa');
var Partida = require('../../model/freguesias');
var Chegada = require('../../model/freguesias');
const sequelize = require('../../model/database');
const op_pagamentos = {}
sequelize.sync()
op_pagamentos.pendentes = async(req,res) => {
const data = await Pedido_viagem.findAll({
include: [Viagem],
include: [Estado],
include:[{
model: Partida,
as:'pp',
attributes:['designacao']
},
{model: Chegada,
as:'pc',
attributes:['designacao']}],
include: [{
model: Pessoa,
attributes:['p_nome', 'u_nome']}],
where:{
estado : "3",
},
order :[[ 'id', 'asc' ]],
})
.then(function (data) {
return data;
})
.catch(error => {
console.log('Erro: ' + error);
return error;
});
res.json({success: true, data: data});
}
module.exports = op_pagamentos;
model pedido_viagem:
var Sequelize = require('sequelize');
var sequelize = require('./database');
var Municipe = require('./pessoa');
var Estado = require('./estado_pedido');
var Partida = require('./freguesias');
var Chegada = require('./freguesias');
var pedido_viagem = sequelize.define('pedido_viagem',{
id:{
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
municipe:{
type: Sequelize.INTEGER,
references:{
model:Municipe,
key:'id'
},
allowNull:false // coloca variável NOT NULL
},
partida:{
type: Sequelize.INTEGER,
references:{
model:Partida,
key:'id'
},
allowNull:false // coloca variável NOT NULL
},
chegada:{
type: Sequelize.INTEGER,
references:{
model:Chegada,
key:'id'
},
allowNull:false // coloca variável NOT NULL
},
data_viagem: {
type:Sequelize.DATE,
allowNull:false // coloca variável NOT NULL
},
hora_viagem:{
type:Sequelize.TIME,
allowNull:false // coloca variável NOT NULL
},
aceita_partilha:{
type:Sequelize.INTEGER,
allowNull:false // coloca variável NOT NULL
},
necessidades_especiais: {
type:Sequelize.INTEGER,
allowNull:false // coloca variável NOT NULL
},
bagagem: {
type:Sequelize.INTEGER,
allowNull:false // coloca variável NOT NULL
},
estado:{
type:Sequelize.INTEGER,
references:{
model: Estado,
key:'id'
}
}
},
{
timestamps: false,
freezeTableName: true
});
pedido_viagem.belongsTo(Municipe,{foreignKey:'municipe'});
pedido_viagem.belongsTo(Partida,{as:'pp',foreignKey:'partida'});
pedido_viagem.belongsTo(Chegada,{as:'pc',foreignKey:'chegada'});
module.exports= pedido_viagem;
model freguesias:
var Sequelize = require('sequelize');
var sequelize = require('./database');
var tipo_freguesia = require('./tipo_frequesia');;
var freguesia = sequelize.define('freguesias',{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
designacao: {
type:Sequelize.CHAR(50),
allowNull:false // coloca variável NOT NULL
},
localizacao: {
type: Sequelize.CHAR(100),
allowNull:false // coloca variável NOT NULL
},
zona: {
type:Sequelize.INTEGER,
allowNull:false // coloca variável NOT NULL
},
tipo_freguesia:{
type: Sequelize.INTEGER,
regerences:{
model:tipo_freguesia,
key:'id'
},
allowNull:false // coloca variável NOT NULL
}
},
{
timestamps: false,
freezeTableName: true,
});
module.exports = freguesia;
Log file:
Node.js Log:
Please, thank you very much if anyone can help me. I am a beginner and I do not understand why I am getting this error.
Greetings to all.
The problem lies here:
include: [Viagem],
include: [Estado],
include:[{
model: Partida,
as:'pp',
attributes:['designacao']
},
{model: Chegada,
as:'pc',
attributes:['designacao']}],
include: [{
model: Pessoa,
attributes:['p_nome', 'u_nome']}]
You are overwriting include which will resolve to use only last one, instead you should use the include as an array:
include: [Viagem, Estado, {
model: Partida,
as:'pp',
attributes:['designacao']
},
{model: Chegada,
as:'pc',
attributes:['designacao']}, {
model: Pessoa,
attributes:['p_nome', 'u_nome']}]

Is mapDispatchToProps the way to go?

I am following a tutorial for a React+Redux fullstack and the instructor did something strange that is not working for me.
Specifically these lines, in the submitForm() class:
this.props.dispatch(registerUser(dataToSubmit))
.then(response =>{
Are causing error:
TypeError: this.props.dispatch(...).then is not a function
This is the whole class:
import React, { Component } from 'react';
import FormField from '../utils/Form/formfield';
import { update, generateData, isFormValid } from '../utils/Form/formActions';
import { connect } from 'react-redux';
import { registerUser } from '../../actions/user_actions';
class Register extends Component {
state = {
formError: false,
formSuccess:false,
formdata:{
name: {
element: 'input',
value: '',
config:{
name: 'name_input',
type: 'text',
placeholder: 'Enter your username'
},
validation:{
required: true
},
valid: false,
touched: false,
validationMessage:''
},
email: {
element: 'input',
value: '',
config:{
name: 'email_input',
type: 'email',
placeholder: 'Enter your email'
},
validation:{
required: true,
email: true
},
valid: false,
touched: false,
validationMessage:''
},
password: {
element: 'input',
value: '',
config:{
name: 'password_input',
type: 'password',
placeholder: 'Enter your password'
},
validation:{
required: true
},
valid: false,
touched: false,
validationMessage:''
},
confirmPassword: {
element: 'input',
value: '',
config:{
name: 'confirm_password_input',
type: 'password',
placeholder: 'Confirm your password'
},
validation:{
required: true,
confirm: 'password'
},
valid: false,
touched: false,
validationMessage:''
}
}
}
updateForm = (element) => {
const newFormdata = update(element,this.state.formdata,'register');
this.setState({
formError: false,
formdata: newFormdata
})
}
submitForm= (event) =>{
event.preventDefault();
let dataToSubmit = generateData(this.state.formdata,'register');
let formIsValid = isFormValid(this.state.formdata,'register')
if(formIsValid){
this.props.dispatch(registerUser(dataToSubmit))
.then(response =>{
if(response.payload.success){
this.setState({
formError: false,
formSuccess: true
});
setTimeout(()=>{
this.props.history.push('/register_login');
},3000)
} else {
this.setState({formError: true})
}
}).catch(e => {
this.setState({formError: true})
})
} else {
this.setState({
formError: true
})
}
}
render() {
return (
<div className="page_wrapper">
<div className="container">
<div className="register_login_container">
<div className="left">
<form onSubmit={(event)=> this.submitForm(event)}>
<h2>Personal information</h2>
<div className="form_block_two">
<div className="block">
<FormField
id={'name'}
formdata={this.state.formdata.name}
change={(element)=> this.updateForm(element)}
/>
</div>
</div>
<div>
<FormField
id={'email'}
formdata={this.state.formdata.email}
change={(element)=> this.updateForm(element)}
/>
</div>
<h2>Verify password</h2>
<div className="form_block_two">
<div className="block">
<FormField
id={'password'}
formdata={this.state.formdata.password}
change={(element)=> this.updateForm(element)}
/>
</div>
<div className="block">
<FormField
id={'confirmPassword'}
formdata={this.state.formdata.confirmPassword}
change={(element)=> this.updateForm(element)}
/>
</div>
</div>
<div>
{ this.state.formError ?
<div className="error_label">
Please check your data
</div>
:null}
<button onClick={(event)=> this.submitForm(event)}>
Create an account
</button>
</div>
</form>
</div>
</div>
</div>
</div>
);
}
}
export default connect()(Register);
So, I tried to add both:
mapDispatchToProps = (dispatch) => {
return {
registerTheUser: (submitData) => {dispatch(registerUser(submitData)) }
}
and
export default connect(mapDispatchToProps)(Register);
then changed:
this.props.dispatch(registerUser(dataToSubmit))
.then(response =>{
to
this.props.registerTheUser(dataToSubmit)
.then(response =>{
However, that also didn't work.
I am at a complete loss as to what it is I need to do. Is mapDispatchToProps() even the strategy I should be taking to fix this?
I can add more code if necessary.
EDIT, action registerUser():
export function registerUser(dataToSubmit){
const request = axios.post(`http://localhost:4444/users/create`,dataToSubmit)
.then(response => response.data);
return {
type: REGISTER_USER,
payload: request
}
}
mapDispatchToProps is the second argument to connect, the first argument is mapStateToProps
To supply just mapDispatchToProps, you must pass the first argument as null like
export default connect(null, mapDispatchToProps)(Register);
then use it like
this.props.registerTheUser(dataToSubmit)
.then(response =>{
Also the first way is correct, however your dispatch action isn't returning a promise and hence .then cannot be executed on it.
Make sure you use redux-thunk middleware and return a promise
const registerUser = (data) => {
return dispatch => {
return API.register('/url', data) // a return statement here for returning promise
}
}

Vuetify v-data-table search.filter not showing any results

Getting data back from our API but built in Vuetify search/filter is not working. I think it has to do with the data coming back being nested in an object. When typing in the search filter i get "No matching records found" after the first character, when removing the search term the full data table is displayed. Thanks in advance for any help.
<template>
<v-container
fill-height
fluid
grid-list-xl
>
<v-layout
justify-center
wrap
>
<v-flex
md6
>
<material-card
color="black"
title="Users"
>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
<v-data-table
:headers="headers"
:items="userData"
:search="search"
hide-actions
>
<template
slot="headerCell"
slot-scope="{ header }"
>
<span
class="subheading font-weight-light text-dark text--darken-3"
v-text="header.text"
/>
</template>
<template
slot="items"
slot-scope="{ item }"
>
<td>
<v-avatar slot="offset" class="mx-auto d-block" size="100">
<img v-if="item.ProfileImage==null" src="img/conectrlogo.jpg">
<img v-else v-bind:src= "item.ProfileImage">
</v-avatar></td>
<td><v-btn text-small outlined color="primary" #click= "goToUserProfile(item.Id)">{{ item.Id}}</v-btn></td>
<td>{{ item.Username}}</td>
<td>{{ item.Name}}</td>
</template>
</v-data-table>
</material-card>
</v-flex>
</v-layout>
</v-container>
</template>
Script
<script>
import axios from 'axios'
export default {
mounted()
{
console.log("got into mounted function");
this.getResults();
},
data () {
return {
customFilter: function (items, search, filter, headers) {
search = search.toString().toLowerCase()
if (search.trim() === '') return items
const props = headers.map(h => h.value)
return items.filter(item => props.some(prop => filter(getObjectValueByPath(item, prop, item[prop]), search)))
},
userData:[],
totalUsers:0,
showResults:true,
search:'',
headers:[
{
text: 'User',
value: 'profileimage',
align: 'center',
width: '50px',
sortable:false
},
{
text: 'id',
value: 'id',
align: 'center',
width: '100px',
sortable:false
},
{
text: 'Username', value: 'username',
align: 'left',
sortable: false,
width: '50px'
},
{
text: 'Name', value: 'name',
align: 'left',
sortable: true,
width: '50px'
}
]
}
},
computed:{
},
methods: {
goToUserProfile: function(Id)
{
console.log("avatar clicked:"+Id);
this.$router.push('/user-profile/'+Id)
},
getResults (){
console.log("got into the all users endpoint");
console.log(this.$baseUrl+'/admin/users');
// axios.get(this.$baseUrl+'/admin/users',
// {withCredentials: true}).then ( response => {
// this.userData=response.data.Users;
// this.totalUsers = response.data.UserCount;
// console.log("all user response:"+this.userData);
// });
//this.showResults=true;
axios.defaults.withCredentials = true;
axios(this.$baseUrl+'/admin/users', {
method: 'GET',
withCredentials: true,
crossDomain:true
}).then(res => {
console.log(res);
this.userData=res.data.Users;
this.totalUsers = res.data.UserCount;
console.log("all user response:"+this.userData);
}).catch(err => {
console.log("got an error");
console.log(err);
})
},
initialize()
{
},
}
}
</script>

build schema correct in mongoDB/mongoose

I'm trying to make a poll vote app.
My big problem is that I can't make an array of objects and access them. I try to make a few option votes to one poll like that:
title:"question?"
option:content:"1 answer",vote:0
content:"2 answer",vote:0
content:"3 answer",vote:...
and build schema like that:
var mongoose = require("mongoose");
var pollSchema = new mongoose.Schema({
title: String,
maker :{
id:{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
options:[{content: String,vote:{type:Number,default:0}}]
});
module.exports = mongoose.model("Poll",pollSchema);
and get the data from there:
<div class="form-group" id="option">
<label for="Option 1">Options</label>
<input type="text" class="form-control" name="options[content]" placeholder="Option 1">
<input type="text" class="form-control" name="options[content]" placeholder="Option 2">
</div>
and the output in mongoDB is:
{
"_id": {
"$oid": "5993030dc5fa8c1b4f7eb176"
},
"title": "Some question?",
"options": [
{
"content": "opt 1,opt 2",
"_id": {
"$oid": "5993030dc5fa8c1b4f7eb177"
},
"vote": 0
}
],
"maker": {
"username": "Naor Malca"
},
"__v": 0
}
I want each option to have separate content, id and vote.
maybe i input the data worng?or the schema is worng?
UPDATE:
This my route code:
//NEW POLL ROUTE
app.post("/",function(req, res){
var title = req.body.title;
var options = req.body.options;
var maker = req.body.maker;
var newPoll = {title:title,options:options,maker:maker};
Poll.create(newPoll,function(err,poll){
if(err){
res.send("create error");
} else{
res.redirect("/");
}
});
});
still not working this the output:(its make the text an array not a array of objects...)
{ _id: 5993fcad9a63350df274b3e5,
title: '111',
__v: 0,
options: [ { text: '222,333', _id: 5993fcad9a63350df274b3e6, vote: '0' } ],
maker: { username: 'naor' } }
When you build your form, add [number] so that each option is different.
<div class="form-group" id="option">
<label for="Option 1">Options</label>
<input type="text" class="form-control" name="options[0][content]" placeholder="Option 1" value="value1">
<input type="text" class="form-control" name="options[1][content]" placeholder="Option 2" value="value2">
</div>
That way when you submit the form, it should come back as array of objects
req.body.options = [
{ content: 'value1' },
{ content: 'value2' }
]
This is a typical approach when you build an "add" form containing grouped elements.
--
When it comes to an "edit" form such that you want to update existing options, you can pass the option's _id
Here's an example using EJS
<div class="form-group" id="option">
<label for="Option 1">Options</label>
<% poll.options.forEach(option => { %>
<input type="text" class="form-control" name="options[<%= option._id %>][content]" placeholder="Option 1" value="<%= option.content %>">
<% }) %>
</div>
Here req.body.options should be an object
req.body.options = {
'some-id': {
content: 'value1'
},
'another-id': {
content: 'value2'
}
}
When you save, you would iterate over the object with the key i.e. _id. I think you can make use of id() to find the object to set.
--
If it doesn't come back in the formats mentioned above, you most likely need to use and set the bodyParser.

Resources