Save innerHTML data and input data to firebase - reactjs

I have this code where I want to save data to firebase. I want to be able to save selected meeting to firebase along with input in form. I am new to react and stuck at the moment to get further with my code so some suggestions what I can do would be much appreciated.
This is how my app looks like and with error
I have conected firebase and I am able to push up data but cant save data from my properties as handleClick..
Error when I try to submit form
import './App.css';
import firebase from 'firebase';
const uuid = require('uuid');
class App extends Component {
constructor(props) {
super(props);
// gör strängar av state
this.state = {
uid: uuid.v1(),
meeting:'',
name:'',
email:'',
};
// binder propertys till click funktion
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.inputData = this.inputData.bind(this);
// kopplar databas
var config = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
};
firebase.initializeApp(config);
// console.log(firebase);
// skapar databasen lokalt med referens ref
var database = firebase.database();
var ref = database.ref('meeting');
// variabel data med sträng id
var data ={
id: '',
}
// Pushar upp data till databas
ref.push(data);
}
// hämtar klick för mötes knappar och skriver ut text i knappar
handleClick = (e) =>{
console.log(e.target.innerHTML);
alert('Du har valt ett möte');
}
// hämtar API för olika möten
componentDidMount(){
fetch('http://www.mocky.io/v2/5c9cdca03300004d003f2151')
.then(res => res.json())
.then(json => {
let meetings = []
json.forEach(meeting => {
if(new Date(meeting.startDate).getDay() !== new Date(meeting.endDate).getDay()){
let day1 = {
activity:meeting.activity,
location:meeting.location,
startDate:meeting.startDate,
}
let day2 = {
activity:meeting.activity,
location:meeting.location,
endDate:meeting.endDate,
}
meetings.push(day1,day2)
}else{
meetings.push(meeting)
}
});
console.log(meetings)
this.setState({
isLoaded:true,
items: meetings,
})
});
// import firebase och ref sträng
firebase
.database()
.ref(`Newdata/${this.state.uid}`)
.on('value', snap => console.log('from db', snap.val()));
}
// hämtar ny data
handleChange(e){
this.setState({
name: e.target.name});
}
// hämtar ref och skriver ut sträng med set till firebase
handleSubmit(e){
alert('Er bokning är bekräftad: ' + this.state.value);
console.log('Du har bekräftat er bokning')
e.preventDefault();
firebase
.database()
.ref(`Newdata/${this.state.uid}`)
.set({
meeting: this.state.meeting,
name: this.state.name,
email: this.state.email,
})
.catch(error => console.log(error));
}
// knyter input text till property
inputData (_e){
const meeting = this.refs.meeting1.value;
const name = this.refs.name1.value;
const email = this.refs.email1.value;
this.setState({ meeting, name, email});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded){
return <div>Loading...</div>;
}
else {
return (
<>
<div className="App">
<div className="AppHeader">
<h1>Boka ditt möte nedan</h1>
</div>
<ul>
{items.map((item,i) => (
<li key={i}>
{/* kopplar handleClick till onChange*/}
<button onClick={(e) => this.handleClick(e)} onChange={this.inputData} ref="meeting1" className="select">
{item.activity}<br/>
Starttid: {item.startDate}<br/>
Sluttid: {item.endDate}<br/>
Plats: {item.location}<br/>
</button>
</li>
))}
</ul>
</div>
<div className="selectedMeeting">Fyll i dina uppgifter och bekräfta</div>
<form onSubmit={this.handleSubmit} className="bookingSection">
<label>
Name:
<input type="text" value={this.state.name} onChange={this.inputData}
ref="name1"/>
</label>
<label>
E-mail:
<input type="text" value={this.state.email} onChange={this.inputData}
ref="email1"/>
</label>
<input className="confirm" type="submit" value="Bekräfta" />
</form>
<div className="viewSelect"></div>
</>
);
}
}
}
export default App;
I get an error when I try to save the meeting, name, email to firebase.

By default the database is only accessible to authenticated users.
'rules': {
'.read': 'auth != null',
'.write': 'auth != null'
}
You have to define the rules on the Firebase console
You can allow to read or write the databse to everyone under development and then if needed add more rules (I suggest you to get familiar with the firebase rules):
'rules': {
'.read': true,
'.write': true
}
This should solve your issue for now.
Also, if you are new to React, I suggest you to learn to use Redux and combine it with React Redux Firebase, these will help you a lot alongside with React.

