Can't access the data of the form submitted - forms

I am starting with angular2. I have a simple template driven form and I can access the data in console. But I am having problem with passing the data. Here is my code.
import {Component} from "angular2/core";
#Component({
selector: 'my-template-driven',
template:`
<h2>Sign-up form</h2>
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<div>
<label for="email">Mail</label>
<input ngControl="email" type="text" id="email" required #email="ngForm">
<span class="validation-error" *ngIf="!email.valid">Not Valid</span>
</div>
<div>
<label for="password">Password</label>
<input ngControl="password" type="text" id="password" required #password="ngForm">
<span class="validation-error" *ngIf="!password.valid">Not Valid</span>
</div>
<div>
<label for="confirm-password">Confirm Password</label>
<input ngControl="confirm-password" type="text" id="confirm-password" required #passwordConfirm="ngForm">
<span class="validation-error" *ngIf="!passwordConfirm.valid">Not Valid</span>
</div>
<button type="submit" [disabled]="!f.valid || password.value !== passwordConfirm.value">Submit</button>
</form>
<h2>You Submitted</h2>
`
})
export class TemplateDrivenFormComponent {
user: {email: '', password: ''};
onSubmit(form){
//console.log(form);
this.user.email = form.value['email'];
//this.user.password = form.controls['password'].value;
}
}
I am getting this angular2.js:23941 ORIGINAL EXCEPTION: TypeError: Cannot set property 'email' of undefined error constantly. How can I access the data of the form submitted.

You don't declare your local correctly, and you must initialize it when you declare it, or in your constructor maybe
user: any;
constructor() {
this.user = {email: "", password: ""} as any;
}
after : you must provide the type.

Html input must have "ngModel" attribute in it.

Related

Why am I getting "500 (Internal Server Error)" and "Uncaught (in promise) SyntaxError: Unexpected token < "?

