How to make a dynamic watch()/usewatch() with react-hook-forms - reactjs

I am having an issue were I need to generate a form from a schema and have fields dependent on each other such as enabled/disable show/hide etc.
my schema looks something like this.
contractorInformation: {
title: "ContractorInformation",
type: "object",
properties: {
contractorName: {
title: "Contractor Name",
type: "string",
ui: "input",
constraints: {
required: true
}
},
contractorFavouriteAnimal: {
title: "Contractor Favourite Animal",
type: "string",
ui: "input",
constraints: {},
dependencies: {
disabled: true,
watching: "contractorName"
// //disabled={!fullName || fullName.length === 0 || errors.fullName}
}
},
contractorEmail: {
title: "Contractor Email",
type: "string",
ui: "input",
constraints: {
common: 10
}
}
}
},
agencyInformation: {
title: "ContractorInformation",
type: "object",
properties: {
contractorName: {
title: "Contractor Name",
type: "string",
ui: "input",
constraints: {
required: true,
minLength: 3,
maxLength: 5
},
dependencies: {
disabled: true,
watching: "agencyName"
}
}
}
}
}
const watchThese = watch()
would allow me to watch everything but if I wanted to change this field from disabled to enabled I could use
<input disabled={!watchThese || watchThese.length === 0 || watchThese.fullName}/>
which works but is obviously triggered by every field.
How could I generate a dynamic watch()/useWatch() from a schema and be able to access the specific dependencies I need to enable/disable the input.
Any help would be gratefully received.

For future reference I solved it by using
export const FormField = () =>
{Object.entries(schema?.actions ?? {}).forEach(([key, value]) => value(watch(key)));
return (<div></div>)}
and update schema to match.

Related

How to get select option label in addition to its value in react antd form?

I used antd-form-builder to create a form. The form contains select field (dropdown). I used form.getFieldValue("task") to get the value of selected option, I also need to get the label of selected option. how can I get it by clicking on a button?
const meta = (
fields: [
{
key: "task",
label: "Task",
widget: "select",
widgetProps: { showSearch: true },
options: [
{ label: "Pre-filter Replacement", value: 1 },
{ label: "Oil Change", value: 2 },
],
},
]
)
const handleClick = () => {
let taskValue = form.getFieldValue("task")
}
<Form form={form} onValuesChange={forceUpdate} onFinish={onFinish}>
<FormBuilder meta={meta} form={form} />
<Button onClick={handleClick}>Done</Button>
</Form>
You can use labelInValue prop to get the value along with selected option label.
Pass labelInValue: true, in widgetProps
const meta = {
fields: [
{
key: "task",
label: "Task",
widget: "select",
widgetProps: {
showSearch: true,
labelInValue: true,
},
options: [
{ label: "Pre-filter Replacement", value: 1 },
{ label: "Oil Change", value: 2 },
],
},
],
};
Now task value will not be a number buy an object containing label, value, key, disabled.
You can follow the Select API Documentation

I am having difficulty accessing this nested array to carry out an update

SCHEMA
Below is my schema structure, kindly correct me if I am getting it wrong. I want to be able to update the ConnectState from false to true using an ObjectId
phones: {
type: String,
required: true,
},
User: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
// required: true,
},
Userpost: {
type: mongoose.Schema.Types.ObjectId,
ref: "userpost",
// required: true,
},
friendshipStatus: [
{
isFriend: {
FProfile: {
type: mongoose.Schema.Types.ObjectId,
ref: "profile",
},
ConnectStatus: {
type: Boolean,
default: false,
},
},
},
],
});
What I have tried
I want to update the Boolean value on ConnectStatus from false to true. I know I am getting the process wrong.
const result = await Profile.updateOne(
{ "friendshipStatus.isFriend.FProfile": uid },
{ $set: { "friendshipStatus.$.isFriend.ConnectStatus": true } },
{ arrayFilters: [{ "friendshipStatus.isFriend.FProfile": uid }] }
);
Try with:
const result = await Profile.update(
{ 'friendshipStatus.isFriend.FProfile': uid },
{ $set: { 'friendshipStatus.$.isFriend.ConnectStatus': true } },
);

Is it possible to add label to rjsf `oneOf` controling select?

