javascriptnode.jsexpressmongooseslugify

How can I create Json with data from a form?


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


Solution

  • 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 )