You can find the full explanation to this problem in Stackoverflow answer . It is also explained how to handle proper sign-In correctly.

Related

Formik form won't submit multiple times consecutively (CRUD app built with React and Firebase)

I've built a recipe app with React and Firebase, and I'm encountering a bug where I'm unable to edit a selected recipe more than once in a row. I can edit it once, but if I open the edit form again and try to submit it, it doesn't go through.
If I select a different recipe (even without reopening the form) and then return to the original one, I'm able to submit an edit again without issue.
When the submission fails, I see the following warning in the console:
Warning: An unhandled error was caught from submitForm() TypeError: Cannot read properties of undefined (reading 'indexOf')
at Function.value (index.esm2017.js:1032:19)
at Qm (index.esm2017.js:16035:32)
at firestore.js:80:17
at c (regeneratorRuntime.js:72:17)
at Generator._invoke (regeneratorRuntime.js:55:24)
at Generator.next (regeneratorRuntime.js:97:21)
at Ve (asyncToGenerator.js:3:20)
at o (asyncToGenerator.js:22:9)
at asyncToGenerator.js:27:7
at new Promise (<anonymous>)
Here's the GitHub repo, and the live site. Use the "demo" button to log in anonymously.
I apologize if this is too broad. I toyed with trying to recreate the issue on a smaller scale in CodeSandbox, but to do so, I think I'd have to rebuild a large portion of the app.
Because the issue resolves upon selecting a different recipe, I suspect it has to do with the selectedRecipe value in the app's state. However, I'm not sure exactly where the "indexOf" in the console warning is coming from.
The recipe form component:
import { useContext, useState, useEffect } from "react";
import { recipeContext } from "../../context/recipeContext";
import { Formik, Field, Form } from "formik";
import { modes } from "../modals/modalModes";
import { addRecipeToDb, updateRecipeInDb } from "../../firebase/firestore";
import * as Yup from "yup";
function RecipeForm({ modalMode, toggleModal, user }) {
const { selectedRecipe, setSelectedRecipe } = useContext(recipeContext);
const [formValues, setFormValues] = useState(null);
// Array => string separated by newlines
const convertFromArray = (array) => {
let string = "";
array.forEach((str, index) => {
if (index < 1) {
string = string + str;
} else string = string + "\n" + str;
});
return string;
};
// String separated by newlines => array
const convertToArray = (string) => {
return string.split("\n");
};
const handleSubmit = async (values) => {
const recipe = {
title: values.title,
description: values.description,
ingredients: convertToArray(values.ingredients),
directions: convertToArray(values.directions),
uid: user.uid,
};
if (modalMode === modes.create) {
recipe.labels = [];
recipe.createdAt = new Date();
await addRecipeToDb(recipe);
setSelectedRecipe(recipe);
console.log(recipe);
} else if (modalMode === modes.edit) {
recipe.labels = selectedRecipe.labels;
recipe.createdAt = selectedRecipe.createdAt;
await updateRecipeInDb(recipe, selectedRecipe.id);
setSelectedRecipe(recipe);
}
toggleModal();
};
const initialValues = {
title: "",
description: "",
ingredients: "",
directions: "",
};
useEffect(() => {
if (selectedRecipe && modalMode === modes.edit) {
setFormValues({
title: selectedRecipe.title,
description: selectedRecipe.description,
ingredients: convertFromArray(selectedRecipe.ingredients),
directions: convertFromArray(selectedRecipe.directions),
});
}
}, [modalMode, selectedRecipe]);
const validationSchema = Yup.object({
title: Yup.string()
.max(80, "Title must be less than 80 characters")
.required("Required"),
description: Yup.string().max(
400,
"Description must be less than 400 characters"
),
ingredients: Yup.string()
.max(
10000,
"That's a lot of ingredients! The limit is 10,000 characters."
)
.required("Required"),
directions: Yup.string()
.max(
10000,
"This recipe is too complicated! The limit is 10,000 characters."
)
.required("Required"),
});
return (
<Formik
initialValues={formValues || initialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
enableReinitialize>
{({ errors, touched }) => (
<Form id="recipe-form" className="form recipe-form">
<div className="field-wrapper">
<label htmlFor="title">Title</label>
<div className="error">{touched.title ? errors.title : null}</div>
<Field id="title" name="title" placeholder="Cake" as="input" />
</div>
<div className="field-wrapper">
<label htmlFor="description">Description</label>
<div className="error">
{touched.description ? errors.description : null}
</div>
<Field
id="description"
name="description"
placeholder="A real cake recipe"
as="textarea"
/>
</div>
<div className="field-wrapper">
<label htmlFor="ingredients">Ingredients</label>
<p className="error">
{touched.ingredients ? errors.ingredients : null}
</p>
<Field
id="ingredients"
name="ingredients"
placeholder="milk
eggs
flour
sugar"
as="textarea"
/>
<p className="message">Type each ingredient on a new line</p>
</div>
<div className="field-wrapper">
<label htmlFor="directions">Directions</label>
<p className="error">
{touched.directions ? errors.directions : null}
</p>
<Field
id="directions"
name="directions"
placeholder="Mix everything together
Bake at 350 degrees for 30 minutes
Let cool
Serve"
as="textarea"
/>
<p className="message">Type each step on a new line</p>
</div>
</Form>
)}
</Formik>
);
}
The function that updates the recipe in Firestore:
const updateRecipeInDb = async (recipeObj, id) => {
const docRef = doc(db, "recipes", id);
try {
updateDoc(docRef, recipeObj);
} catch (e) {
console.error("Error updating document: ", e.message);
}
};
I've messed around with several things over the past few days. Adding selectedRecipe to the form component's useEffect dependency list didn't make a difference, nor did removing the validation schema. I just can't figure out exactly what's going wrong, or where the problem is occurring. Has anyone encountered something similar, or is there something obvious I'm missing?

Updating a nested array element in React setState

I am maintaining an array of objects which is stored in a state object. Basically I am pushing each object to this array whenever I click on Add button .This stores this object in array.
I am maintaining a flag updateButtonFlag to show the update button for that particular account.
I want to update this flag of an account that just got submitted(that is in onAddAccount() function).
After addition , a new card gets displayed with input fields, so that next user details can be entered
Help would be appreciated
//Have included only onAddAccount function ,where the logic needs to go.
//There is a fetch call as well, which basically displays accounts info if there are any accounts w.r.t to that user
import * as React from 'react';
interface IState{
users : Account[];
user: Account
}
interface Account{
name: string;
email: string;
phone: string;
updateButtonFlag: boolean
}
export default class App extends React.Component<{},IState> {
constructor(props:any){
super(props);
this.state= {
users: [],
user: null
}
}
async componentDidMount(){
let useraccounts = await this.fetchAccounts(); // call that returns accounts, if present
let id:any, account: IAccount ;
if(useraccounts.length === 0) // if no account, display an empty card
{
this.setState({ accounts: [...this.state.accounts, {firstname:'',lastname:'',phone:'',updateButtonFlag: false}]},()=>{});
}
if(useraccounts.length > 0) // if there are accounts existing, display themand add update button to them
{
let accountArray = [];
for(let i=0;i<useraccounts.length;i++)
{
account = {
firstsname: useraccounts[i].firstsname,
lastname: useraccounts[i].lastname,
phone: useraccounts[i].phone,
updateButtonFlag: true
}
accountArray.push(account);
}
this.setState(({accounts}) => ({accounts: [...accounts, ...accountArray]}),()=>{});
}
}
onAddAccount = (index:number) => { // this adds one more card with input fields after submission of current user info
let { users } = this.state;
let account : IAccount = {firstname: users[index].firstname, lastname: users[index].lastname , phone: users[index].phone, updateButtonFlag:false} // maintaining a updateflag to show update button for the corresponding account
this.submit(account); // submit call to submit the account details
//here i need to update the flag of currently submitted account to true, so that update button gets shown , how to do it?
this.setState((prevState) => ({
users: [ ...prevState.users, {firstname:'',lastname:'',phone:''updateButtonFlag:false} ],
}));
} // in this line,next card gets added here
}
renderAccounts = (users: Account[]) => {
return accounts.map((value, index) => {
return (
<div key={index}>
<div>
<form>
<label>First Name:</label>
<input
type="text"
name="firstname"
value={value.firstname}
onChange={e => this.handleChange(e, index)}
required
/>
<label>Last Name:</label>
<input
type="text"
name="lastname"
value={value.lastname}
onChange={e => this.handleChange(e, index)}
/>
<label>Age:</label>
<input
type="text"
name="age"
value={value.age}
onChange={e => this.handleChange(e, index)}
required
/>
<div>
<button onClick={() => this.onAddAccount(index)}>
Save & Add Another Account
</button>
{users[index].updatedButtonFlag?<button onClick={() => this.onUpdateAccount(index)}>
Update Account
</button> :null}
<button onClick={() => this.onRemoveAccount(index)}>
Remove Account
</button>
)}
</div>
</form>
</div>
</div>
);
});
};
render() {
return <div>{this.renderAccounts(accounts)}</div>;
}
}
}
Following what I saw on this thread, you cannot use setState to update nested objects. So, in your case, you'll have to update the entire array.
onAddAccount = (index:number) => {
let { users } = this.state;
let account : IAccount = {firstname: users[index].firstname, lastname: users[index].lastname , phone: users[index].phone, updateButtonFlag:false}
this.submit(account);
users[index].updateButtonFlag = true;
users.push({firstname:'',lastname:'',phone:'',updateButtonFlag:false}); // Add an empty account
this.setState({
users: users,
}));
}

