React/ES6: Trouble Importing a Script - javascript

EDIT: Pinpointed the issue: This code is causing it not to work. If I change it from this:
{this.state.formVisible
? <Form onClick={this.hideForm}/>
: <AddBtn onClick={this.showForm}/>
}
to this:
<Form/>
it works? Why? I don't understand why I can't show and hide the form component and still have the script work???
I'm having trouble correctly using a script in my React app. It was working correctly when I rendered the form directly inside a component (App.js), but I moved the form over to it's own component and now render the component inside App.js, and now the imported scripts won't work.
Here's the breakdown of the two files (the script I need to run is custom.js). As you can see, importing the script into either file doesn't work, as the script is never used.
The first file that renders the "Form" component (App.js):
import React, {Component} from 'react';
import './App.css';
var script = require('./custom.js');
import AddBtn from './AddBtn.js';
import Form from './Form.js';
class App extends Component {
constructor(props, context) {
super(props, context);
this.state = {
formVisible: false
};
};
showForm = () => {
this.setState({formVisible: true});
}
hideForm = () => {
this.setState({formVisible: false});
}
render() {
return (
<div className="header">
<h1 id="p2">Contact Book</h1>
<form className="search">
<input type="text" name="search" placeholder="Search by last name"/>
<button type="button">Search</button>
</form>
{this.state.formVisible
? <Form onClick={this.hideForm}/>
: <AddBtn onClick={this.showForm}/>
}
</div>
);
}
}
export default App;
The second file that contains the form:
import React, {Component} from 'react';
var script = require('./custom.js');
class Form extends Component {
render() {
return (
<form id="addform">
<input type="text" name="fname" placeholder="First name" required/>
<input type="text" name="lname" placeholder="Last name" required/>
<input type="email" name="email" placeholder="email" required/>
<input type="input" name="address" placeholder="address" required/>
<input type="tel" name="phone" placeholder="phone number" required/>
<input type="submit" id="submitbtn" value="Submit"/>
<button type="button" id="closebtn" onClick={this.props.onClick}>Close</button>
</form>
);
}
}
export default Form;
AAAAND the script itself (which doesn't really matter. I already know it works correctly.)
import $ from 'jquery';
//will hold an array of people objects
var list = [];
//constructor that builds new people to add to address book
function Person(first, last, email, address, phone) { //new person constructor
this.firstName = first;
this.lastName = last;
this.email = email;
this.address = address;
this.phone = phone;
};
$(document).ready(function () {
// When the submit button is clicked, create a new person and add the values of
// the form fields to the properties of the object
$("#addform")
.submit(function (e) {
e.preventDefault();
var person = new Person($("input[name = 'fname']").val(), $("input[name = 'lname']").val(), $("input[name = 'email']").val(), $("input[name = 'address']").val(), $("input[name = 'phone']").val());
list.push(person);
console.log(list);
});
});

Instead of relying on DOM nodes which is how jQuery operates, stick within the realm of React.
class Form extends Component {
handleSubmit = e => {
e.preventDefault();
let data = new FormData(e.target)
for (let [key, val] of data.entries()) {
// do something with your data
console.log(key, val);
}
}
render() {
return (
<form id="addform" onSubmit={this.handleSubmit}>
<input type="text" name="fname" placeholder="First name" required/>
<input type="text" name="lname" placeholder="Last name" required/>
<input type="email" name="email" placeholder="email" required/>
<input type="input" name="address" placeholder="address" required/>
<input type="tel" name="phone" placeholder="phone number" required/>
<input type="submit" id="submitbtn" value="Submit"/>
<button type="button" id="closebtn" onClick={this.props.onClick}>Close</button>
</form>
);
}
}
This way you don't need your external script at all, or jQuery for that matter, and you can keep your conditional ternary in your parent component the way it is.

Related

Take user input and onclick button it should load url according to input in new tab in react js

I want to take city name as input and on button click it should call specific url https://www.google.com/maps/search/tourist+places+in+ mumbai with ending url with input value in react. It should open the url in new tab
Destination.jsx (file name)
import React from 'react'
const Destination = () => {
return (
<div>
<h1>Destination</h1>
<input type="text" name="place" class="form-control" id="place" placeholder="Enter place" />
<button type="Submit" id="submit"> Search </button>
</div>
)
}
export default Destination
You can do like this to search places in new tab.
import React from 'react';
const Destination = () => {
const handleSearch = (e) => {
window.open(
`https://www.google.com/maps/search/tourist+places+in+${e.target.place.value}`,
'_blank'
);
};
return (
<div>
<h1>Destination</h1>
<form onSubmit={handleSearch}>
<input
type="text"
name="place"
class="form-control"
id="place"
placeholder="Enter place"
/>
<button type="Submit" id="submit">
Search
</button>
</form>
</div>
);
};
export default Destination;
Create a state:
const [destination, setDestination] = useState("");
Then use this state to populate your search query like this:
<input type="text" name="place" class="form-control" id="place" placeholder="Enter place" value={destination} onChange={(e) => setDesitnation(e.target.value)} />
and then when you submit you can call a custom function on the onClick() of button:
<button id="submit" onClick={searchDestination}> Search </button>
The function might go somwthing like this:
const searchDestination = () => {
window.location.href = `https://www.google.com/maps/search/tourist+places+in+${destination}`;
}

React + EmailJS is sending me tons of emails in onClick method

I'm new to web development in general but I'm trying to create my own Contact page on my website and I'm having trouble. I'm using React, Gatsby, and Emailjs. I have my form set up so that the inputs are passed into the state onChange. Then I have a "send message" button that should send an email using EmailJS using the tokens and the state vars. This does all work and the email sends successfully, but it's sending dozens of emails. I believe what's happening is it's calling sendEmail every time the state is set and the DOM re-renders, or basically once for each character that's input into the fields, but I don't know why.
Bonus points if you can help me figure out why pressing the send message button also sends me to a 404 /# route on my site.
import React from 'react'
import emailjs from 'emailjs-com
class Main extends React.Component {
constructor(){
super()
this.state = {
fromName:'',
message:'',
fromEmail:''
}
}
render() {
return (
<div ...
>
...
<article>
...
<form method="post" action="#">
<div className="field half first">
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" value={this.state.fromName} onChange={e => this.setState({fromName: e.target.value})}/>
</div>
<div className="field half">
<label htmlFor="email">Email</label>
<input type="text" name="email" id="email" value={this.state.fromEmail} onChange={e => this.setState({fromEmail: e.target.value})}/>
</div>
<div className="field">
<label htmlFor="message">Message</label>
<textarea name="message" id="message" rows="4" value={this.state.message} onChange={e => this.setState({message: e.target.value})}
placeholder = "..."></textarea>
</div>
<ul className="actions">
<li>
<input type="submit" value="Send Message" className="special" onClick={this.sendEmail()}/>
</li>
</ul>
</form>
</article>
</div>
)
}
sendEmail() {
const serviceId='...'
const templateId='...'
const userId='...'
emailjs.send(serviceId, templateId, this.state, userId)
}
}
export default Main
The issue is that you never followed the emailjs documentation well and you never prevented the default form action.
According to the emailjs documentation you should have set the onClick function with the send email function (without invoking it) on the form's opening tag NOT on your submit button. (but the button is still necessary so that it can send the sign that the form needs to be submitted). You also invoked the sendEmail function which is inappropriate and leads to problems.
You must also add event as a parameter in your sendEmail function when creating this function. Then inside the sendEmail function call the event.preventDefault() function .
import React from 'react'
import emailjs from 'emailjs-com
class Main extends React.Component {
constructor(){
super()
this.state = {
fromName:'',
message:'',
fromEmail:''
}
}
render() {
return (
<div>
<article>
<form method="post" onClick={this.sendEmail} action="#">
<div className="field half first">
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" value={this.state.fromName} onChange={e => this.setState({fromName: e.target.value})}/>
</div>
<div className="field half">
<label htmlFor="email">Email</label>
<input type="text" name="email" id="email" value={this.state.fromEmail} onChange={e => this.setState({fromEmail: e.target.value})}/>
</div>
<div className="field">
<label htmlFor="message">Message</label>
<textarea name="message" id="message" rows="4" value={this.state.message} onChange={e => this.setState({message: e.target.value})}
placeholder = "..."></textarea>
</div>
<ul className="actions">
<li>
<input type="submit" value="Send Message" className="special"/>
</li>
</ul>
</form>
</article>
</div>
)
}
sendEmail(event) {
event.preventDefault();
const serviceId='...'
const templateId='...'
const userId='...'
emailjs.send(serviceId, templateId, this.state, userId)
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
}
}
export default Main

Local Storage/Session Storage

My Html file is as follows:
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID: [(ngModel)]</b></label>
<input type="text" placeholder="Enter mail ID" [(ngModel)]="mail" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" [(ngModel)]="mail" name="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
My Typescript file is as follows:
import { Component, NgModule, OnInit } from '#angular/core';
import { Router, RouterModule, Routes } from '#angular/router';
import { MyProductPageComponent } from '../my-product-page/my-product-page.component';
#Component({
selector: 'app-my-home-page',
templateUrl: './my-home-page.component.html',
styleUrls: ['./my-home-page.component.css']
})
export class MyHomePageComponent implements OnInit {
phoneNumber = "";
mailID = "";
constructor(private router: Router) {
}
ngOnInit(): void {
}
myFunc() {
localStorage.setItem("phoneNumber", this.phoneNumber);
localStorage.setItem("mail", this.mailID);
this.router.navigate(['/products']);
}
}
const routes: Routes = [
{ path: 'MyProductPageComponent', component: MyProductPageComponent },
]
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
I want to fetch Phone number and Mail ID entered in form and save that in Local Storage. And redirect to the next page. Please help.
Am getting this error: Declaration expected.
you need to use ngmodel to bind the value with input control and same you can access in your component.
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID: </b></label>
<input type="text" [(ngModel)]="mailID" placeholder="Enter mail ID" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" name="phoneNumber" [(ngModel)]="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
Add variables to phone/mail in your .ts components
Use this to variables in myFunc() to get the value of the variables
Use ngModel to bind the variables with the input of the user (set ngModel on the input not label).
Use import { NgModule } from '#angular/core'; in the app.module and NOT in your component
see working code
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID:</b></label>
<input type="text" placeholder="Enter mail ID" [(ngModel)]="mail" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" [(ngModel)]="phoneNumber" name="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
phoneNumber = "";
mailID = "";
myFunc() {
localStorage.setItem("phoneNumber", this.phoneNumber);
localStorage.setItem("mail", this.mailID);
}
const routes: Routes = [
{ path: 'MyProductPageComponent', component: MyProductPageComponent },
]
The path variable should not have a component and you are using router.navigate('/products')
const routes: Routes = [
{ path: 'products', component: MyProductPageComponent },
]
These variables which are used in the ts should bind with the ngModel used in the template
phoneNumber = "";
mailID = "";
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID: </b></label>
<input type="text" placeholder="Enter mail ID" [(ngModel)]="mailID" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" [(ngModel)]="phoneNumber" name="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>