Let's take the default oneOf example from rjsf docs:
const schema = const schema = {
type: 'object',
oneOf: [
{
properties: {
lorem: {
type: 'string'
}
},
required: ['lorem']
},
{
properties: {
ipsum: { type: 'string' }
},
required: ['ipsum']
}
]
}
official codepen demo here
Is it possible to add a label to the select that switches between oneOf items?
You can add a field (in the example I named it "dropdownField") whose value is the condition for showing the other fields.
That field can have a title just like the others.
{
type: "object",
properties: {
dropdownField: {
title: "Your label goes here",
type: "string",
enum: ["Option 1", "Option 2"],
default: "Option 1",
},
},
dependencies: {
dropdown: {
oneOf: [
{
properties: {
dropdown: { enum: ["Option 1"] },
lorem: {
type: "string",
},
},
required: ["lorem"],
},
{
properties: {
dropdown: { enum: ["Option 2"] },
ipsum: {
type: "string",
},
},
required: ["ipsum"],
},
],
},
},
}
You can read more at the "dependencies" page.

How to make array type schema objects appear one in a row? react-jsonschema-form

I am using react-jsonschema-form to create a form. Single components are displaying fine but array components are coming in a row. How Can I make them appear one array object in a row so that everytime I click Add button , new array object is rendered in new row. Code is as follows:
const schema = {
type: "object",
properties: {
Name: { type: "string", title: "Name", default: "A new Task" },
Title: { type: "object", properties: { First: { type: "string" }, Second: { type: "string" } } },
XYZ: { type: "array", items: { type: "object", properties: { Third: { type: "string" }, Forth: { type: "boolean", enum: [true, false], enumNames: ["True", "False"] } } } }
}
}
const uiSchema = {
"ui:order": ["Name", "Title", "Done"],
Name: { "ui:widget": "textarea" },
Title: { First: { "ui:widget": "textarea" }, Second: { "ui:widget": "textarea" } },
XYZ: { items: { Third: { "ui:widget": "textarea" }, Forth: { "ui:widget": "radio", "ui:options": { inline: true } } }, "ui:options": { orderable: false, removable: true, inline: false } }
}
Form Code is as Follows:
<Form schema={schema}
// formData = {defaultData}
uiSchema={uiSchema}
onChange={log("changed")}
onSubmit={SubmitRoutine}
onError={ErrorRoutine}
/>
As shown in the following picture Array XYZ objects are fixed width and displaying next to each other. I want them full width and every object in new row. I am using React and Bootstrap4
Also very time I have to even add first object by clicking Plus button. I want first object to appear itself. Please let me know how may I fix it. Thanks
Checkout this library. It allows laying out your form using bootstrap-grid.
It could be achieved with pure CSS, provided there is no need to reflect order in the model:
/* class of a wrapping element */
.array-item-list {
display: flex;
/* column, column-reverse, row, row-reverse */
flex-direction: column-reverse;
}

Node Js, Sequelize and Jade. How get data from has-many associations between them?

I'm working on a NodeJS+Sequelize+jade web-app. I have a table called box and another one called user. The user has a one-to-many relation with box. What I like to do is list and show in a jade-template all the box details, including the user who owns it.
First I created the tables using sequelize tools
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
dateOfBirth: DataTypes.DATE,
role: {
type: DataTypes.ENUM,
values: ['ADMIN', 'USER'],
defaultValue: 'USER'
}
},{
classMethods:{
associate: function(models) {
User.hasMany(models.Box);
}
})
return User;
};
The same to box:
module.exports = function(sequelize, DataTypes) {
var Box = sequelize.define('Box',{
boxTitle: {
type : DataTypes.STRING,
allowNull: false
},
lifetime: {
type : DataTypes.DATE,
allowNull : false
},
status: {
type: DataTypes.ENUM,
values: ['ACTIVE', 'NOTACTIVE'],
defaultValue: 'ACTIVE'
},
count: {
type: DataTypes.INTEGER,
allowNull : false
}
},{
classMethods:{
associate: function(models) {
Box.belongsTo(models.User);
}
});
return Box;
};
So, when I put some data in the database, I'm trying to print te box information:
each box in boxes
each user in box.users
tr
td= box.getDataValue('boxTitle')
td= user.getDataValue('name')
td= box.getDataValue('lifetime')
td= box.getDataValue('count')
td= box.getDataValue('status')
I did this so far, but I'm getting an error:
Cannot read property 'length' of undefined
I believe the program is not recognizing the association between those two tables, but I'm not sure.
Does anyone knows how can I solve this problem, or maybe to it in a different way?
I would be very grateful if you could help me.

Resources