How to remove a field after inserting it? - react-jsonschema-forms

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?

Related

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.

Redux form - how to set fields as touched

I'm working with form that consists of multiple pages and I want to solve validation.
When I hit Submit button all fields on the present page shows error messages beneath, but if I change the page then I need to hit submit again because these fields weren't set as touched.
My problem would be solved if I could for example set all fields on the page as touched, once the form has flag anyTouched: true.
I'm using redux-form: '^6.0.0-rc.4' and I have one container where I include redux-form and multiple components consisting of fields.
I think your problem was the opposite way around, but in case anyone lands here as I did looking for a way to have anyTouched set after any field in the form is touched...
In redux-form 6 and above you have to explicitly choose the behaviour you want with the form-level configurations touchOnChange and touchOnBlur - see the docs here - by default nothing is configured and so nothing happens.
const Form = reduxForm({
form: 'my-form',
touchOnChange: true,
touchOnBlur: true
})(...)
These flags make it so that any given field is marked as touched (and therefore anyTouched is marked true on the form) when that field's onChange or onBlur handler is called, respectively.
I should have looked better:
Redux form returns touch as a prop to the component. The function takes names of fields as a parameter, so I'm checking in componentWillUpdate when submitFailed will change and then I'm gonna touch all fields that are not valid.
componentWillUpdate(nextProps) {
const {
formName: { syncErrors },
submitFailed,
touch
} = this.props
if (submitFailed !== nextProps.submitFailed) {
const toTouch = []
for (const key in syncErrors) {
syncErrors.hasOwnProperty(key) && toTouch.push(key)
}
touch(...toTouch)
}
}
In redux-form 7.4.2. This can be achieved by checking to see if the form is valid.
If valid you can can load one of your other pages.
If the form is not valid, use reduxForms getFormSyncErrors selector and pass in the keys returned by this object to the reduxForm touch property.
import React, { Component } from 'react'
import { compose } from 'redux';
import { connect } from 'react-redux';
import { reduxForm, getFormSyncErrors } from 'redux-form';
class MyComponent extends Component {
...
this.props.valid ?
// navigate away
: this.props.touch(...Object.keys(this.props.formErrors))
...
}
function mapStateToProps(state) {
return {
formErrors: getFormSyncErrors('myForm')(state)
}
}
export default compose(
connect(mapStateToProps, null),
reduxForm({form: 'myForm'})
)(MyComponent)

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 keep your model in sync with an {{#each}} block?

I have something like this:
Template.todoList.helpers({
todos: function() {
return Todos.find({}); // Returns records with a todoText, ownerId and done field.
}
});
And then in the template I use a {{#each}} block to list the todos. But I want to be able to change if they are done with a checkbox. If I just add a checkbox like this in the {{#each}} block, it will correctly display the initial state, but if I toggle the checkbox, the record will not update. I would need to keep track of the _id of the record, but where would I store it? If I can get hold of the correct _id the rest is very simple:
Template.todoList.events({
'change .doneCheckbox': function(event) {
var todoId = ??;
Todos.update(todoId, {$set: {done:event.target.checked}});
}
});
What would I insert at the place of ???
Should be available from this (more specifically this._id):
var todo = this,
todoID = todo._id;
You can access other properties from the record too (e.g. this.done).

AngularFire update single object

How to update a single object within node.
{
foo:
{
title: 'hello world',
time: '1000'
}
}
As above, I just want update title.
$firebase(new Firebase(ref).child('foo')).$save(); will update the entire node. Also tried $save('title') but not work.
The reason I just want to update a single object, because some of the ng-model doesn't need to update to firebase.
Heres an example setting the title to "whatever"
$firebase(new Firebase(ref)).$child('foo').$child('title').$set("whatever")
I have recently been working with angularfire and firebase. I am not sure if this is a fix but i dont think you dont need to explicitly select the item property you want to update when you are using the $save() method.
For instance, in my use case i was selecting a user and had an init function that got that whole object
html
<ul ng-repeat="user in vm.users>
<button ng-click="vm.updateUserInit(user)">Edit</button>
</ul>
This then opened up the update form with the users properties. In the controller i took that user and assigned it into a $firebaseObject.
controller
var selectedUser;
vm.updateUserInit = function (user) {
var ref = new Firebase("https://<foo>.firebaseio.com/users/" + user.$id);
selectedUser = $firebaseObject(ref);
}
It justs puts the user into a firebase object as the variable selectedUser to use in the $save.
Then when the user updates the details
html
<button type="button" ng-click="vm.updateUserDetails()">Update User Details</button>
the function already has the selected user as an object to use and anything added will be updated. Anything omitted will not.
controller
vm.updateUserDetails = function () {
selectedUser.firstName = vm.firstName;
selectedUser.$save();
}
The selectedUser.$save(); changes only the first name even though the user has 6 other properties
Not sure if this helps, trying to wrap my head around all of this as well. Check out valcon if you dont already have it. Really nice extension on the chrome inspector for firebase
UPDATE FOR ANGULARFIRE 2
if you create a service for your calls , which could serve all update calls
constructor(private db: AngularFireDatabase) {}
update(fbPath: string, data: any) {
return this.db.object(fbPath).update(data);
}
And then in the page component
this.api.update(`foo`, ({ title: 'foo Title' }) );
Much simpler

Resources