Function CollectionReference.add() requires its first argument to be of type object, but it was: undefined

I want to store the image in firebase storage and pass its URL reference in firestore. So I'm able to upload an image in storage but unable to pass the image URL reference in cloud firestore.
import React , {Component} from 'react';
import fire from './../fire'
import Uploadimg from './Uploadimg'
class Adproduct extends Component{
geturl = (imurl) =>{
this.setState({
img:imurl
});
}
submit = e =>{
e.preventDefault()
var db= fire.firestore();
db.settings({
timestampsInSnapshots: true
});
db.collection('newproducts').add(this.State)
.then(res =>{
console.log(res.id)
this.props.submit()
})
.catch(err =>{
console.log('something went wrong',err)
})
}
takedata = e =>{
this.setState({
[e.target.name]: e.target.value
});
}
constructor(props){
super(props);
this.state ={
name:'',
productdetails:'',
size:'',
}
}
render() {
return (
<div className="container w3-padding">
<div className="row w3-padding">
<div className="col-md-6 w3-padding">
<h3 className="w3-tag w3-padding w3-center">Add New</h3>
<form className="w3-container" onSubmit={this.submit}>
<label className="w3-text-blue"><b>Name</b></label>
<input className="w3-input w3-border" type="text" name="name" value={this.state.name} onChange={this.takedata} required/>
<label className="w3-text-blue"><b>productdetails</b></label>
<input className="w3-input w3-border" type="text" name="productdetails" value={this.state.productdetails} onChange={this.takedata} required/>
<label className="w3-text-blue"><b>size available</b></label>
<input className="w3-input w3-border" type="text" name="size" value={this.state.size} onChange={this.takedata} required/>
<br/>
<Uploadimg geturl={this.geturl} />
<br/>
<button className="w3-btn w3-blue">Add</button>
</form>
</div>
</div>
</div>
);
}
}
export default Adproduct;
If the accepted answer doesn't help you, you might be having the same issue I was having.
I solved this by using the typescript spread operator:
add(wizard: Wizard): Promise<DocumentReference> {
return this.wizardCollection.add({...wizard});
}
Hope this helps you.
use
db.collection('newproducts').add({...this.State})
instead of
db.collection('newproducts').add(this.State)
it can happen if you forgot to create database in the project...
Its happen to me - I copy the project secret key - but forgot to actually create database in the project.... after I create the DB - it solved...
It simply works for me.
Go in Database -> Rules ->
Change allow read, write: if false; to true;
It can happen because either you have not created any database or have no permission to read/write on the database from Under Rules tab i.e,
{
"rules": {
".read": true,
".write": true
}
}
You should create the Firestore database, allow the read, write rules, and configure it to your project. Then you can use the spread operator as below to save.
saveStudent(student: Student) {
return new Promise<Student> ((resolve, reject) => {
this.fireStore.collection('students').add({...student}).then(res => {}, err => reject(err));
});
}
From the documentation
To use a custom class, you must define a FirestoreDataConverter function for your class. For example:
class City {
constructor (name, state, country ) {
this.name = name;
this.state = state;
this.country = country;
}
toString() {
return this.name + ', ' + this.state + ', ' + this.country;
}
}
// Firestore data converter
var cityConverter = {
toFirestore: function(city) {
return {
name: city.name,
state: city.state,
country: city.country
}
},
fromFirestore: function(snapshot, options){
const data = snapshot.data(options);
return new City(data.name, data.state, data.country)
}
}
Call your data converter with your write operation:
// Set with cityConverter
db.collection("cities").doc("LA")
.withConverter(cityConverter)
.set(new City("Los Angeles", "CA", "USA"));

