I'm using redux-form-material-ui for the forms. I have simple form with two text fields. This form will show the initalValues passed to it and user can also update the values of TextField. These TextFields working fine with validations and all but I'm facing problem while re-rendering. On route change, I'm passing the different intialValues to that form component but even though proper values passed to it, TextFields are not getting updated. It just shows the first time passed initialValues.
Here is my code:
From parent component:
<ReduxForm {...initialValues} />
ReduxForm component:
class ReduxForm extends React.Component {
render () {
return (
<div>
<form onSubmit={() => console.log('Submitted')} >
<Field
className='input-field'
name='name'
component={TextField}
floatingLabelText='Full Name'
/>
<Field
className='input-field'
name='email'
component={TextField}
floatingLabelText='Email'
/>
</form>
</div>
)
}
}
export default reduxForm({
form: 'test-form',
validate
})(ReduxForm)
I Know that, this is the same problem with defaultValue in material-ui's TextField. Is this expected behavior in redux-form-material-ui also? If so, is there way I can solve this issue without setting the state and all?
Thank you!
Haven't used redux-form-material-ui but try adding enableReinitialize: true to your reduxForm decorator
export default reduxForm({
form: 'test-form',
validate,
enableReinitialize: true
})(ReduxForm);
And see if that works.
Related
Maybe I'll start with what I want to achieve: I have a form with a required field. By default it should not display any error. The error should be displayed if a user touches the field. So my field looks more or less like this:
<ion-input .... (ionBlur)="updateDispayedErrors()"></ion-input>
But I don't know how to test it because:
Running fixture.debugElement.nativeElement.blur() does not triggers ionBlur handler (the same with ....dispatchEvent(new Event('blur')))
Plain angular (blur) does not work (i.e. if I change the code to (blur)="updateDisplayErrors()" then it does not work)
It seems that calling blur() method on native <input .../> element that is created in the browser would work but... the problem is that when I run the tests fixture.debugElement.nativeElement.childNodes is empty... So the native <input .../> is not created
Please let me know if you would like to see a full example to illustrate it.
If you add a selector to ion-input like:
<ion-input .... (ionBlur)="updateDisplayedErrors()" id="specialInput"></ion-input>
Then you can use fixture.debugElement.triggerEventHandler:
import { By } from '#angular/platform-browser';
...
it('should emit ionBlur', () => {
const ionDe = fixture.debugElement.query(By.css('#specialInput'));
const ionBlurResult = spyOn(component, 'updateDisplayedErrors');
ionDe.triggerEventHandler('ionBlur', {});
expect(ionBlurResult).toHaveBeenCalled();
});
I am just a beginner in reactjs. I feel so good about using it, but I have been stuck for a while on a concept that I wanna implement, that would solve me whole lot of other issues.
Concept
I want to create a form component that can have dynamic children passed to it. It won't be a specific form component like LoginForm, ContactForm etc. Rather it would just be Form.
Approach 1
class LoginPage extends Rect.Component {
constructor(props) {
super(props)
this.submit = this.submit.bind(this);
this.validate = this.validate.bind(this);
this.reset = this.reset.bind(this);
}
submit(...args) {
this.refs.form.submit(args);
}
validate(...args) {
this.refs.form.validate(args);
}
reset(...args) {
this.refs.form.reset(args);
}
render() {
return (
<LoginPage>
<Form ref="form" onSubmit={this.submit}>
<Input value="email" pattern="/email_pattern/" onValidate={this.validate} />
<Input value="password" pattern="/password_pattern/" onValidate={this.validate} />
<Button value="submit" action={this.submit} />
<Button value="reset" action={this.reset} />
</Form>
</LoginPage>
}
}
Input onChange calls the validate function that just passes on the args to the Form's validate function. For the Form to know if all it's children's are validated. I pass isValid and targetInputComponent as args to the form.
Button Submit onClick calls the submit function likewise and LoginPage (acts as middleware) passes the call to the Form component. Form check it's state for inValid inputs etc.
Button Reset onClick call is passed to the Form component likewise. But how do the form handle this reset functionality? Input's value is controlled by LoginPage. Form can't change the input's value.
Aproach 2
What I did was add the input's data and validity to the LoginPage state. Now both Form and Inputs just call the Login Page to update it's state. Form and Inputs components are using this state as prop.
class LoginPage extends React.Component {
constructor(props) {
super(props)
this.state = {
formSchema: this.initSchema()
}
this.validateField = this.validateField.bind(this);
this.submitForm = this.submitForm.bind(this);
}
initSchema() {
const formSchema = {
email: {
isValid: false,
value: ''
},
password: {
isValid: false,
value: ''
},
password2: {
isValid: false,
value: ''
}
}
return formSchema;
}
validateField(dataObj, targetComponent) {
const formSchema = Object.assign(this.state.formSchema, dataObj);
this.setState({ formSchema })
}
submitForm(isSuccess) {
console.log(isSuccess);
console.log('Form Submit: ', this.state.formSchema);
throw new Error('Submition Error');
}
reset() {
// Loop through each object in formSchema and set it's value to empty, inputs will validate themselves automatically.
}
render() {
return <div>
<Form ref="formLogin" className="auth-form" onSubmit={this.submitForm} formSchema={this.state.formSchema}>
<h1>
Switch Accounts
</h1>
<Input type="email" name="email" onValidate={this.validateField} value={this.state.formSchema.email.value}
isValid={this.state.formSchema.email.isValid}/>
<Input type="password" name="password" onValidate={this.validateField} value={this.state.formSchema.password.value}
isValid={this.state.formSchema.password.isValid}/>
<Button value="Submit" type="submit" />
</Form>
</div>
}
}
Problem
This approach is making the LoginPage Component quite messy. How will the LoginPage component will handle the forms if I have more than 1 form on the page? There will be even more features to LoginPage like Lists, Grid, Modals etc. This LoginPage shouldn't Handle these situations. Form should be responsible for all the inputs, submition, etc functionality. This form component should be generic to all types of forms. I don't want to create feature forms like LoginForm, ContactForm, etc.
The solution to this issue will aid me a lot in whole lot of other components.
Your approach 2 is the standard way of handling this problem.
Why wouldn't you create a separate <LoginForm>? Doing so can abstract the fields and validation away from other unrelated functionalities on your page.
If later you need a <ContactForm> or any other type of form, it will have different fields and different validation logic, meaning you'll need to build it out regardless.
Short of using something like redux, you're on the right track.
There are numerous ways to make ‘generic’ forms. But in my opinion it is best to keep the forms seperatly.
The reason why I say this, is because one way or another, you still have to implement various validation condition for most fields, such as e-mailaddress or what ever you will use.
I think the best approach is to make the components individual. For example: make a TextField component that handles input stuff like validation. Maybe a Button component for submit and callbacks.
So my advise: keep the forms seperatie. No need to overthink and lose useful time in trying to make things ‘pretty’.
Goodluck!
I have been trying to figure out how to bind a value to a textbox in Angular2. Currently I have a textbox with a placeholder that is loaded with a predetermined value.
<input id="textbox" class="k-textbox" placeholder={{label}} />
But once I change a value of a date component, I would want the placeholder value to be updated to the date value selected. So far i wrote this but this doesn't seem to be working. Please advice.
date-component.html
<input id="datepicker" (input)="changeLabel()"/>
date-component.ts
label:string;
constructor() {
this.label = 'Select Date';
}
changeLabel() {
this.label = 'Date Selected';
}
}
use an click event to propagate the changes.
date-component.html
<input id="datepicker" (click)="changeLabel()"/> //<-- click event
You could use two way databinding with NgModel.
https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel
Basically this would make "label" change to whatever the user types.
<input [(ngModel)]="label" id="datepicker" />
You will also need to import FormsModule in your app.
Plunker to show what I mean:
https://plnkr.co/edit/CfmalT7GesrP5lzBsNFx?p=preview
use keyup Event
<input (keyup)="changeLabel()">
enter the value its call the keyup event
How to hide a text field in play framework? For example how to hide this field:
#inputText(userProfileForm("name"), '_label -> "Name")
This should work in all browsers:
#inputText(
userProfileForm("name"),
'_label -> "Name",
'style -> "display: none"
)
Note that this only hides the field, not the label etc.
If you want to hide the label aswell, you can't do this with the default helpers.
You can however specify the input field yourself:
<input type="hidden" name="name" value="#userProfileForm.data.get("name")" />
The name should be name of the field in your form (coincidentally name aswell in this case).
I haven't tested the value but it should work, maybe you'll need to strip the " around name.
If you do this, the hidden data will be sent, along with the other data in the form to the server.
Edit:
If the hidden value is empty, that means you didn't bind it to the form when calling the view. You can bind the name to the form like this in Java (I don't know Scala, but it's explained in the Play Scala documentation):
Map<String, String> data = new HashMap<>();
data.put("name","get the username here");
return ok(index.render(userProfileForm.bind(data));
Another option (which is cleaner in my opinion) is to simply pass the username as an argument to the view. The controller becomes:
return ok(index.render(userProfileForm, "username goes here"));
And in the view you can then simply do:
#(userProfileForm : Form[UserProfileForm])(name : String)
#helper.form(...){
<input type="hidden" name="name" value="#name" />
//...
}
The inputText helper takes a varargs of (Symbol, Any), which represent the html attributes. If you are using html5 you can just add the hidden attribute:
#inputText(userProfileForm("name"), '_label -> "Name", 'hidden -> "hidden")
normally the hidden attribute has no value, but I couldn't find any information about how to do this with the helpers. In Chrome at least it works like this as well.
edit:
btw, you can also just use html instead of the helper:
<input attribute=value hidden />
I know that this is an old question, but i had a similar issue, i wanted to hide an inputText and still, handle it using the helpers.
The best and cleanest way to do it is to write your own helper adding a custom value to tell when to hide the element itself.
I came to a solution like this
my own field constructor
#(elements: helper.FieldElements)
#if(elements.args.contains('hideIt)){
#elements.input
}else{
<div class="#if(elements.hasErrors) {error}">
<div class="input">
#elements.input
<span class="errors">#elements.errors.mkString(", ")</span>
<span class="help">#elements.infos.mkString(", ")</span>
</div>
</div>
}
that i used in the view file like this:
#inputText(form("fieldName"),
'hidden -> "true",
'hideIt -> true
)
now you are done :)
While it worked, I didn't like the hashmap version provided by #Aerus, preferring to use the statically typed forms when possible, so I came up with an alternative.
final UserProfileForm initial = new UserProfileForm("get the username here");
return ok(index.render(Form.form(UserProfileForm.class).fill(initial));
Then, in the profile, you can do as follows:
<input type="hidden" name="name" value="#userProfileForm("name").value" />
Here is the zul file for reference
<?page title="MVVM Tree POC"?>
<zk>
<borderlayout height="800px">
<west size="25%"></west>
<center>
<window apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('com.nagarro.viewmodel.TreeViewModel')"
title="Dynamic Tree" border="normal">
<tree checkmark="true" model="#bind(vm.treeModel)"
onSelect="#command('select')" >
<template name="model" var="node" status="s">
<treeitem checkable="#load(node.checkable)"
open="true">
<treerow style="text-align:center;">
<treecell
label="#bind(node.data.firstName)" style="text-align:left;">
</treecell>
</treerow>
</treeitem>
</template>
</tree>
</window>
</center>
</borderlayout>
</zk>
There is a "onSelect" event in the tree tag and there are checkboxes for some treeItems only. Now, I want to create certain components like a combobox for the corresponding tree row when its checkbox is selected. I am trying to do it with the onSelect event of the tree but the problem is I need to pass the reference of the selected checkbox which I am unable to pass as the onSelect event is kept outside the scope of the template through which treeItems are getting rendered.
Is there any other way out to do what I want
This is the page which I get through the above zul file.
I want to know which checkbox is selected ?
You can pass any parameter on every event like that (from ZK docs):
<button label="Delete" onClick="#command('delete', item=item)"/>
and use this parameter in your java code:
#Command
public void delete(#BindingParam("item") Item item ) {
//do some stuff based on what item you've picked
}
In your case I would move onSelect-Event from Tree-Component to Treeitem, like this:
<tree checkmark="true" model="#bind(vm.treeModel)">
<template name="model" var="node" status="s">
<treeitem checkable="#load(node.checkable)"
open="true" onSelect="#command('select', nameParameter=node.data.firstName">
<treerow style="text-align:center;">
<treecell
label="#bind(node.data.firstName)" style="text-align:left;">
</treecell>
</treerow>
</treeitem>
</template>
</tree>
and use parameter in your #Command-method:
#Command
public void select(#BindingParam("nameParameter") String nameParameter ) {
System.out.println(nameParameter + " selected");
}
See ZK MVVM > Advance > Parameter Docs for more information
This is an issue I often run into. My solution has always been to attach data to the component itself; keep a database entity's id or an object itself on the checkbox for retrieval during the event.
checkbox.setAttribute("myAttributeName", myAttributeValue);
This requires a cast to retrieve, which is unfortunate, but with some best practices you can do so confidently.