I am using the redux to hide and show components based on a value.
The Redux form documentation mentions the following:
Connecting to multiple fields should be used sparingly, as it will require the entire component to re-render every time any of the fields it is connected to change. This can be a performance bottleneck. Unless you absolutely need to, you should connect to your fields individually with .
I am unclear if my solution to hiding and showing fields based on radio buttons is good enough to use Fields giving the warning to use sparingly.
Can you please clarify if my component merits enough reason to use Fields. If not, what is an alternative way to implement?
Also, how does fields implement validations?
<div>
<form>
<Fields
component={RadioButtonGroupField}
names={['radioButtonGroup', 'nameTextField', 'nickNameTextField']}
/>
</ form>
</div>
function RadioButtonGroupField(fields) {
return(
<div>
<RadioButtonGroupComponent
{...fields.radioButtonGroup.input}
{...fields.radioButtonGroup.meta}
/>
{
(fields.radioButtonGroup.input.value === 'name' ||
fields.radioButtonGroup.input.value === 'both') &&
<NameTextFieldComponent
{...fields.radioButtonGroup.input}
{...fields.radioButtonGroup.meta}
/>
}
{
(fields.radioButtonGroup.input.value === 'nickname' ||
fields.radioButtonGroup.input.value === 'both') &&
<NicknameTextFieldComponent
{...fields.radioButtonGroup.input}
{...fields.radioButtonGroup.meta}
/>
}
</div>
);
}
There is another way you could do that, selecting the specific value using redux-form selectors (http://redux-form.com/6.0.5/docs/api/Selectors.md/) from the redux store in your mapStateToProps and then conditionally rendering certain components.
However, I think that Fields is exactly what you should use in this circumstance. I think that warning is largely to warn people not to go and put their entire form into Fields, having those 3 fields rerender is no big deal.
The thought process that led to the creation of Fields in the first place is probably the best way to get a handle on this: https://github.com/erikras/redux-form/issues/841
Related
I'm trying to add custom validation logic to my react-bootstrap forms, but isInvalid doesn't seem to be respected. As soon as validated={true} is set on the form, it always validates non-empty strings, regardless of isValid or isInvalid. The invalid message is displayed, but the field shows as green. See here:
Here is the offending code:
<Form noValidate validated={formValidated} id="bidForm">
<Form.Group className="mb-3" controlId="formBasicBidding">
<Form.Label>Bid Amount</Form.Label>
<InputGroup hasValidation className="mb-3">
<InputGroup.Text id="inputGroupPrepend">$</InputGroup.Text>
<Form.Control
required
value={bidAmount}
isInvalid={!(parseInt(bidAmount) > 0) && formValidated}
onChange={e => setBidAmount(e.target.value)}
/>
<InputGroup.Text id="inputGroupAppend">.00</InputGroup.Text>
<Form.Control.Feedback type="invalid">
Please select a dollar amount {`>`} 0
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
<...>
</Form>
I was able to get it to work using a pattern= regex on the input, but I'm planning to do more complex validation where a regex won't be sufficient. How can I get react-bootstrap to follow isValid and isInvalid properly? Thanks!
The docs don't do a great job of making this clear, but the form-level validated attribute hooks directly into HTML5's native validation library and can't be used simultaneously with other validation techniques. So if you're using the native option and an input doesn't violate any of the native validation options (required, pattern, etc), then the input will be considered valid. Since you don't have any of the native validation attributes besides required on your bid input, "foo" is valid as far as React-Bootstrap is concerned.
(If you're thinking 'well that's bad code design to let you use both simultaneously', I'd tend to agree with you.)
You'll note that with your current code, if you enter "foo" and submit the form the element actually does have an is-invalid class applied to it, but it's also got the :valid psuedo-selector applied to it because the entire form was validated, which seems to take precedence from a CSS perspective:
The best solution here is to use either the native HTML5 validation option (detailed here) or roll your own (with or without a helper library like Formik), but not both simultaneously.
If you're trying to avoid validating until the input is actually in a "dirty" state (e.g. the user filled it out or submitted the form), you can do something like this (CodePen here):
<Form.Control
required
value={bidAmount}
isInvalid={!(parseInt(bidAmount) > 0) && (bidAmount.length || formSubmitted)}
onChange={(e) => setBidAmount(e.target.value)}
/>
I have a form in reactstrap that has several input fields that uses FormFeedback like this:
<Input invalid={typeof data.name === "undefined" || data.name.length<1} bssize="sm" type="text" name="name" id="name" placeholder="Name" value={data.name} onChange={this.props.handleInputChange} />
<FormFeedback >A name is required</FormFeedback>
<Button color="primary" onClick={this.save} disabled={!this.state.okToSubmit}>Submit</Button>
Is it possible to have the submit button of the form disabled until all fields are validating ok?
I can´t find any way to access the "invalid" prop of a field. The closest I have come so far is to look at the classList of target in the handleInputChange-function. But that feels very hacky and not the best way.
Quite new to React so all help is really appreciated.
There are a number of ways you can accomplish this: Since you are using onChange event handler, you can set another state var.
So, for example, say you have five form elements that you want to have be required. Every time an element is validated, increase that state var by one. Then add a conditional for the button to be disabled or not by disabled={this.state.okToSubmit != 5} (this can also be done using hooks if you're using a functional component.
Another option would be to keep the button live, and do all the validation within the onSubmit handler, but I think most modern day UX is to validate on a per element basis.
What is best practice to change content on a page without creating a route?
BlazeLayout.render('mainLayout', { top: 'header', menu: 'menu', main: 'dashboard', bottom: 'footer' });
How can i hide/show template components inside the dashboard without creating a new route? Should this be done in helpers using some sort of if/else logic in the html and using helper for on button click? Let's say i want to show different content inside dashboard template based on button clicks (href).
Please provide a best practice and good solution that is easy with lots of components.
How can i hide/show template components inside the dashboard without
creating a new route? Should this be done in helpers using some sort
of if/else logic in the html and using helper for on button click?
You can do that but you should be aware of some points to keep your code clean and modular:
Try to wrap parts of your dashboard into own templates to keep the code clean
Use ReactiveDict in favor of many ReactiveVar instances
Wrap recurring parts in templates, too to reduce duplicate code
Register recurring helpers globally or in the most upper template of your Dashboard
Subscribe on the parent template to data that is shared across all parts of the dashboard and subscribe to local data in the respective components
Use autorun and subscription.ready() and display a loading indicator until the subscription is ready. Don't wait to have everything loaded before rendering as this may reduce the UX dramatically.
Let's say i want to show different content inside dashboard template
based on button clicks (href).
You can attach a data attribute to the button, that has a specific id of the target to be toggled:
<template name="dashboardComponent">
<a href class="toggleButton" data-target="targetId">My Link</a>
</template>
You can then read this id and toggle it's state in your ReactiveDict:
Template.dashboardComponent.events({
'click .toggleButton'(event, templateInstance) {
event.preventDefault();
// get the value of 'data-target'
const targetId = $(event.currentTarget).attr('data-target');
// get the current toggle state of target by targetId
const toggleState = templateInstance.state.get( targetId );
// toggle the state of target by targetId
templateInstance.state.set( targetId, !toggleState );
}
});
In your template you can then ask to render by simple if / else:
<template name="dashboardComponent">
<a href class="toggleButton" data-target="targetId">My Link</a>
{{#if visible 'targetId'}}
<div>target is visible</div>
{{/if}}
</template>
And your helper is returning the state:
Template.dashboardComponent.helpers({
visible(targetName) {
return Template.instance().state.get(targetName);
}
});
There could be the problem of sharing the state between parent and child templates and I suggest you to avoid Session where possible. However as beginner it is a lot easier to first use Session and then work towards a more decoupled (parameterized templates) solution step by step.
Please provide a best practice and good solution that is easy with
lots of components.
This is a high demand and it is your competency to work towards both! However here is a short peek into this:
Best practice is what works for you plus can work for others in other use cases. Try to share your work with others to see where it will fail for their use case.
Using routes has the advantage, that you can use query parameters to save the current view state in the url. That adds the advantage, that on reloading the page or sharing via link, the page state can be fully restored.
easy with lots of components is a contradiction and I don't know if you expect some magical puff that solves this complexity for you. As a software engineer it is your competency to abstract the complexity into smaller pieces until you can solve the problem within certain boundaries.
I am trying to get the following behavior in react using redux. I have two side by side components both have a <input> textfield that displays the same value. When I edit either of the field's, I want to dispatch an action and have redux store update the state of my app in both components
Exactly like asana app.
when I edit the field on left it updates the field on the right side as well
and when i edit the field on right, It updates the text field on left as well
I can only get it working one way and not both ways. I am using the value prop of the <input> textfield and keeping a state variable to update the <input> textfield as described in
react-docs.
I have state variable in one component and other one directly listens to the props.
I tried using the defaultValue prop if <input> textfield but it runs into other problems of not updating value when switching between different items
Hard to answer this without seeing your code, but based on what you're saying it sounds like you are storing one input's value on state?
If I want a value to be linked to a global store, I wouldn't store it on state. I'd do something like this (a bit pseudocody but hopefully you get the idea!)
onChange: function (e) {
this.props.dispatch(updateName(e.target.value));
},
render: function() {
return (
<input value={this.props.name} onChange={this.onChange} />
);
}
The dispatch causes an update to the global store which then cascades that updated name value back down to the react component you are currently typing in, as well as the other input elsewhere that is populated by the same data.
Let supplier be documents (with code, names, and many other fields).
I have a component
export class SuppliersDetails extends MeteorComponent {
supplier: any;
invalidKeys: Object; // array <key> => <error message>
and a form
<div>
<input [(ngModel)]="supplier.code" [class.invalid]="invalidKeys['code']" id="code" type="text" class="validate">
<label for="code" [class.active]="supplier.code || invalidKeys['name']" [attr.data-error]="invalidKeys['code']" >Code</label>
</div>
that allow me to edit it.
How could I refactore my component/template, to lighten my template ?
Here it's only 1 field, and only the display of invalidKeys message is handled. But I have 8 fields and some specific logic to add. This will get unreadable.
I am looking for something like
<div>
<input plsDoItAllAndUseThatId='code'></input>
<label plsDoItAllAndUseThatId='code'>Code</input>
</div>
But I have no idea of the design, any idea ?
I would suggest looking into dynamic forms as described in the cookbook section of angular2 docs. The key here is to separate the business logic out of the form itself, such as by creating:
A questions object that will hold all the input properties
A service that will create all the generate all the questions needed by a specific form
A generic component that will loop through a list of questions and bind all the question properties to the input
This would be a good time you could use an attribute directive.
https://angular.io/docs/ts/latest/guide/attribute-directives.html#!#write-directive
You could write it as an attribute like you did in what you want to do. With that you can manipulate the element in the directive to add other attributes if you want or do whatever.
That would make it pretty slick. I'm a fan of this kind of stuff.
Lots of cool stuff you can do with that if you get creative.