Using Reactjs to show Json response data on each form submission

How can I use Reactjs list records response on each form submission.
I have searched for previous post on this on stackoverflow but most solution I found does not address my issue.
The code below works but only list one record or
replace already existing displayed data on each form submission.
Here is what I want to achieve.
If I submit form 4 times am supposed to have 4 records displayed
For Instance
uid filename
1 macofile
2 johnfile
3 lukefile
4 tonyfile
But what this code does is to replace already existing record on each form submission and
as a result, it only show just one records
Eg. on 4th form submission it shows only
4 tonyfile
In angularjs I use something like push function to actualize my goal as per code below
$scope.users.push(res.data[0]);
In reactjs if I try the code below
const users = users.push(res.data);
//const users = users.push(res.data[0]);
it will show error
Cannot read property 'push' of undefined
Here is the code
import React, { Component } from "react";
import axios, { post } from "axios";
class FilePage extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "",
filename: "",
loading: false,
users: [],
error: null
};
this.handleChange = this.handleChange.bind(this);
}
_handleSubmit(e) {
e.preventDefault();
//send it as form data
const formData = new FormData();
formData.append("filename", this.state.filename);
//alert(this.state.filename);
this.setState({ loading: true }, () => {
axios
.post("http://localhost/apidb_react/up.php", formData)
.then(res => {
//const users = res.data;
//const users = users.push(res.data[0]);
const users = users.push(res.data);
this.setState({ users, loading: false });
/*
this.setState({
users: res.data,
loading: false
});
*/
})
.catch(err => {
console.log(err.message);
});
});
}
// handle form submission
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
render() {
const { loading, users, error } = this.state;
return (
<div>
<form onSubmit={e => this._handleSubmit(e)}>
<b>filename:</b>
<input
tyle="text"
className="form-control"
value={this.state.filename}
name="filename"
onChange={this.handleChange}
/>
<button
className="submitButton"
type="submit"
onClick={e => this._handleSubmit(e)}
>
submit
</button>
</form>
<ul>
{this.state.users.map((user, index) =>
<option key={user.uid} value='{ user.uid }' > { user.uid } { user.filename}</option>
)}
</ul>
</div>
);
}
}
because the local user is not defined as an array to have .push() function.
const users=this.state.users;
users.push(res.data) then you can replace it with the users in the state.
what works for me is the concat functions as per code below
const users=this.state.users.concat(res.data);
// const users=this.state.users.push(res.data);// does not work.
Consequently, push() does not work because it returns the length of the extended array, instead of the array itself.
Thanks

