Assign a value to a [(ngModel)] input - node.js

new to MEAN stack here,
I'm trying to insert datas into MongoDB, but with the _id of the connected user, so I have a function which display it :
getSessionInfos(){
return sessionStorage.getItem('id');
}
db.collection('transactions').insertOne({
date : req.body.date,
titre: req.body.titre,
description : req.body.description,
montant : "-" + req.body.montant,
id: req.body.id, <-------------
type: "debit"
So I thought to myself, alright, I'm gonna create a hidden input with the ID as a value, it's gonna be easier :
<input type="text" [(ngModel)]="data.id" value="getSessionInfos()">
Except that NO, it seems that you can't change the value of a NGmodel input,
So how am I supposed to do that ?
Thanks a lot

<input [hidden]='true' type="text" [(ngModel)]="data?.id" >

data: any = {
date: "",
titre: "",
description: "",
montant: "",
id: sessionStorage.getItem('id'),
type: ""
}

<ng-container *ngfor="let dataa in data"><input [hidden]='true' type="text" [(ngModel)]="dataa.id" (change)="getSessionInfos()"></ng-container>

Related

trying to pass check boxes as string (node)

im doing a small project to learn fullstack (mongo&node&express&ejs), what i have in the project:
-object - name film. it got a couple of fields, like length, genre, director.
-an add film form.
i store the objects in mongo. overall everything is working good.
in the add film, the genre label is an options one - and i decided it would be more professional to make it check boxes, so user can choose how many genres as he want (after all most films are belong to a couple of genres.) i need one of the 2 next options:
-to change the genre field type of the object from string to array, and store an array of all the select check boxes, and show them in the film page. (i didnt manage to achieve an array of all the selected check boxes name)
-leave the genre field type as string, and then just display it as string. (didnt work so far, gets blank)
right now when its just options, it get passed as string, and all is working good and really simple. but i cant manage to work with the check boxes so far. tried as array and as String and so far all errors or undefined. i looked alot of solutions and all i saw are solutions in php or solutions that require document property (which doesnt work, from googling i understood its because of node.)
any idea how can i implement such thing?
this is what i have now (genre as options, and its working):
the object (not all the fields)
const filmSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
releaseYear: {
type: Number,
required: true
},
genre: {
type: String,
required: true
},
#the form genre part
<label>Genre</label>
<select name="genre">
<% genre.forEach(g => { %>
<% if (g === film.genre) { %>
<option selected label="<%= g %>" value="<%= g %>"></option>
<% } else { %>
<option value="<%= g %>"><%= g %></option>
<% } %>
<% }) %>
</select>
the post (relevant parts)
router.post('/', async (req, res) => {
const film = new Film({
title: req.body.title,
director: req.body.director,
releaseYear: req.body.releaseYear,
genre: req.body.genre,
length: req.body.length,
description: req.body.description,
})
displaying a film
<h2> <%= film.title %> </h2>
<img height="150" width="100" src="<%= film.posterImagePath %>">
<div>Director: <%= film.director.name %></div>
<div>Release Year: <%= film.releaseYear %> </div>
<div>Genre: <%= film.genre %> </div>
<div>Length: <%= film.length %></div>
<div>Description: <%= film.description %></div>
im stuck on this problem for a few hours, any help would be greatly appreciated!

Selecting first element from the dropdown [ select tag ] cause the backend to crash but selecting other works just fine

I'm building a simple app with node.js and reactjs but the problem arises when I want to add book especially while selecting dropdown value.
In the select tag when I select the first element it crashes the backend but when I select the second or below it they work just fine. What could be the reason behind it ? Dropdown menu has been filled correctly. My code is :
import React, { Component } from 'react'
import axios from 'axios'
export default class AddBook extends Component {
state = {
name : '',
author : '',
publishers : '',
pages :'',
genres : [],
genre : '',
addedMessage : null
}
async componentDidMount() {
const genres = await axios.get('http://localhost:5000/api/genres')
this.setState({ genres : genres.data})
}
onInputChange = (e) => {
this.setState({[e.target.name] : e.target.value }) //looks for name
}
onFormSubmit = (e) => {
e.preventDefault();
const book = {
name : this.state.name,
author : this.state.author,
publishers : this.state.publishers,
pages : this.state.pages,
genres : this.state.genre
}
axios.post('http://localhost:5000/api/books', book)
.then(res => console.log(res))
.catch(err => console.log("error occured while posting data ", err))
console.log(book)
//alert("book added successfully !!!")
this.setState({addedMessage : 'Book added successfully'})
window.location = "/books"
}
render() {
const { name, author, publishers, pages, genres, addedMessage } = this.state;
return (
<div className="container">
<h2>ADD BOOK </h2>
{ addedMessage && <h2 style={{textAlign : 'center'}} className="alert alert-info">{addedMessage}</h2> }
<form onSubmit = { this.onFormSubmit }>
<div className="form-group">
<label htmlFor="name">BookName:</label>
<input type="text" required className="form-control" id="name"
placeholder="Enter Book name" name="name"
onChange={this.onInputChange}
value={name}
/>
</div>
<div className="form-group">
<label htmlFor="author">Author:</label>
<input type="text" required={ true } className="form-control"
id="author" placeholder="Enter Author" name="author"
onChange={this.onInputChange}
value={author}
/>
</div>
<div className="form-group">
<label htmlFor="publishers">Publishers:</label>
<input type="text" required className="form-control"
id="publishers" placeholder="Enter Publishers Name"
name="publishers"
onChange={this.onInputChange}
value={publishers}
/>
</div>
<div className="form-group">
<label htmlFor="pages">Pages:</label>
<input type="number" required className="form-control"
id="pages" placeholder="Enter No of Page" name="pages"
onChange={this.onInputChange}
value={pages}
/>
</div>
<div className="form-group">
<label htmlFor="genre">Category:</label>
<select type="select" className="form-control"
id="genre"
name="genre"
onChange={this.onInputChange}
>
{/* <option value="selectCategory" onChange={this.onInputChange}>Select</option> */}
{
genres.map( genre => (
<option key={genre._id} onChange={this.onInputChange} value={genre.name}>
{genre.name }</option>
))
}
</select>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
)
}
}
My backend is up and running and has successfully fetched the genres[ categories ] , but I am not able
to figure out why selecting the first doesn't work but others just work fine. How should I solve it ?
It shows the following error for this case.
Error: Book validation failed: genres: Path `genres` is required.
at ValidationError.inspect
(E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\error\validation.js:48:26)
at formatValue (internal/util/inspect.js:718:31)
at inspect (internal/util/inspect.js:287:10)
at afterInspector (internal/errors.js:682:14) {
errors: {
genres: ValidatorError: Path `genres` is required.
at validate (E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\schematype.js:1178:13)
at E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\schematype.js:1161:7
at Array.forEach (<anonymous>)
at SchemaString.SchemaType.doValidate
(E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\schematype.js:1106:14)
at E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\document.js:2387:18
at processTicksAndRejections (internal/process/task_queues.js:79:11) {
properties: [Object],
kind: 'required',
path: 'genres',
value: '',
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
},
_message: 'Book validation failed'
}
[nodemon] app crashed - waiting for file changes before starting...
And code for my book schema is as follows
const mongoose = require('mongoose')
//schema for genres
const bookSchema = mongoose.Schema({
name : {
type : String,
required : true,
trim : true,
unique : true //title is made unique.
},
author : {
type : String,
required : true,
trim : true
},
publishers : {
type : String,
trim : true,
},
pages : {
type : Number,
required : true,
trim : true
},
genres : {
type : String,
required : true,
trim : true
},
create_date : {
type : Date,
default : Date.now
}
})
//It will create books collection in your database and documents
//inside that collection will have fields from bookSchema when you save first document.
const Book = module.exports = mongoose.model('Book', bookSchema)
//get the books
module.exports.getBooks = (callback, limit) => {
// Book.find(callback)
Book.find(callback).limit(limit)
}
//get single book
module.exports.getBookById = (id,callback) => {
// Book.find(callback)
Book.findById(id,callback);
}
module.exports.addBook = (book,callback) => {
Book.create(book, callback);
}
module.exports.updateBook = (id,book,options, callback) => {
const query = {
_id : id
}
const updatedBook = {
name : book.name,
author : book.author,
publishers : book.publishers,
pages : book.pages,
genres : book.genres
}
Book.findByIdAndUpdate(query, updatedBook, {} , callback);
}
module.exports.deleteBook = (id,callback) => {
const query = {
_id : id
}
Book.findByIdAndDelete(query, callback);
}
I checked some of the similar answers in the stackoverflow but couldn't figure out why I'm getting that
error.
Here's the problem with your code :
The first option of the dropdown is chosen by default, and thus "selecting" the first option doesn't trigger the Category dropdown's onChange function (because the selected value doesn't really change).
Since the default value of this.state.genre is an empty string, the genres property of the book you send to the backend also has genres as an empty string.
Finally, Mongoose does not accept an empty string for a required string field, which gives you the Path 'genres' is required error.
Try switching to another option and back to the first. It will work then because the onChange function will then get called and this.state.genre will be set properly.
There are a few ways to fix this:
Add a placeholder option to the dropdown - something like "Select an option...". Then the user will be forced to select a genre from the dropdown and onChange would be called.
Or, in componentDidMount, set this.state.genre to the first genre of the list of genres you fetch.

html form input name for mongoose

MongoDB
{
"_id" : ObjectId("5bfac9c5c44526e73f960e89"),
"brand" : "Under Armour",
"amazon" : {
"order" : "666-666-666",
"id" : "B072LNJPS1"
}
...
}
HTML
<form....>
<input class="form-control" type="text" name="brand">
<input class="form-control" type="text" name="amazon.id">
<input class="form-control" type="text" name="amazon.order">
...
</form>
NodeJs
const myPost = request.body
const query = { _id: request.body._id }
const options = { upsert: true, new: true }
await model.findOneAndUpdate(query, myPost, options);
I have this error message because of the '.' in the field name
errmsg: 'Updating the path 'amazon.id' would create a conflict at 'amazon''
You have tips for the field name to match the model structure
This may not be a complete answer, but you need to replace "amazon.id" with "amazon[id]" to match the nested structure.
Reference: Colt Steele's "The Web Developer Bootcamp"

sailsjs: Avoid saving some form inputs in database

I am trying to make a signup page, following irl nathans guide. Now everything works, however sail.js seems to save everything from the form in the database. For an example, I have this form:
<form class="form-signup" name="signup-form" action="/user/create" method="POST">
<input type="text" name="username" placeholder="<%= __('username') %>"> %>">
<input type="text" name="email" placeholder="<%= __('email') %>">
<input type="password" name="password" placeholder="<%= __('password') %>">
<input type="password" name="confirmation" placeholder="<%= __('confirm-password') %>">
<input class="button" type="submit" value="<%= __('signup') %>"/>
<input type="hidden" name="_csrf" value="<%= _csrf %>"/>
</form>
In this example it saves both the password and the password-confirmation in the database, which it shouldn't.
In my User.js model I have the following attributes, but these are just saved alongside the two passwords. I also have an encryptedPassword, that encrypts the password if they match.
module.exports = {
attributes: {
username: {
type: 'string',
required: true,
unique: true
},
email: {
type: 'string',
required: true,
isEmail: true,
unique: true
},
encryptedPassword: {
type: 'string'
},
// more unimportant code here.
}
I would like to know whether and it is possible to prevent sails.js from saving the two unencrypted passwords in the database whenever the form is submitted. I know I can just remove it afterwards from the database, however, that seems kind of stupid.
The saved record in the database, when submitted:
{
"username": "testuser",
"password": "2",
"confirmation": "2",
"email": "myemail#email.com",
"createdAt": 1496268539155,
"updatedAt": 1496268539155,
"encryptedPassword": "$2a$10$BkwvQnu3TA4DQ1kDMZmi6O7Z/K5uX90fHi/6zkZF.nkKi8MU.zWTS",
"id": "592f3efbaa4d2563e159dc20"
}
Since I am encrypting the password, it shouldn't also save the unencrypted passwords, just because they were part of the submit form. How do I prevent it from doing so?
Where you setup your db connection (connections.js or in your /env/development.js) specify schema: true
For example:
someDbServer: {
adapter: 'sails-mongo',
host: 'localhost',
port: 27017,
user: 'username',
password: 'pwd',
database: 'db_name',
schema: true
}
Setting schema to true means only attributes in the model js file can be inserted.
For encrypting your password you want to do that in beforeCreate and beforeUpdate. Take a look at lifecycle callbacks -sailsjs lifecycle callbacks
Thank you for the answers, however, I managed to solve the problem by passing an object to the .create() function. This object contains all the parameters I want to save, instead of using req.params.all().
var userObj = {
username : req.param('username'),
firstname : req.param('firstname'),
encryptedPassword : password,
surname : req.param('surname'),
email : req.param('email')
}

How search value inside an object in Redis?

I'm newbie to Redis and Nodejs, I've watched this tutorial and i'm trying to search users by name,
Here is the object, returned from redis when i pass the id:
{
first_name: '‪john',
last_name: 'doe',
email: 'john#gmail.com',
phone: '543313305',
id: 'user001'
}
Here is the function of the search :
app.post('/user/search',function (req,res,next) {
let id = req.body.id;
client.hgetall(id ,function(err,obj){
if(!obj){
res.render('searchusers',{
error:"user doesn't exist",
});
} else {
obj.id = id
console.log(obj);
res.render('details',{
user:obj, });
}
});
});
I've tried to replace the search by id to search by first_name by doing this:
First I've changed the field name to "first_name" instead of "id"
<h1>Search Users</h1>
{{#if error}} <span>{{error}}</span>{{/if}}
<form class="form-inline" method="POST" action="/user/search">
<div class="form-group">
<input type="text" name="first_name" placeholder="Search" class="form-
control">
</div>
<input type="submit" class="btn btn-primary" value="Search">
And than I've changed it in the app.js ;
app.post('/user/search',function (req,res,next) {
let first_name = req.body.first_name;
client.hgetall(first_name ,function(err,obj){
if(!obj){
res.render('searchusers',{
error:"user doesn't exist",
});
} else {
obj.first_name = first_name
console.log(obj);
res.render('details',{
user:obj, });
}
});
});
The hgetall method that you are using in the search function of the method looks up a hash by the key, which in this case is the user id and returns all of the fields of the hash from Redis.
There is no function to search over the fields of the hash. If you need to be able to map from a first name to a user, you will need to manually build a secondary index using a data structure such as sets, that allows you to go from first name to the users that have that first name.

Resources