Custom ui:widget will not alter the formData - react-jsonschema-forms

When using ui:widget the field will not change the formData of the form, unlike when not using ui:widget any change in the field will be seen in the formData when the form is submitted.
Shall I change the formData of the form manually when the field text changes? if so, is there an example to do so?
Steps to Reproduce
Create the class that represent the custom UI, and use the following for render:
return (
<div >
{this.props.children}
</div>
)
Add to the schema.properties "City": {type: "string", title:"City"}
Add to the schema.properties "City": { "ui:widget": DefaultInput, classNames: "col-md-4"}
Where City is the name of the custom component.
and DefaultInput is the class that represent the custom ui of field.
Expected behavior
To see the value of the custom text field when submit the form:
onSubmit = ({formData}) => console.log(formData);
What I see is:
{City: undefined}
Any idea?

if you use custom 'ui:widgets' you have to use the json-schema-form onChange method when any item's value gets changed and after that you can get changed value from form.

Related

How can I pass value as GET through a hyperlink?

I have two entities - Budget and Income. On the "view budget" page I have this hyperlink, from where the user can create an income to that specific budget:
Create income to this budget
// Result: /income/new?budget=1
// What I want: /income/new
Is it possible somehow to remove ?budget=1 and still pass on the budget.id as a POST variable value so the hyperlink becomes short: /income/new?
You cant pass post parameters with an anchor
You could use a form though, sth like:
<form action="{{ path('app_income_new') }}" method="POST">
<input type="hidden" name="budget" value="{{ budget.id }}">
<input type="submit" value="Create income to this budget">
</form>
should do the trick, maybe add some css to make it "look like a link"
In order to have this behavior with just an actual anchor <a> element you need to use a javascript event listener to build and submit a form element when the anchor is clicked. You can insert the related data (path & budget.id) into data attributes of the anchor. The event listener can access the data of the clicked anchor (so you can have many with different datasets). Below is a configurable example that can support additional fields by adding the field name where noted, and the appropriate data attribute.
const postAnchors = document.querySelectorAll(".post-link");
postAnchors.forEach((anchor) => {
anchor.addEventListener('click', function(e) {
const fields = [
'budget',
// to support additional fields add here
]
const form = document.createElement('form')
fields.forEach(field => {
if (anchor.dataset[field]) {
const input = document.createElement('input')
input.name = field
input.type = 'text'
input.value = anchor.dataset[field] // data-{field} value
form.append(input)
}
})
form.method = 'post'
form.action = anchor.dataset.action
document.querySelector('body').append(form)
form.submit()
})
})
Create income to this budget

Trim White Spaces From Beginning and End of Form Fields in React-JsonSchema-Form