Meteor - callback executing twice

I have this Meteor app that sends data to an api then uses the data sent back in the website. However, when I call the function that gets the api data, uploadToCloudinary() which has a callback, I find it running twice. One of the documents get inserted correctly with the correct information and one is missing the res.data.secure_url. Am I not doing the callback thing right or is it because it is non-blocking code, so I think(correct me if I am wrong) that when the imageURL.push function executes, it cannot find a res so it goes and does the other code first and then when it finds the res it pushes it and creates another document.
import { Meteor } from "meteor/meteor"
import React from "react";
import { withRouter, Link } from "react-router-dom";
import SimpleSchema from "simpl-schema";
import axios from "axios"
import { SubjectRoutes } from "./subjectRoutes/subjectRoutes";
import "../methods/methods";
import Menu from "./subComponents/Menu";
class AddNote extends React.Component{
constructor(props){
super(props);
this.state = {
message: "",
loginMessage: (<div></div>),
urls: []
};
}
renderSubjects(subjects){
return subjects.map((item) => {
return <option key={item}>{item}</option>
})
}
componentWillMount() {
Meteor.subscribe('user');
}
addNote(e){
e.preventDefault();
let title = this.refs.title.value;
let subject = this.refs.subject.value;
let description = this.refs.description.value;
let allUrls = [this.refs.imageURL.value].concat(this.state.urls);
let imageURL = allUrls.filter(function(entry) { return entry.trim() != ''; });
let userId = Meteor.userId();
let userEmail = Meteor.user().emails[0].address;
let createdAt = Date.parse(new Date());
let unit = this.refs.unit.value;
let file = this.refs.fileInput.files[0];
if(!Meteor.userId()){
this.setState({
message: "You need to login before you can add a note",
loginMessage: <Link to="/login">Login</Link>
})
throw new Meteor.Error(400, "User is not signed in.")
}
if(title && subject && description && unit){
if(imageURL.length == 0 && file == undefined){
this.setState({ message: "You need to enter an image." })
return;
}
console.log(imageURL.length, file)
if(imageURL){
let noteInfo = { title, subject, description, imageURL, userId, userEmail, createdAt, unit };
Meteor.call("notes.insert", noteInfo, (err, res) => {
if(err){
this.setState({ message: "Please enter a valid image URL." });
}else{
this.props.history.push("/")
}
})
}
if(file){
let noteInfo = { title, subject, description, imageURL, userId, userEmail, createdAt, unit };
this.uploadToCloudinary(file, (err, res) => {
imageURL.push(res.data.secure_url);
Meteor.call("notes.insert", noteInfo, (err, res) => {
//problem .......inserting 2 docs, one empty and one with proper data
console.log("CALLED")
if(err){
this.setState({message: err.reason});
console.log(err);
}else{
this.props.history.push("/")
}
})
});
}
}
}
addLink(){
let file = this.refs.fileInput.files[0];
if(this.refs.imageURL.value || file != undefined){
if(this.state.urls.length < 10){
if(!this.state.urls.includes(this.refs.imageURL.value)){
const URLSchema = new SimpleSchema({
imageURL:{
type:String,
label:"Your image URL",
regEx: SimpleSchema.RegEx.Url
}
}).validate({ imageURL:this.refs.imageURL.value })
let urls = this.state.urls.concat([this.refs.imageURL.value]);
this.setState({ urls });
this.refs.imageURL.value == "";
}else{
this.setState({ message: "You already inserted this note." })
}
}else{
this.setState({ message: "Only allowed 10 notes per upload. "})
}
}else{
this.setState({ message: "Please enter a note." })
}
}
uploadToCloudinary(file, callback){
const CLOUDINARY_URL = "MY_CLOUDINARY_URL";
const CLOUDIARY_UPLOAD_PRESET = "MY_CLOUDIARY_UPLOAD_PRESET"
let formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", CLOUDIARY_UPLOAD_PRESET)
axios({
url: CLOUDINARY_URL,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: formData
}).then(function(res){
callback(new Meteor.Error(400, "Error, cannot connect to cloudinary."), res);
}).catch(function(err){
console.log(err);
})
console.log(file);
}
render(){
return(
<div>
<form onSubmit={this.addNote.bind(this)}>
<Menu />
<p>*Just a friendly reminder: If you cannot read the note yourself,
others cannot as well. Please make sure your notes are clear and
easy to read.*</p>
<h1>Add a note</h1>
<br />
<input className="addNote-input" id="title" ref="title" type="text" placeholder="Title" autoComplete="off" />
<br />
<select ref="subject">
<option selected disabled value="">Choose a subject</option>
{this.renderSubjects(SubjectRoutes)}
</select>
<br />
<input className="addNote-input" id="description" ref="description" placeholder="Description Here..." autoComplete="off" />
<br />
<Link to="/questions">What is this?</Link><br />
<div className="inline full">
<div className="left">
<input id="imageUrl" className="addNote-input insert-link" ref="imageURL" placeholder="Enter image URL here" autoComplete="off" />
</div>
or
<div className="right">
<input className="addNote-input inline" type="file" ref="fileInput" onChange={this.readImage} id="fileInput" autoComplete="off"/>
</div>
<div className="full inline-block">
<span onClick={this.addLink.bind(this)} id="addLink">+</span>
<span>({this.state.urls.length})</span>
</div>
</div>
<input className="addNote-input" placeholder="Subject Unit" type="text" ref="unit" autocomplete="off" />
<br />
<button>Add Note</button>
<br />
<div className="alert alert-danger">Error: {this.state.message}</div>
<br />
{this.state.loginMessage}
</form>
</div>
)
}
}
export default withRouter(AddNote);
PS the function uploadToCloudinary() just receives data as an argument and sends it to an api then puts it into a callback to return an object. And also the console.log("CALLED") is only executed once which is really confusing to me since it is creating two documents so it should be running twice. Thanks in advance!
You're calling notes.insert method twice in addNote():
In if (imageURL) { ... }
In if (file) { ... } — this one is calling uploadToCloudinary first and adds secure_url into imageURL.

Resources