Need to get the multiple form elements in uncontrolled components in reactjs

i am trying to get the multiple form fields input values and sending that to server. But i am only able to get the last field's value on submit.
I am using uncontrolled component because i am trying to editing the form and then updating it.Please help me out to get all the form details entered in the form.
import React from 'react';
import axios from 'axios';
class Update extends React.Component {
constructor(props) {
super(props);
this.state = {
info:''
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
console.log(event);
alert(event);
}
componentDidMount(){
let self = this;
axios.get('http://localhost:8080/studentById')
.then(function(data) {
//console.log(data);
self.setState({info:data.data});
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit} >
<label className="w3-label w3-text-blue w3-large w3-margin-0 ">
First Name:
<input autoFocus type="text" className="w3-input w3-border" defaultValue={this.state.info.Firstname} ref={(input) => this.input = input} required />
</label>
<label className="w3-label w3-text-blue w3-large">
Last Name:
<input type="text" className="w3-input w3-border" defaultValue={this.state.info.Lastname} ref={(input) => this.input = input} required />
</label>
<input className="w3-btn-block w3-blue w3-margin-bottom w3-large" type="submit" value="Submit" />
</div>
)};
}
In your code, you assign all refs to the same variable. (your code simplified for showing what I mean)
First Name:
<input ref={(input) => this.input = input} />
Last Name:
<input ref={(input) => this.input = input} />
Instead use different variable for different input fields:
First Name:
<input ref={(input) => this.firstNameInput = input} />
Last Name:
<input ref={(input) => this.lastNameInput = input} />
You should use different property names for each input inside refs callbacks (currently you override this.input so it points to the last input):
<input autoFocus type="text" className="w3-input w3-border" defaultValue={this.state.info.Firstname} ref={(input) => this.input1 = input} required />
<input autoFocus type="text" className="w3-input w3-border" defaultValue={this.state.info.Firstname} ref={(input) => this.input2 = input} required />
Then inside your component methods you can access value of an input this way:
let inputValue = this.input1.value;

Aurelia: Trigger Validation on tab-out(blur event)

I have returned a validation group to validate my inputs which triggers on submit button and I want to trigger by validation on blur event to trigger respective validation, not all.
For example:
HTML:
<form role="form" submit.delegate="welcome()" validate.bind="validation">
<div class="form-group">
<label for="fn">First Name</label>
<input type="text" value.bind="firstName & updateTrigger:'blur'" class="form-control" id="fn" placeholder="first name" />
<span>${firstName}</span>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
Validation Rule in ViewModel:
this.validation = validation.on(this)
.ensure('firstName')
.isNotEmpty()
.hasMinLength(3)
.hasMaxLength(10);
Since I have written updateTrigger:'blur' none of the validation are getting triggered.
Once you remove updateTrigger:'blur' all the validations are working expected.
Requirement:
I want that once the input box loses focus(blur is triggered) then validation(s) related to 'firstname' are triggered no other validation(of other properties).
Thanks in advance.
This is now supported in the aurelia-validation alpha. Check out this blog post: https://www.danyow.net/aurelia-validation-alpha/
Here's an example: https://gist.run?id=381fdb1a4b0865a4c25026187db865ce
registration-form.html
<template>
<require from="./validation-summary.html"></require>
<h1>Register!</h1>
<form submit.delegate="submit()"
validation-renderer="bootstrap-form"
validation-errors.bind="errors">
<validation-summary errors.bind="errors"
autofocus.bind="controller.validateTrigger === 'manual'">
</validation-summary>
<div class="form-group">
<label class="control-label" for="first">First Name</label>
<input type="text" class="form-control" id="first" placeholder="First Name"
value.bind="firstName & validate">
</div>
<div class="form-group">
<label class="control-label" for="last">Last Name</label>
<input type="text" class="form-control" id="last" placeholder="Last Name"
value.bind="lastName & validate">
</div>
<div class="form-group">
<label class="control-label" for="email">Email</label>
<input type="email" class="form-control" id="email" placeholder="Email"
value.bind="email & validate">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-default" click.delegate="reset()">Reset</button>
</form>
</template>
registration-form.js
import {inject, NewInstance} from 'aurelia-dependency-injection';
import {ValidationController, validateTrigger} from 'aurelia-validation';
import {required, email, ValidationRules} from 'aurelia-validatejs';
#inject(NewInstance.of(ValidationController))
export class RegistrationForm {
#required
firstName = '';
#required
lastName = '';
#required
#email
email = '';
constructor(controller) {
this.controller = controller;
// the default mode is validateTrigger.blur but
// you can change it:
// controller.validateTrigger = validateTrigger.manual;
// controller.validateTrigger = validateTrigger.change;
}
submit() {
let errors = this.controller.validate();
// todo: call server...
}
reset() {
this.firstName = '';
this.lastName = '';
this.email = '';
this.controller.reset();
}
}
Aurelia's validation was updated in late 2016 to include a changeOrBlur validateTrigger option, which in my opinion should be the new default. Here's how to use it:
constructor(controller) {
this.controller = controller;
controller.validateTrigger = validateTrigger.changeOrBlur;
// controller.validateTrigger = validateTrigger.blur; (default)
// controller.validateTrigger = validateTrigger.change;
// controller.validateTrigger = validateTrigger.changeOrBlur;
// controller.validateTrigger = validateTrigger.manual;
}

Categories