I am trying to insert some data into the database through a fetch API POST request to a Next.js API route but I am getting the following two error messages in the browser's console:
api/addCompany/addCompany:1 Failed to load resource: the server responded with a status of 500 (Internal Server Error) register:1
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
These are my project's folders (it's relevant because of Next.js's routing system)
This is the component where I am doing the fetch API request (please don't judge my poor Typescript skills, I am new to it, still not finding the propper event type):
import styles from '../styles/Register.module.css'
import { NextPage } from "next"
import { prisma } from '../prisma/prisma_client';
import { Prisma } from '#prisma/client';
import { useSession } from "next-auth/react"
const Register: NextPage = () => {
const createCompany: any = async (event: any) => {
event.preventDefault()
const company: Prisma.CompanyCreateInput = {
companyName: event.target.companyName.value,
gender: event.target.gender.value,
firstName: event.target.firstName.value,
lastName: event.target.lastName.value,
street: event.target.street.value,
houseNumber: parseInt(event.target.houseNumber.value),
postcode: parseInt(event.target.postcode.value),
city: event.target.city.value,
country: event.target.country.value,
countryCode: event.target.countryCode.value,
callNumber: parseInt(event.target.callNumber.value),
emailAddress: event.target.emailAddress.value,
website: event.target.website.value,
socials: {},
companyUser: {
connect: { id: 'cl0y4y8xo0021mwtcmwlqfif6' }
}
}
const companyJSON = JSON.stringify(company)
const endpoint = '/api/addCompany/addCompany'
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: companyJSON,
}
const response = await fetch(endpoint, options)
const data = await response.json()
console.log(data)
}
return (
<form onSubmit={createCompany} className={styles.form} id="signupForm" noValidate>
<h2>Company Information</h2>
<div className="fieldWrapper">
<input type="text" id="companyName" name="companyName" placeholder=" " />
<label htmlFor="companyName">Company Name<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" list="genders" id="gender" name="gender" placeholder=" " />
<label htmlFor="gender">Gender<span>*</span></label>
<div className='errorMessage'></div>
<datalist id="genders">
<option>Female</option>
<option>Male</option>
</datalist>
</div>
<div className="fieldWrapper">
<input type="text" id="firstName" name="firstName" placeholder=" " />
<label htmlFor="firstName">First Name<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="lastName" name="lastName" placeholder=" " />
<label htmlFor="lastName">Last Name<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="street" name="street" placeholder=" " />
<label htmlFor="street">Street<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="number" id="houseNumber" name="houseNumber" placeholder=" " />
<label htmlFor="houseNumber">House Number<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="number" id="postcode" name="postcode" placeholder=" " />
<label htmlFor="postcode">Postcode<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="city" name="city" placeholder=" " />
<label htmlFor="city">City<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="country" name="country" placeholder=" " />
<label htmlFor="country">Country<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="countryCode" name="countryCode" placeholder=" " />
<label htmlFor="countryCode">Country Code<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="number" id="callNumber" name="callNumber" placeholder=" " />
<label htmlFor="callNumber">Call Number<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="email" id="emailAddress" name="emailAddress" placeholder=" " />
<label htmlFor="emailAddress">Email Address<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="website" name="website" placeholder=" " />
<label htmlFor="website">Website</label>
</div>
<div className="fieldWrapper">
<input type="text" id="socials" name="socials" placeholder=" " />
<label htmlFor="socials">Socials</label>
</div>
<div className="fieldWrapper">
<button type="submit">Save</button>
</div>
</form>
)
}
export default Register
And this is the the addCompany file's code which serves as the Next.js API route for my fetch API request:
import { Prisma } from '#prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../../prisma/prisma_client';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const {body} = req;
const companyData: Prisma.CompanyCreateInput = JSON.parse(body);
const addCompany = await prisma.company.create({
data: companyData
})
res.status(200).json(addCompany);
}
export default handler
I appreciate any help. Thank you.
I tried to comment out
const data = await response.json() console.log(data)
in the Register component so the error "Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0" disappeared but that is no solution to the problem at all.
I also tried to adjust the route of my fetch request to any possible option because I wasn't sure how exactly Next.js autocompletes it, for example I tried: '/api/addCompany/addCompany.ts' and so on.
I expect the problem to be something small, I hope it isn't typo.
Thank you again.
PS: I also checked similar posts on this matter but couldn't find a fix for my problem.
There is no need to reparse the body data in the API endpoint because Next.js middleware convert that data to an object already:
API routes provide built in middlewares which parse the incoming
request (req). Those middlewares are:
req.cookies - An object containing the cookies sent by the request. Defaults to {}
req.query - An object containing the query string. Defaults to {}
req.body - An object containing the body parsed by content-type, or null if no body was sent
something like below should work:
import { Prisma } from '#prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../../prisma/prisma_client';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const {body: companyData} = req;
//const companyData: Prisma.CompanyCreateInput = JSON.parse(body);<- No need to reparse the data here
const addCompany = await prisma.company.create({
data: companyData
})
res.status(200).json(addCompany);
}
export default handler
Thanks to this answer here for clarification.

Input field is not working

