Is mapDispatchToProps the way to go? - node.js

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
}
}

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>

Display (map) list of messages nested in an object (MERN)

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.

how can I store 4input data to anoptions array?

this is my react code where I want to create polls using react form but I don't understand what goes wrong with my code...!`Here I have 4 input field with { option1: "", option2: "", option3: "", option4: "" }, but I don't know how to store data just like I store data using POSTMAN...!CAN ANYONE HELP PLEASE help....!PLEASE HEPL I DO NOT UNDERSTAND WHAT TO DO...! WITH MY CODE
HELP PLEASE......
import React, { useState, useEffect } from "react";
import "../styles.css";
import { isAutheticated } from "../auth/helper/index";
import { createaPoll } from "./helper/adminapicall";
const AddPoll = () => {
const { user, token } = isAutheticated();
const [value, setValue] = useState({
question: "",
options: { option1: "", option2: "", option3: "", option4: "" },
error: "",
loading: "false",
getRedirect: false,
formData: "",
});
const { question, options, error, loading, getRedirect, formData } = value;
const handleChange = (event) => {
// setError("");
setValue({ ...value, [event.target.name]: event.target.value });
// console.log(event.target.value);
const newOption = {
...value.options,
[event.target.name]: event.target.value,
};
setValue((prev) => ({ ...prev, options: newOption }));
};
const onSubmit = (event) => {
event.preventDefault();
setValue({ ...value, error: "", loading: true });
// console.log(handel);
createaPoll(user._id, token, { question, options }).then((data) => {
if (data.error) {
setValue({ ...value, error: data.error });
} else {
setValue({
...value,
question: "",
options: { option1: "", option2: "", option3: "", option4: "" },
error: "",
loading: "false",
getRedirect: false,
formData: "",
});
}
});
};
return (
<div className="AddPoll">
<div className="container">
<h1>Add New Poll</h1>
<form>
<textarea
rows="4"
cols="50"
className="form-control mb-2"
placeholder="Question"
name="question"
value={question}
onChange={(event) => handleChange(event)}
autoFocus
></textarea>
<input
type="text"
className="form-control mb-2"
placeholder="Option1"
onChange={(event) => handleChange(event)}
name="option1"
value={options.option1}
/>
<input
type="text"
className="form-control mb-2"
placeholder="Option2"
onChange={(event) => handleChange(event)}
name="option2"
value={options.option2}
/>
<input
type="text"
className="form-control mb-2"
placeholder="Option3"
onChange={(event) => handleChange(event)}
name="option3"
value={options.option3}
/>
<input
type="text"
className="form-control mb-2"
placeholder="Option4"
onChange={(event) => handleChange(event)}
name="option4"
value={options.option4}
/>
<button type="submit" onClick={onSubmit} className="btn Submitbtn">
Submit
</button>
</form>
</div>
</div>
);
};
export default AddPoll;
And when I did with POSTMAN it's work fine! Here is my POSTMAN IMAGE
so I don't understand what to do, with my react form code , can anyone help me please....!
Try to separate question and option values in handleChange function.
const handleChange = event => {
if (event.target.name === 'question') {
setValue({ ...value, [event.target.name]: event.target.value });
} else {
const newOption = {
...value.option,
[event.target.name]: event.target.value
};
setValue({ ...value, option: newOption });
}
};
try this :
const [value, setValue] = useState({
question: "",
option: [ option1: "", option2: "", option3: "", option4: "" ],
error: "",
loading: "false",
getRedirect: false,
formData: "",
});
const onSubmit = (event) => {
event.preventDefault();
setValue({ ...value, error: "", loading: true });
// console.log(handel);
createaPoll(user._id, token, { question, option }).then((data) => {
if (data.error) {
setValue({ ...value, error: data.error });
} else {
setValue({
...value,
question: "",
option: ["hello","hi","hey"],
error: "",
loading: "false",
getRedirect: false,
formData: "",
});
}
});
};

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']}]

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>

Resources