so, i have a Mongoose Schema, something like:
Person: {
name: String,
address: {
street: String,
number: String,
city: String
}
}
Is there a way, to code our form so that i can map directly from req.body to the Person instance? considering the sub-division in address.
I tried:
<form>
<input name="name">
<input name="address.street">
<input name="address.number">
<input name="address.city">
</form>
and it doesn't work...
Try this:
<form>
<input name="name">
<input name="address[street]">
<input name="address[number]">
<input name="address[city]">
</form>
See this post on application/x-www-form-urlencoded encoding.
Related
when I'm using the POST endpoint from Sveltekit, I get a "flat" object as output. How can I get a "structured" Object instead ?
Let's assume the following code:
index.svelte
<div class="container">
<form method="post">
<label for="firstname">Firstname</label>
<input type="text" name="firstname" />
<label for="lastname">Lastname</label>
<input type="text" name="lastname" />
<label for="dog">Dog 1</label>
<input type="text" name="dog" />
<label for="dog">Dog 2</label>
<input type="text" name="dog" />
<!-- ... -->
<button>Save</button>
</form>
</div>
index.js
export async function post({request}){
const data = Object.fromEntries(await request.formData());
console.log(data);
return{}
}
Ouput (what I'm calling "flat" object)
{ firstname: 'foo', lastname: 'bar', dog: 'teckel', dog: 'labrador' }
Instead of that output, how should I proceed to get the following one in my index.js
Expected output:
{
firstname: 'foo',
lastname: 'bar',
dogs: [ { dog: 'teckel' }, { dog: 'labrador' } ]
}
There are libraries that can perform a transform like this more or less automated. Some use conventions in the field names to parse the data into arrays and nested structures, others additionally use schemas to do type conversions or validation. E.g. to achieve an array of objects like this, one might set the names like this:
<label for="dog">Dog 1</label>
<input type="text" name="dogs[][dog]" />
<label for="dog">Dog 2</label>
<input type="text" name="dogs[][dog]" />
The [] Indicates that the field is part of an array, [dog] indicates that a property called dog is set on the element (.dog would also be reasonable).
So instead of calling Object.fromEntries you have to either parse the data yourself or find a library that does it for you. (Note that StackOverflow is not a place for library recommendations.)
Personally, I would avoid the synchronous form post and send JSON asynchronously instead, that way you can send in a fixed structure and receive that exact structure. Of course this requires binding/reading the form values yourself.
I am relatively new to coding and have been working on a restful routes exercise for an online course using a MEN stack. In the exercise, I am trying to use a default image when no data is entered into the /new route form. I have already indicated a default image in my mongoose schema, but it doesn't seem to be working when I leave the image field blank on my form. It creates a new post with a "unknown" src attribute. I have attached code for my schema, my /new ejs form, and new and create routes. Thanks for any help!
(MONGOOSE SCHEMA)
var catSchema = new mongoose.Schema({
name : String,
description: String,
ranking: Number,
image: {type: String, default: "https://i.cubeupload.com/SnsWs2.png"},
created: {type:Date, default: Date.now}
(NEW AND CREATE ROUTES)
app.post("/cats", function(req,res){
Cat.create(req.body.cat, function(err,newBlog){
if(err){
res.redirect("/cats/new")
}else{
res.redirect("/cats")
}
});
});
(NEW ROUTE)
<%- include("partials/header") %>
<div class="container">
<form action="/cats" method="POST">
<div class="form-group">
<label required for="cat[name]">Name</label>
<input type="text" name="cat[name]" class="form-control" id="name" aria-describedby="emailHelp" placeholder="Enter cat name">
</div>
<div class="form-group">
<label for="cat[description]">Description</label>
<input type="text" class="form-control" name="cat[description]" placeholder="description">
</div>
<div class="form-group">
<label for="cat[ranking]">Ranking</label>
<input type="number" class="form-control" name="cat[ranking]" placeholder="Password">
</div>
<div class="form-group">
<label for="cat[image]">Ranking</label>
<input type="text" class="form-control" name="cat[image]" placeholder="image URL">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
Here I'm using the nested property Schema of mongoose to nest all the "stages" then using formGroup in typescript.
I'm not sure what should be the formControlName for the radio
buttons as it needs to be similar?
Also, not sure if I'm missing anything?
Code:
// Schema
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
stages: {
stageOne: { type: Boolean, default: false },
stageTwo: { type: Boolean, default: false },
stageThree: { type: Boolean, default: false }
});
// typescript/component.ts
this.form = this.formBuilder.group({
name: [''],
email: [''],
stages: this.formBuilder.group({
stageOne: [null],
stageTwo: [null],
stageThree: [null]
});
});
// html/template.html
<form [formGroup]="form">
<div class="form-group">
<input name="name" class="form-control" id="name" type="text" [(ngModel)]="name" formControlName="name">
<input name="email" class="form-control" id="email" type="email" [(ngModel)]="email" formControlName="email">
<div class="custom-control custom-radio">
<input type="radio" id="stageOne" class="custom-control-input" [(ngModel)]="stageOne" formControlName="???">
<label class="custom-control-label" for="stageOne">1</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="stageTwo" class="custom-control-input" [(ngModel)]="stageTwo" formControlName="???">
<label class="custom-control-label" for="stageTwo">2</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="stageThree" class="custom-control-input" [(ngModel)]="stageThree" formControlName="???">
<label class="custom-control-label" for="stageThree">3</label>
</div>
</div>
</form>
It is no different than with your other input form controls. However, the ControlValueAccessor will get the value from your radio button so you do not require the additional ngModel directives. When you submit your form the from object itself, this.form.value, will contain all your form values.
Reactive Form
this.form = this.formBuilder.group({
name: [''],
email: [''],
stages: ['1']
});
Template
<form [formGroup]="form">
<div class="form-group">
<input name="name" class="form-control" id="name" type="text" formControlName="name">
<input name="email" class="form-control" id="email" type="email" formControlName="email">
<div class="custom-control custom-radio">
<input type="radio" id="stageOne" class="custom-control-input" formControlName="stages" [value]="1">
<label class="custom-control-label" for="stageOne">1</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="stageTwo" class="custom-control-input" formControlName="stages" [value]="2">
<label class="custom-control-label" for="stageTwo">2</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="stageThree" class="custom-control-input" formControlName="stages" [value]="3">
<label class="custom-control-label" for="stageThree">3</label>
</div>
</div>
</form>
.I know I am not targeting correctly my schema because I get an empty array. I want to push my input values in the staff array. It seems like there's limited handlebars documentation on input fields templating. Thanks!
My Schema:
var docketSchema = new Schema({
companyName: string,
address: string,
staff: [{ manager: String,
receptionist: String
}]
});
My handlebars template:
<div class="form-group">
<input type="text" id="address" name="address" required value="{{input.address}}">
</div>
<div class="form-group">
<input type="text" id="companyName" name="companyName" required value="{{input.companyName}}">
</div>
<div class="form-group">
<input type="text" id="manager" name="manager" required value="{{input.staff.manager}}">
</div>
<div class="form-group">
<input type="text" id="receptionist" name="receptionist" required value="{{input.staff.receptionist}}">
</div>
My route:
router.post('/create', function(req, res, next) {
userService.addDocket(req.body, function(err) {
var vm = {
input: req.body
};
res.redirect('/dockets');
});
});
My console:
[ { companyName: 'Acme',
address: 'New York',
staff: [] } ]
My addDocket method:
exports.addDocket = function(docket, next) {
var newDocket = new Docket({
companyName: docket.companyName,
address: docket.address,
staff: docket.staff
});
newDocket.save(function(err) {
next(null);
});
};
In your handlebars template, try creating the form elements with arrays as follows:
<div class="form-group">
<input type="text" id="address" name="address" required value="{{input.address}}">
</div>
<div class="form-group">
<input type="text" id="companyName" name="companyName" required value="{{input.companyName}}">
</div>
<div class="form-group">
<input type="text" id="manager" name="staff[manager]" required value="{{input.staff.manager}}">
</div>
<div class="form-group">
<input type="text" id="receptionist" name="staff[receptionist]" required value="{{input.staff.receptionist}}">
</div>
I have file views/user/index.ejs
<form action="" method="POST>
<label>Username: </label>
<input type="text" class="form-control" value="<%= req.param('username') %>" name="username">
<input type="Submit" value="Submit">
</form>
Content of api/controllers/UserController.js
module.exports = {
index: function (req, res) {
sails.log(req.param('username'));
// Result: invest
}
}
Although the log print "invest", but the content of input is "undefined". I think that the array of requested parameters had not been kept.
Can anyone help me solve it? I will donate 2 eggs ;)
You can use this to pass variables to your view:
module.exports = {
index: function (req, res) {
return res.view("user/index", {username: req.param('username')});
}
}
In your view:
<input type="text" class="form-control" value="<%= username %>" name="username">