When I am using state variable as a value for the input fields, second input field is not working.
Here is the code:
<input
type="text"
className="form-control"
placeholder="mobileNumber"
onChange={this.handleLoginMobileNumber}
onKeyUp={this.handleLoginMobileNumber}
value={this.state.loginMobileNumber}
/>
<input
type="text"
className="form-control"
placeholder="Passcode"
maxLength="4"
value={this.state.loginPasscode}
/>
<br/>
<button
className="btn btn-large btn-primary medata-login-form-input medata-login-form-submit-button"
onClick={this.submitLogin}>
Log in
</button>
Help me, Thanks.
Issue is, you are using Controlled Component and you forgot to define the onChange method and update the state value with password field, because of that password field is read only.
Check this example:
class App extends React.Component{
constructor(){
super();
this.state = {
loginMobileNumber: '',
loginPasscode: ''
}
}
handleLoginMobileNumber(e){
this.setState({loginMobileNumber: e.target.value})
}
loginPasscode(e){
this.setState({loginPasscode: e.target.password})
}
render(){
return(
<div>
<input
type="text"
className="form-control"
placeholder="mobileNumber"
onChange={this.handleLoginMobileNumber.bind(this)}
value={this.state.loginMobileNumber}
/>
<input
type="password"
className="form-control"
placeholder="Passcode"
maxLength="4"
value={this.state.loginPasscode}
onChange={this.loginPasscode.bind(this)}
/>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>

Form validation not working correctly when user hits login button (Angular 2)

I have a form with username and password, when a user hits the submit button, a error message is displayed stating if one or both fields are blank, I'm trying to add a route to the button so it takes them to the home page, however, when I add a route to the button, it ignores the validation as aspect and will work if fields are blank. I've tried to disable the button so that it's only enabled when the form is valid but I'm getting a bit confused between ngForm and ngFormModel
Thanks
This is my html form
<form [ngFormModel]="loginForm" (ngSubmit)="loginUser(loginForm.value)">
<div class="form-group" [ngClass]="{ 'has-error' : !username.valid && submitAttempt }">
<label class="control-label" for="username">Username</label>
<em *ngIf="!username.valid && submitAttempt">Required</em>
<input id="username" type="text" class="form-control" placeholder="Username" ngControl="username">
</div>
<div class="form-group" [ngClass]="{ 'has-error' : !password.valid && submitAttempt }">
<label class="control-label" for="password">Password</label>
<em *ngIf="password.hasError('required') && submitAttempt">Required</em>
<em *ngIf="password.hasError('minlength') && submitAttempt">Must be at least 8 characters</em>
<input id="password" type="password" class="form-control" placeholder="Password" ngControl="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</form>
And this is my component
import {Component, EventEmitter} from "angular2/core";
import {Router} from "angular2/router";
import {ROUTER_DIRECTIVES} from "angular2/router";
import {Control, ControlGroup, FormBuilder, Validators, FORM_DIRECTIVES} from 'angular2/common';
//import {UsernameValidators} from './usernameValidators';
#Component({
selector: 'LoginHTML',
templateUrl: 'dev/LoginComponents/login-form.component.html',
directives : [FORM_DIRECTIVES]
})
export class LoginHTMLComponent{
loginForm: ControlGroup;
username: Control;
password: Control;
submitAttempt: boolean = false;
form: ControlGroup;
constructor( private builder: FormBuilder, private _router: Router) {
this.username = new Control('', Validators.required)
this.password = new Control('', Validators.compose([Validators.required, Validators.minLength(8)]))
this.loginForm = builder.group({
username: this.username,
password: this.password
});
}
loginUser(user) {
this.submitAttempt = true;
this._router.navigate(['Dashboard']);
}
}
You should be free to do anything with your code, so the form won't try to intervene your loginUser function to navigate to Dashboard. But it does provide you information about form validity that you can make use of:
loginUser(user) {
this.submitAttempt = true;
if (this.loginForm.valid) {
this._router.navigate(['Dashboard']);
}
}

Angular2 New Form API: Submitting form without any bindings of its elements

Attention: It should work with the new forms API!
Is there a possibility to submit a raw form without any bindings of its elements?
An Example:
<div class="form-mantle">
<form (ngSubmit)="onSubmitForm1(f1.value)" #f1="ngForm">
<input ngControl="name1" name="name1" type="text" required/><br/>
<input ngControl="text1" name="text1" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!f1.form.valid">Next </button>
</form>
</div>
<pre>
{{ form1 | json }}
</pre>
How should onSubmitForm1() look like, so that I get form1 like below rendered:
{
name1: "Michael Jackson",
text1: "They don't really care about us"
}
I've already preapared a component to copy+paste, for those, who want to help:
import { Component } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'form1',
templateUrl: 'form1.component.html',
styleUrls: ['form1.component.css']
})
export class Form1Component {
form1 : any = {};
constructor() { }
onSubmitForm1 (data?:any) {
// get raw data from form without bindings
this.form1 = data;
console.log("Data", data);
return false;
}
}
Edit: The exact working copy in plnkr (http://plnkr.co/edit/nMPTYLGxgWzzJuD9Be3f?p=preview) does not work within the seed from https://github.com/mgechev/angular2-seed . Maybe it is a version problem ??
Double binding works without errors:
<div class="form-mantle">
<form (ngSubmit)="onSubmitForm1(f1.value)" #f1="ngForm">
<input [(ngModel)]="f1.name1" #name="ngModel" name="name1" type="text" required/><br/>
<input [(ngModel)]="f1.text1" #name="ngModel" name="text1" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!f1.form.valid">Next </button>
</form>
</div>
<pre>
{{ f1.value | json }}
</pre>
Just call it like so in your ngSubmit:
(ngSubmit)="onSubmitForm1(f1.value)"
To every control you want to submit add the ngControl attribute to set its name:
<input ngControl="name1" name="name1" type="text" required/><br/>
<input ngControl="text1" name="text1" type="text" required/><br/>
Then in your onSubmitForm1:
onSubmitForm1 (data?:any) {
console.log("Data", data);
this.form1 = data;
}
Plunker for example usage
Yeap, for now (rc4) you have only two ways for accepting a data after submit:
1) model-driven strategy (bindings)
2) template-driven strategy (ngControls)
Finaly the following has worked (double bindings :/ ):
<form (ngSubmit)="onSubmitForm()" #s1="ngForm">
<input [(ngModel)]="step1.name1" [ngModelOptions]="{standalone: true}" type="text" required/><br/>
<input [(ngModel)]="step1.text1" [ngModelOptions]="{standalone: true}" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!s1.form.valid">Next </button>
</form>

