0

I recently started working on a project in which the administrator can create tours online by filling out a form. By completing the form the information to be introduced intro a Mongoose Schema and create JSON.

In createcontent.js file takes the data from the form, I used new FormData(); because to upload images i use a module call multer.

const createTour_form = document.querySelector('.form-create__tour');
if (createTour_form) {
    createTour_form.addEventListener('submit', (cr) => {
        cr.preventDefault();

        const create = new FormData();
        // Name
        create.append('name', document.getElementById('tour_name').value);
        //Tour Duration
        create.append('duration', document.getElementById('tour_duration').value);
        //Number Participoants
        create.append('maxGroupSize', document.getElementById('tour_participants').value);
        //Tour Difficulty
        create.append('difficulty', document.getElementById('tour_difficulty').value);
        //Tour Price
        create.append('price', document.getElementById('tour_prices').value);
        //Short Description
        create.append('summary', document.getElementById('tour_short_des').value);
        //Description
        create.append('description', document.getElementById('tour_long_des').value);

        createTour(create);
    })
}

I use a module slugify to convert the tour name to a slug that I use in the url. This is my mongoose schema:

const tourchema = new mongoose.Schema({
    name: {
        type: String,
        require: [true, 'A tour mush have a name'],
        unique: true,
        trim: true,
        maxlength: [50, 'A tour name must have less or equal then 50 characters'],
        minlength: [10, 'A tour name must have more or equal then 10 characters'],
        //validate:[validator.isAlpha, 'Tour name must only contain characters']
    },
    slug: {
        formType: String
    },
    duration: {
        type: Number,
        require: [true, 'A tour must have a duration']
    },
    maxGroupSize: {
        type: Number,
        require: [true, 'A tour must have a group size']
    },
    difficulty: {
        type: String,
        require: [true, 'A tour must have a difficulty'],
        enum: {
            values: ['easy', 'medium', 'difficult'],
            message: 'Difficulty is either: easy, medium, difficult'
        }
    },
    ratingsAverage: {
        type: Number,
        default: 4.5,
        min: [1, 'Raiting must be above 1.0'],
        max: [5, 'Raiting must be below 5.0'],
        set: val => Math.round(val * 10) / 10
    },
    ratingsQuantity: {
        type: Number,
        default: 0
    },
    price: {
        type: Number,
        require: [true, 'A tour must have a price']
    },
    priceDiscount: {
        type: Number,
        validate: {
            validator: function (val) {
                //his only points to create doc on new document creation
                return val < this.price;
            },
            message: 'Discount price ({VALUE}) shoud be below the regular price'
        }
    },
    summary: {
        type: String,
        trim: true,
        require: [true, 'A tour must have a description']
    },
    description: {
        type: String,
        trim: true
    },
    imageCover: {
        type: String,
        require: [true, 'A tour must have a cover image']
    },
    images: [String],
    createdAt: {
        type: Date,
        default: Date.now()

    },
    startDates: [Date],
    secretTour: {
        type: Boolean,
        default: false
    },
    startLocation: {
        //GeoJSON
        type: {
            formType: String,
            default: 'Point',
            enum: ['Point']
        },
        coordinates: [Number],
        adress: String,
        description: String
    },
    locations: [
        {
            type: {
                type: String,
                default: 'Point',
                enum: ['Point']

            },
            coordinates: [Number],
            adress: String,
            description: String,
            day: Number
        }
    ],
    // guides:Array
    guides: [
        {
            type: mongoose.Schema.ObjectId,
            ref: 'User'
        }
    ]
}

tourchema.index({ slug: 1 });
tourchema.pre('save', function (next) {
    this.slug = slugify(this.name, { lower: true });
    next();
});

When i upload data from form unsign axios winth asynchronus function:

import axios from 'axios';
import { showAlert } from './alert';

export const createTour = async(data)=>{
  try{
     const create_tour = await axios({
          method:'POST',
          url:'http://127.0.0.1:3000/api/v1/tours',
          data:data
     });
  }
  catch(err){
       console.log(err);
       showAlert('error',err.response.data.message); 
  }
}

when the referral action takes place an error occurs slugify: string argument expected I did not find anything on the internet about this error. I tried to build my own function to replace the module but it didn't work there is no solution to solve this error??

KSR
  • 387
  • 2
  • 10
  • Is it possible that a closing parenthesis is missing before `tourchema.index({slug:1});` I mean the one you've opened here `const tourchema = new mongoose.Schema` **(** `{` – Cedric Cholley Jul 20 '20 at 21:07
  • is closed above const tourchema = new mongoose.Schema{ } tourchema.index({slug:1}); tourchema.pre('save',function(next){ this.slug = slugify(this.name,{lower:true}); next(); }); const Tour = mongoose.model('Tour',tourchema); module.exports = Tour; – Pruteanu Alexandru Jul 20 '20 at 21:17
  • Could you add a log of the JSON that axios actually sends ? – KSR Jul 20 '20 at 21:20
  • no my code dosne't send nothing due to errors does not send anything – Pruteanu Alexandru Jul 20 '20 at 21:22
  • Have you tried to `console.log(this)` in `tourchema.pre('save',function(next){ console.log(this); this.slug......` to see what data gets in there? – Molda Jul 20 '20 at 21:28
  • Do you have an indication of where it actually fails ? You could add `console.log(data)` right before calling axios for example. – KSR Jul 20 '20 at 21:29
  • yes I console.log data is empty i try to convert FromData to an Object like in the answer below and it's start to work. thank you very much for your help. – Pruteanu Alexandru Jul 22 '20 at 05:29

1 Answers1

0

You can convert the "FormData" to an Object and then parse it.

function formDataToObj(formData) {
    let obj = {};
    for (let key of formData.keys()) {
        obj[key] = formData.get(key)
    }
    return obj;
}

Example:

function formDataToObj(formData) {
  let obj = {};
  for (let key of formData.keys()) {
    obj[key] = formData.get(key)
  }
  return obj;
}
    

const fd = new FormData()
fd.append('a', 1)
fd.append('b', 2)
const obj = formDataToObj(fd)
console.log( obj )
const json = JSON.stringify( obj )
console.log( json )

UPDATE: A better approach could be by using the native way like this:

Object.fromEntries(formData.entries())

Example:

const fd = new FormData()
fd.append('a', 1)
fd.append('b', 2)
const obj = Object.fromEntries(fd.entries())
console.log( obj )
const json = JSON.stringify( obj )
console.log( json )
Yoel Duran
  • 381
  • 3
  • 5
  • Thank you very much for your help,it's wprk data it's sent to apy,but one more quiestions how to add data in complex JSON structure like tour { startPoint:{ coordinates:'','adress' } } something like that. – Pruteanu Alexandru Jul 22 '20 at 05:31