AutoForm 5.0.2 nested schema inputs required on update - validation

I have schemas set up so that I can have an array of complex input sets. Something like:
address = {
street:{
type: String
},
city: {
type: String
},
active_address: {
type: Boolean,
optional: true
},
...
}
people: {
name:{
type: String
},
address:{
type: [address],
optional: true,
defaultValue: []
}
}
This way adding an address is optional, but if you add an address all of the address fields are required.
This worked in (I believe it was) version 4.2.2. This still works on insert type autoforms, but not on update type autoforms. Doing an update, none of the fields will submit unless all required fields in the nested schema are also valid.
For reference, I'm creating the form as such:
{{#autoForm collection="people" id=formId type="update" doc=getDocument autosave=true template="autoupdate"}}
{{> afQuickField name='name' template="autoupdate" placeholder="schemaLabel"}}
{{> afQuickField name='address' template="autoupdate"}}
{{/autoForm}}
My templates (autoupdate) I copy-pasted the entirety of bootstrap3 autoform templates and rearranged some of the html to fit my needs. I updated these to the best of my ability according to the 5.0.0 changelog when I updated. It could possibly be in there if someone can think of an attribute in the templates that would cause inconsistent behavior between insert and update that changed in 5.0.0.
More information
I just tried recreating all of my form templates using the bootstrap3 templates from 5.0.2. Still the same behavior.
+
I have a Boolean (checkbox) input in the address schema. Looking in a doc, the address array is populated with [0 : {active_address: false}]
active_address: {
type: Boolean,
optional: true
}
Not sure if that helps...
+
As per #mark's suggestion, I added defaultValue:[]. It fixed the issue... sort of. There are no "open" nested schemas in the update form now, and other values can be changed. If you "add" a nested schema to the form with the add button, that entire form becomes required even if you don't insert any value in any field. This happens regardless of the Boolean type input.
I can nail down the Boolean type input in the nested schema causes that entire nested schema to become necessary to do the insert. Removing the Boolean input caused it to be insertable again. So there's a new problem in the same vein.
This new issue can be found here

I think the best solution is to add a defaultValue: [] to the address field in the schema. The behavior you described in the question (not allowing the update) is actually intended -- read on to see why.
The thing is, this behavior only exists if an array form element has already been added to the form. What I mean is, if you click the minus sign that removes the street, city, etc. inputs from the form, the update succeeds because AutoForm doesn't misinterpret the unchecked checkbox as the user explicitly unchecking the box (and therefore setting the value to false). Setting the defaultValue to an empty array lets AutoForm know to not present the address form unless the user has explicitly clicked the plus sign (i.e, they have an address they want to enter), in which case the behavior of making the street, city, etc. fields required is what you want.
Note that this means you'll have to update the existing documents in your collection that are missing the address field and set it to an empty array. Something like this in the mongo shell:
db.people.update({ "address": { $exists: false } }, { $set: { "address": [] } }, { multi: true })
You'll probably want to make sure that the query is correct by running a find on the selector first.
Edit
If the behavior you want is to show the sub-form without making it required, you can work around the checkbox issue by using the formToDoc hook and filtering out all address objects that only have the active_address field set to false (the field that AutoForm mistakenly adds for us).
AutoForm.addHooks('yourFormId', {
formToDoc: function (doc) {
doc.address = _.reject(doc.address, function (a) {
return !a.street && !a.city && !a.active_address;
});
return doc;
}
});
The formToDoc hook is called every time the form is validated, so you can use it to modify the doc to make it so that AutoForm is never even aware that there is an address sub-field, unless a property of it has been set. Note that if you're using this solution you won't have to add the defaultValue: [] as stated above.

Related

GraphQL - Execute sub query conditionally

I'm trying to optimise the query executed by some of my react components that are shared across the whole app, such as Footer and Header components.
I'm trying not to fetch the Student Solution details when the variable institutionPath is not provided.
query organisationAndInstitution($organisationName: String!, $institutionPath: String!, $fetchInstitution: Boolean!){
organisation(where: {
name: $organisationName
}){
name
}
studentSolutionRelationships(where:{
AND: [
{
status: PUBLISHED
},
{
studentSolution: {
status: PUBLISHED
}
}
]
}) #include(if: $fetchInstitution) {
status
}
}
To do so, I added a fetchInstitution boolean variable and added the #include(if: $fetchInstitution) directive.
But directives seem to apply only on fields, not on whole queries. So I wonder if what I want to do is possible, because the way I wrote it is invalid.
Any field in a GraphQL document can be explicitly included using the #include directive or explicitly excluded using the #skip directive. The directive should be provided after the field name and arguments, but before the field's selection set, if it has one, as shown in your question:
studentSolutionRelationships(where:{
#...input fields omitted for brevity
}) #include(if: $fetchInstitution) {
status
}
The directive takes a single argument (if) which must be a Boolean value. This value may be a literal (i.e. true or false) or a variable of the Boolean type. GraphQL does not provide a way to evaluate expressions -- any conditional logic has to be reside in the client code and be used to determine the value of the variable passed to the if argument.
The directives may be applied to any field in a document, including root-level ones like studentSolutionRelationships and organisation in the question. In fact, you can exclude all root fields using these directives -- just keep in mind that in such a scenario, the query will still run and just return an empty object.
In other words, your approach here is correct. If the query is failing, it's because of an unrelated issue.