Why doesn't my React Js form accept user input?

I have a simple AddUser component and in the render function I am returning the following html:
<form ref="form" className="users-form" onSubmit={ this.handleAddNew }>
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={function() {}} /><br />
<input ref="email" type="email" name="email" placeholder="email"
value={this.state.email} onChange={function() {}} /><br />
<button type="submit"> Add User </button>
</form>
I am binding the state of username and email to this.state which I am setting to blank in getInitialState like so:
getInitialState() {
return { username: '', email: '' };
}
I am binding state to the form so I can set it to blank after form submission.
The problem with this setup is that the form now renders as readonly.
I cannot get any user input into either text fields. What am I doing wrong?
Your input fields are controlled components, since you are using the value property. This makes the inputs readonly and they will always reflect the value, the variable (in this case, the state variable) holds. You have to explicitly setState onChange since you are setting username field as a state variable.
Read more about it here
onUserNameChange : function(e){
this.setState({username : e.target.value})
},
render: function(){
return ...
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={this.onUserNameChange} /><br />
...
<button type="submit"> Add User </button>
</form>
}
A better way to do this is :
onChange : function(field,e){
this.setState({field: e.target.value});
},
render : function(){
return <form ref="form" className="users-form" onSubmit={ this.handleAddNew }>
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={this.onChange.bind(this,"username")} /><br />
<input ref="email" type="email" name="email" placeholder="email"
value={this.state.email} onChange={this.onChange.bind(this,"email")} /><br />
<button type="submit"> Add User </button>
</form>
}
It looks like you saw the console warning about controlled fields needing an onChange handler and added one just to shut the warning up :)
If you replace your empty onChange handler functions with onChange={this.handleChange} and add this method to your component, it should work:
handleChange(e) {
this.setState({[e.target.name]: e.target.value})
}
(Or for people not using an ES6 transpiler:)
handleChange: function(e) {
var stateChange = {}
stateChange[e.target.name] = e.target.value
this.setState(stateChange)
}
However, if your component is an ES6 class extending React.Component (instead of using React.createClass()), you will also need to ensure the method is bound to the component instance properly, either in render()...
onChange={this.handleChange.bind(this)}
...or in the constructor:
constructor(props) {
super(props)
// ...
this.handleChange = this.handleChange.bind(this)
}