I'm using react-jsonschema-form 1.2.1 to build a form based on a JsonSchema (v7). I want to automatically trim leading and trailing white spaces from certain text box input fields when a user presses submit on the form. Since the form is completely rendered by the <Form> element of the react-jsonschema-form module, I don't know how I can do this with JavaScript code.
Does react-jsonschema-form have trim capabilities?
Thanks in advance!
There a few different ways to do this, none as simple as flag to trim all string data though.
You can define a custom widget and use the uiSchema to designate specific fields to use this widget. This widget can then trim the value before using the native onChange function to notify the form that its value was changed, refer to: https://react-jsonschema-form.readthedocs.io/en/latest/advanced-customization/#custom-widget-components
You can define your own TextWidget (reserved name, refer to: https://github.com/mozilla-services/react-jsonschema-form/blob/master/src/components/widgets/TextWidget.js => https://github.com/mozilla-services/react-jsonschema-form/blob/master/src/components/widgets/BaseInput.js) and then use this TextWidget to replace all string-type fields:
const myWidgetOverrides = { TextWidget };
render() {
return (
<Form schema={schema}
widgets={this.myWidgetOverrides}
/>
);
}
You can override the validate function inside a new class component that extends the React JSONSchema Form class:
class TrimmedStringForm extends Form {
validate(formData, schema) {
formData = trimAllStrings(formData);
return super.validate(formData, schema);
}
}
or define your own validation function (refer to:
https://react-jsonschema-form.readthedocs.io/en/latest/validation/#custom-validation) to trim all/specific string-type fields from formData before it is passed into the submit function.

How to remove a field after inserting it?

I am building a custom form, I have successfully been able to add new fields at run time into the form as:
Options.schema.properties= {...Options.schema.properties, [key]: {type: "string"} }
Options.uiSchema= {...Options.uiSchema, [key]: { "ui:widget": DefaultInput, classNames: "col-md-4"} }
Where key is the field id, and Options is observable via Mobx
In the form, I am using observable pattern via Mobx to update the schema.properties
Something like this:
class StudentsTab extends Component {
render() {
return (
<MyForm schema={Options.schema} uiSchema={Options.uiSchema} widgets={Options.widgets}
fields={this.customFields}
onChange={log("changed")}
onSubmit={log("submitted")}
onError={log("errors")}
/>
)
}
}
export default observer(StudentsTab);
Although a new fields can be added in this way, however, I could not remove them, my attempt was like:
delete Options.schema.properties[key]
delete Options.uiSchema[key]
I can see that the field id is removed, but its not removed from the DOM
Any idea? How would I remove a field after adding it?

Selected option tag using Meteor

I have an Items collection with a boxId field (and a Boxes collection), and I want to be able to, through a select tag, change an item's boxId.
Here's my template:
And this is how I define the boxOptions helper:
How can I get an item's boxId and use it to find the proper option tag, and then give it the selected attribute?
Create an event
Template.item.helpers({
"change select": function(event){
const boxId = event.target.value;
items.update({_id: this._id}, {$set: {boxId: boxId}});
}
})
Note this assumes you are using the packages insecure and autopublish. If you don't use these and you really should not, then you best read about:
Parameter validation
Publications
Meteor Methods
Use Template.parentData() to have access to the item's id. Here's the helper:
selected: function () {
if (this._id == Template.parentData().boxId) {
return "selected";
}
}

How to add additional classes to django form field

I've just recently learned about:
Form.error_css_class
Form.required_css_class
Docs: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.error_css_class
So by defining 'error_css_class' and 'required_css_class' in forms
class MyForm(forms.Form):
error_css_class = 'error'
required_css_class = 'required'
name = forms.CharField(...)
I can do:
<div class="field-wrapper {{ form.name.css_classes }}">
...
</div>
This will output:
<div class="field-wrapper required">
...
</div>
However I want to add additional classes to the field, e.g I would like to add 'text name' css class for the "name" field. And reading the docs, I think its possible.
https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.BoundField.css_classes
After reading the above I tried to do
self.fields['name'].css_classes('name text')
That doesn't work. I get
'CharField' object has no attribute 'css_classes'
I also tried
name = forms.CharField(css_classes='name text')
TypeError
__init__() got an unexpected keyword argument 'css_classes'
I know I can add extra attr to field widget
self.fields['name'].widget.attrs['class'] = 'name text'
But I want to add css classes to field wrapper.
I could write a custom templatetag... to check field name/type and return appropriate css classes... but if there is something builtin .. I would love to keep my templates clean :-).
Also hardcoding css classes per field is not an option .. as the form fields are dynamic.
Any help will be appreciated.
I figured out how to do it using a custom BoundField
from django.forms import forms
class CustomBoundField(forms.BoundField):
def css_classes(self, extra_classes=None):
# logic for determining css_classes has been omitted
extra_classes = ['name', 'text']
return super(CustomBoundField, self).css_classes(extra_classes=extra_classes)
In my forms, I overide getitem
def __getitem__(self, name):
try:
field = self.fields[name]
except KeyError:
raise KeyError('Key %r not found in Form' % name)
return CustomBoundField(self, field, name)

Resources