Can I dump a Symfony form's validation schema to JSON?

I'm considering setting up some proof-of-concept tool that could grab metadata from a Symfony2 FormType instance in order to dump a validation schema as JSON, something like the following:
[
{
name: 'someFieldName',
value: '',
email: true
},
{
name: 'yetAnotherFieldName',
value: 'I have a default value',
required: true
}
]
The aim obviously is to use it in front-end JS code (let's say React), to be able to set up the same validation constraints, as much as possible (required and the likes).
However, Symfony is well-architectured and its Form component knows nothing about validation. Considering only the nominal case of a simple form to begin with, how would one go about doing it? How to map back the form to the validatable objects/entities it references?
Using the symfony validator you can get the metadata for a given class:
$this->get('validator')->getMetadataFor(Foo::class);
It returns a ClassMetadata instance. If the passed value is an entity, you will have the members and properties properties returned which then contain a constraints property with the classes being used.
Final step is to serialize that in JSON.

Kendo - creating a custom model property with value from server property

I have a property called Copies which is defined on the server that represents the default number of copies allowed. And I can update this value and it will update an input field on my UI.
however, I would like to be able to reset the Copies property to the original value if the user resets this field on the UI.
My idea was to define a custom property on my kendo datasource model called originalValue that references the Copies property. but this just seems to override the Copies property if I do something like this.
schema: {
data: 'd',
total: function (data) {
return data.d.length;
},
model: {
originalCopies: "Copies"
}
}
how can I go about creating a custom property like this which is basically a immutable clone of my Copies property?
You can try to do it on the server side, just create a separate property "OriginalCopies" and set it to Copies. Once passed to the client side , it will lose its immutability.
Something similar could be done on the client side as well. JSON.stringify your Copies and set
OriginalCopies to the JSON.parse value of the stringified variable as:
var copies = JSON.stringify(data.Copies);
data.OriginalCopies = JSON.parse(copies);

Validation of dynamic fields in a MVC

My model looks like
public class Template
{
Id
Title
List<Field> Fields
}
The “Field” Entity contains information like Name, Caption, Type (TextBox/Select/Radio), Options, and validation rules (Range, Required, string length).
The standard validation in MVC is based on DataAnnotations, but I wants to validate (Both client and Server Side) the form dynamically based on Field Metadata which is dynamic and configurable.
Is it possible? Any pointers?
PS. I searched for the similar questions, but not able to find a solid answer.
I had a similar situation, this is how I handled it:
Server Side
When the POST happened I iterated over all the Fields values and did the Validation based on the validation rules I had on my objects. Then you can simply add ModelErrors to the Field object.
Since you push a Template object to the View you can access the Fields by name Fields[x].SomeProperty. Make sure you have a ValidationMessageFor for SomeProperty
ModelState.AddModelError("Fields[x].SomeProperty", "The Error Message you want to show.);
Client side
Make sure your form has an Id so you can access the Validate method().
Then you iterate over all the fields and just add the validation as you please.
For all the validations rules check the validation Jquery documentation.
$('#frmYourForm').validate();
for (var i = 0; i < 'CountOfAllFields'; i++)
{
$('#Fields_' + i + '__Foo').rules('add', { required: true, messages: { required: 'The Foo field is required'} });
$('#Fields_' + i + '__Bar').rules('add', { required: true, messages: { required: 'The Bar field is required'} });
}
I hope I helped you on your way !
Ps, use FireBug to help you find the correct names of the properties and that's how you can link them with the ModelErrors in the modelstate etc.

jqGrid saving a row with nullable columns

So I have a jqGrid on an ASP.NET MVC 3 website. It's loading the data, searching, filtering, and saving rows with the built in pop-up editor. What I can't get to work is saving a nullable property. I'm using LargeJsonResult instead of the built in JsonResult, so an example of a row in the grid is this:
// C# class
public class Row
{
public string A { get; set; }
public string B { get; set; }
public int C { get; set; }
}
// an example object instance, let's say these values come from the DB
var ret = new Row { A = "a", B = null, C = 5 };
// the JSON string sent to the grid will look like this (notice B is omitted)
// "{ A: 'a', C: 5 }"
Now, the grid will show this as:
A B C
a undefined 5
And this brings me to my problem. The pop-up edit form will show "undefined" in the textbox for B, and will also post this to the server. So if I save that to the database, I'll have "undefined" in my DB instead of null.
How do I get jqGrid to preserve the null value round trip? One solution that seems to me very hacky is based on something Oleg solved in another thread:
// override jqGrid serialization
jQuery.extend(jQuery.jgrid.edit, { ajaxEditOptions: { contentType: "application/json" }, serializeEditData: function (data) {
return JSON.stringify(data).replace(/"undefined"/g, 'null');
}});
This will work, but seems dangerous because it's doing mass edits of data without the user's knowledge. In thinking more about it, I guess this is the fundamental problem of saving back null instead of "undefined" or some other string representation of null (empty string, etc.). The desired behavior would be:
if the property is null, and the user doesn't change the value, it posts as null
if the user changes the value, the property is no longer null
Can we get the grid's edit form to behave like this for nullable properties? Or would I have to create a custom edit form that tracks what the user does with a property?
I hope that I understand your problem. In one my applications where I used jqGrid I had once the problem with NULL values. At the time of development of the application I was not sure how to solve the problem and I placed on the server side the text value "(NULL)" instead of null value of one property. The grid was for advanced users who understand what "(NULL)" is. The value "(NULL)" has no sense in the field (one had no user account with the name) and inside of server code for the Edit operation I could distinguish "(NULL)" value from the real field value. In the way I could come over the problem.
In your case you should solve at least two problems:
You should decide how the null value should be displayed. The "undefined" text seems me not the best one. You can solve the problem with the "undefined" text either on the server side (like I did in my case) or with respect of custom formatter. The custom formatter is very simple thing. It define how a cell value should be displayed as a HTML fragment of the <td> contain. You can for example include an additional hidden <span> element or other HTML element or attribute which will save the information that the value was null.
You should solve the problem with decoding of the null value on the server side during Edit operations. You can solve the problem very easy on the server side (like I do with compare of the corresponding field to the "(NULL)") or with respect of custom unformatter on the client side. The custom unformatter will get the information from the grid cell (from the hidden <span> or other hidden HTML element or attribute) and place the information in the server request.
You can look at the demo for the answer to see an example how one can use a hidden <span> to save an additional information in the cell with respect of custom formatter and to read the information later with respect of custom unformatter.

Resources