I have a form that can have different state based on which button was used for submission; one does a simple submit while the other one adds a flag then submit.
I found a working solution that is, imo, quite ugly, so I'd like to know how else to do it ?
class MyForm extends Component {
// Hijack submit to add published flag
handlePublish = (e) => {
e.preventDefault();
const { handleSubmit, onSubmit } = this.props;
handleSubmit((values) => {
onSubmit({
...values,
isPublished: true,
});
})();
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field
name="foo"
component="input"
/>
<button
type="submit"
onClick={this.handlePublish}
>
Publish
</button>
<button type="submit">
Save
</button>
</form>
);
}
}
✅ This is the idiomatic way. Alternatively, you could provide any number of values as initialValues that don't actually have a Field on the form, but will be submitted.
Related
I am taking coding courses online, so I can build my app sometime next year...
Can you help me with this instant message code please?
a. I am supposed to display an alert message when the user is not logged in.
b. Display the usename in the header.
c. Display the username with his instant message.
Since insecure is removed, I have to use Meteor.methods and meteor.call. I cannot use Sessions. I keep getting weird errors...
Here is the javascript code I have tried based on the course module, but I get errors that don't make sense to me...
Messages = new Mongo.Collection("messages");
if (Meteor.isClient) {
// this will configure the sign up field so it
// they only need a username
Accounts.ui.config({
passwordSignupFields: 'USERNAME_ONLY',
});
Template.messageForm.events({
// this event listener is triggered when they click on
// the post! button on the message form template
'click .js-save-message': function (event) {
var messageText = $('#message-text-input').val();
// notice how tihs has changed since the lsat time
// now we read the username from the Meteor.user()
var messageNickname = "Anon";
if (Meteor.user()) {
messageNickname = Meteor.user().username;
}
var message = {
messageText: messageText,
nickname: messageNickname,
createdOn: new Date()
};
// HERE is where you come in ....
// call a meteor method
// on the server here instead of
if (Meteor.isServer) {
Meteor.methods({ // defines a method, adds extra security layer to app
insertMessage: function () {
var doc, user, euser;
doc = Message.findOne();
if (!doc) {
return;
} // no logged in user, give up
// now I have a doc and possibly a user
user = Meteor.user().profile;
eusers = insertMessage.findOne({ docid: doc._id });
if (!eusers) {
eusers = {
docid: doc._id,
users: {},
};
}
user.lastEdit = new Date();
eusers.users[this.userId] = user;
insertMessage.upsert({ _id: eusers._id }, eusers);
}
}
)
}
// comment out this code, which won't work as we removed insecure...
//Messages.insert(message); // the insecure way of doing it
// ... put code here that calls the
Meteor.call('insertMesage', message, function (err, res) {
if (!res) {
alert('You need to log in!');
}
});
Template.header.helpers({
// HERE is another one for you - can you
// complete the template helper for the 'header' template
// called 'nickname' that
// returns the nickname from the Session variable?, if they have set it
nickname: function () {
if (Meteor.user()) {
return Meteor.user().username;
}
},
});
Template.messageList.helpers({
// this helper provides the list of messages for the
// messageList template
messages: function () {
return Messages.find({}, { sort: { createdOn: -1 } })
}
});
},
});
}
Here is the html file
<body>
{{>header}}
{{>nicknameForm}}
{{>messageList}}
{{>messageForm}}
</body>
<template name="header">
<h1>Welcome to M-Instant {{nickname}}</h1>
</template>
<template name="messageList">
{{#each messages}}
{{>messageItem}}
{{/each}}
</template>
<template name="messageItem">
<h3>{{nickname}} - {{messageText}}</h3>
</template>
<template name="nicknameForm">
<div class="form-group">
<label for="nickname-input">Nickname:</label>
<input type="text" class="form-control" id="nickname-input"
placeholder="Type message here...">
<button type="submit" class="btn btn-default js-set-nickname">Set my
nickname!</button>
</div>
</template>
<template name="messageForm">
<div class="form-group">
<label for="message-text-input">Message:</label>
<input type="text" class="form-control" id="message-text-input"
placeholder="Type message here...">
<button type="submit" class="btn btn-primary js-save-message">Post!
</button>
</div>
</template>
Here is the Methods file
Meteor.methods({
'insertMessage':function(message){
console.log("If you manage to call the method, you'll see this
message in the server console");
if (!Meteor.user()){
return;
}
else {
return Messages.insert(message);
}
}
})
import { Formik, Form, Field } from "formik";
import { Button } from "antd";
const AddUser = () => {
const initialValues = {
name: "",
};
return (
<>
<Formik
initialValues={initialValues}
onSubmit=(values) => {
alert("hi");//calling mamy times
Here added api call (post method)
}}
>
{({ isValid, submitForm, isSubmitting, values }) => {
return (
<Form>
<Field
name="name"
label="Name"
placeholder="Dataset Name"
/>
<Button
type="primar"
htmltype="submit"
loading=(props.addingdata) // this is my reducer state intial was false after post call request became true and success state value false
>
Add Dataset
</Button>
</Form>
);
}}
</Formik>
</div>
</>
);
};
export default AddUser;
I have simple formik form antd button I have used when click submit button post api calling twice and thrice even If I added loading property in button why its happening like this?
I have been asked to tamper with React-Redux code (knowing very little at the moment) and update a colleague's front-end code. One of the application's functionality, is for the administrator to create alert notifications and distribute them across different departments. These departments are selected with checkboxes and finally with a 'Send' button, they alert everyone involved. The form with all the necessary fields, is saved in the database. The notification details page, has detailed information and the mockup that we are supposed to produce, has the involved departments with the same form of grouped checkeboxes (along with their checked/unchecked status).
My colleague had created a reusable component like so:
import React from "react";
import { connect } from "react-redux";
import {reset, change, registerField } from "redux-form";
import _ from "lodash";
import DepartmentTypeCheckBoxes from "./ThreatTypeCheckBoxes";
import { setNotifView, setNotifViewForm } from "Actions/notifView.action";
import { Label } from "reactstrap";
import { ICustomProps } from "Entities/baseForm";
interface INotificationState {
notifStatus?: boolean;
}
interface IProps extends ICustomProps {
registerField(): void;
resetForm(): void;
changeField(value: any): any;
setNotifView(view: any): void;
setNotifViewForm(form: any): void;
}
class DepartmentType extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
};
this.onFieldChange = this.onFieldChange.bind(this);
}
public componentWillMount() {
this.props.registerField();
}
public onFieldChange() {
if(this.state.status && this.state.status == true){
this.setState({ status: false })
this.props.changeField(false);
}
else{
this.setState({ status: true })
this.props.changeField(true);
}
}
public componentWillReceiveProps(nextProps: IProps , nextState: IState) {
}
public render() {
return (
<div className="form-group">
<div className="f" >
<Label for="type">Department Types</Label>
<div className="">
<div className="">
<DepartmentTypeCheckBoxes id="1" value="option1" label="Development" fieldName="development" formName="CreateAlertNotification"></DepartmentTypeCheckBoxes>
</div>
<div className="">
<DepartmentTypeCheckBoxes id="2" value="option2" label="Human resources" fieldName="humanResources" formName="CreateAlertNotification"></DepartmentTypeCheckBoxes>
</div>
<div className="">
<DepartmentTypeCheckBoxes id="3" value="option3" label="Consultance" fieldTag="consultance" formTag="CreateAlertNotification"></DepartmentTypeCheckBoxes>
</div>
</div>
<div className="">
<div className="">
<div className="">
<DepartmentTypeCheckBoxes id="4" value="option4" label="Logistics" fieldTag="logistics" formTag="CreateAlertNotification"></DepartmentTypeCheckBoxes>
</div>
</div>
<div className="">
{this.props.children && this.props.children}
</div>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state: any, ownProps: ICustomProps) => {
return {
};
};
const mapDispatchToProps = (dispatch: any, ownProps: ICustomProps) => {
const formTag = ownProps.formTag;
const fieldTag = ownProps.fieldTag;
return {
registerField: () => dispatch(registerField(formTag, fieldTag, "FieldArray")),
changeField: (value: any) => dispatch(change(formTag, fieldTag, value, false, false)),
setNotifView: (view: any) => dispatch(setNotifView(view)),
setNotifViewForm: (form: any) => dispatch(setNotifViewForm(form)),
resetFields: () => dispatch(reset("CreateAlertNotification")),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(DepartmentType);
and uses it in the submission form like so:
<Row>
<Col md="6">
{ initialValues.ShowDepartmentBoxes &&
<DepartmentType fieldTag="DepType" formTag="CreateAlertNotification">
<Field name="AnotherCustomField" className="form-control" component={renderField} type="text" label="General Information" />
</DepartmentType>
}
</Col>
<Col md="6">
<AnotherCustomField fieldTag="SomeFieldName" formTag="CreateAlertNotification" Mode="create"/>
</Col>
</Row>
I want to use the same DepartmentType field in my "Notification Details" page, with the values loaded in the notification object from the db. Assuming I have 4 bool values like
notification.IsHumanResourcesAlerted
notification.IsDevelopmentAlerted,
notification.IsLogisticsAlerted,
notification.IsConsultanceAlerted
how will I pass them in the details page that is NOT a form and the "value" in the DepartmentTypeCheckBoxes seems to be predefined?
I have not found anything relevant yet and because we are on a tight schedule, I want to try and come up with a solution as possible.
Any help is appreciated.
I might be misunderstanding the implementation of your form and your details page, but if you need the form to exist exactly as it is selected on your send page you could see how the values of this form are being dispatched. With that information you could build something into an existing reducer for your details page or create a new reducer that holds those values and then use them later on to display your details page.
This would most likely be considered improper usage of Redux store (see https://goshakkk.name/should-i-put-form-state-into-redux/ for why I feel that may be the case). But it would work for your implementation as I understand it.
Edit: I should also mention that to display this data you could just display it as the same form as before, but disable the checkboxes so that the preselected values you imported cannot be changed.
Why does my redux-form not submit when I have more than one field?
If I have more than one field then the onSubmit on my form does not run.
The following code will not show the alert :
//#flow
import * as React from 'react';
import {Field, reduxForm, Form} from 'redux-form';
class CustomerPage2 extends React.Component {
constructor(props) {
super(props);
}
render() {
let submit = () => alert("show me the money")
return (
<Form id="myform" onSubmit={submit} >
<Field
label={'asdf'}
className={'input'}
id='1'
name={'salutation'}
mandatory={true}
component='input'
/>
<Field
label={'asdf2'}
className={'input'}
id='2'
name={'first_name'}
mandatory={true}
component='input'
/>
</Form>
);
}
}
export default reduxForm({
form: 'customerRegistration',
})(CustomerPage2)
However if I remove one of the fields the alert will pop up :
render() {
let submit = () => alert("show me the money")
return (
<Form id="myform" onSubmit={submit} >
<Field
label={'asdf'}
className={'input'}
id='1'
name={'salutation'}
mandatory={true}
component='input'
/>
</Form>
);
}
I also created a fiddle where you can see it for your own eyes :
https://jsfiddle.net/036ur33k/150/
Just remove one of the fields and you will see what I mean.
I think you forgot to use the handleSubmit function (redux-form adds it on the component props) in your onSubmit event.
I modified your fiddle, check if it is what you need.
https://jsfiddle.net/036ur33k/173/
I have a redux-form with a react-select. The expected behaviour is that, as I type in the select field, I call the redux action (by using OnInputChange). But I don't know how to call the action. The line that calls the action is commented in the snippet below, because it fails (this.props.getArtistSearch(value)). Any ideas of how to properly call the action as user types in?
class FormApplication extends React.Component {
submit(values) {
this.props.submitForm(values)
}
getArtist(value){
//this.props.getArtistSearch(value) --> props is undefined
console.log(value)
}
render() {
const { handleSubmit } = this.props
return (
<form className='content text padding-top-0' onSubmit={handleSubmit(this.submit.bind(this))}>
<div className='row adjust-form-row'>
<div className='col-md-6 last-lineup'>
<div className='row adjust-form-row'>
<div className='col-md-6'>
<div className='form-group'>
<Field
name='dl_artistname'
options={this.props.gap.artistSearch}
component={props => (
<Select
{...props}
name={props.name}
onInputChange={this.getArtist}
onChange={(value) => {
this.props.requestArtistInstance({id: value.dl_artistid })
return props.input.onChange(value != null ? value.dl_artistid : null)}
}
onBlur={() => props.input.onBlur(props.input.value)}
options={props.options}
//loadOptions={getOptions}
clearable={false}
cache={false}
backspaceRemoves={false}
valueKey='dl_artistid'
labelKey='dl_name'
value={props.input.value || ''}
isLoading={false}
disabled={false}
/>
)}
/>
</div>
</div>
</div>
</div>
</div>
</form>
)
}
}
const mapDispatchToProps = dispatch => ({
getArtistSearch: (text) => {
dispatch(getArtistSearch(text))
},
submitForm: (values) => {
dispatch(submitForm(values))
}
})
Going through your code, I noticed that the custom method you defined, getArtist was not bound to your React context so props will be undefined. Two possible approaches for this are:
1) bind it in the constructor method
constructor(){
super();
this.getArtist = this.getArtist.bind(this);
}
2) Alternatively, bind it in the Select component(Not ideal tho')
onInputChange={this.getArtist.bind(this)}