ngx-Formly - Display first array input by default without initializing empty model - angular9

I am using ngx-formly's JSON Schema approach to build out custom forms (Angular 9 + ng-bootstrap + bootstrap 4). Our app has a lot of array inputs - some are nested even. I have used the custom array type code from https://formly.dev/examples/advanced/json-schema to implement the array display.
The rendering of the form based on the schema for array inputs - is correct in the sense that the hierarchy of nesting is as required. However in case of array inputs - the form fields do not appear until someone clicks on the add (plus) button to show the first set of inputs. From a UI standpoint, we need atleast one set of fields displayed even if the user does not enter any value for the array (these are not mandatory inputs).
So far from the documentation there seem to be two approaches
initializing a model object with an empty or null first item for the array seems to be the way to make the fields appear. But we would need to put in empty/dirty/untouched checks to not commit these fields to the backend.
we change the template in the array type definition file to show one empty set of fields by default. Have not tried this approach, not sure how the binding of array fields would work if displaying one set of fields is forced.
Is there another way we can achieve this - by using some option fields?

I seem to have found a solution :)
Need to put "defaultValue": [ "undefined" ].
Full code below.
{
"fieldGroup": [
{
"key": "driver_section",
"type": "repeatDrivers",
"defaultValue": [ "undefined" ],
"fieldArray": {
"fieldGroup": [
{
"key": "last_name",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"label": "Фамилия",
"required": true
}
},
{
"key": "first_name",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"label": "Имя",
"required": true
}
},
{
"key": "paternal_name",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"label": "Отчество",
"required": true
}
},
{
"key": "date_of_birth",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"type": "date",
"label": "Дата рождения",
"required": true
}
},
{
"key": "series_and_number_of_VU",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"type": "number",
"label": "Серия и номер ВУ",
"required": true
}
},
{
"key": "date_of_issue_of_the_current_VU",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"type": "date",
"label": "Дата выдачи действующего ВУ",
"required": true
}
},
{
"key": "year_of_issue_of_the_first_VU",
"type": "input",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"type": "number",
"label": "Год выдачи первого ВУ",
"required": true
}
},
{
"key": "driver_license_changed",
"type": "checkbox",
"className": "flex-2",
"defaultValue": "",
"templateOptions": {
"label": "Водительское удостверение менялось в течение года",
"required": false
}
}
],
"fieldGroupClassName": "display-flex"
},
"templateOptions": {
"title": "Drivers",
}
}
],
"fieldGroupClassName": "display-flex"
}

It seems nicer to write like
"defaultValue": [ {} ]
, and it also works great

Related

Why can't the schema see the required array?

I have created a JSON Schema, but when I try to use it to validate another object, the schema fails due to an error, citing:
Message:
Required properties are missing from object: Envelope.
Schema path:
#/required
However, I can clearly see the required array listed inside of the envelope as a sibling to its properties. In every schema I've seen online, this is how is is displayed. I have included a trimmed-down selection of the schema below that still sees the same error. Can anyone tell me why this is failing?
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Envelope": {
"type": "object",
"properties": {
"TP_UNIQUE_NUM": {
"length": 50,
"type": "string"
},
"SENDER_ID": {
"length": 50,
"type": "string"
},
"TRANSMISSION_FORMAT": {
"length": 50,
"type": "string"
},
"RECEIVER_ID": {
"length": 50,
"type": "string"
},
"HEADER": {
"type": "object",
"properties": {
"door": {
"description": "Door at which product associated with ASN is scheduled to be unloaded",
"type": "string",
"mandatory": "Y",
"maxLength": 10
},
"notes": {
"description": "Comments associated with ASN",
"type": "string",
"mandatory": "Y",
"maxLength": 4000
},
"wareHouseReference": {
"description": "Additional notes or reference information for the warehouse",
"type": "string",
"mandatory": "Y",
"maxLength": 100
}
},
"required": [
"wareHouseReference"
]
},
"TP_TRANSMISSION_TYPE": {
"maxLength": 50,
"type": "string"
},
"FILE_NAME": {
"maxLength": 50,
"type": "string"
},
"TRANSMISSION_DATE_TIME": {
"maxLength": 50,
"type": "string"
},
"TRANSACTION_COUNT": {
"maxLength": 50,
"type": "string"
}
}
}
},
"required": [
"Envelope"
]
}
It seems that you are missing a required array within the Envelope object.
You have a required array at the root level object, you also have one within the HEADER object, but not within the Envelope object.
I'm assuming a required array is required for each object type.
EDIT: My assumption is probably wrong, I was able to run your schema at json-schema-validator without an issue using this sample JSON. #Jason Desrosiers comment seems to be right on the money.
{
"Envelope": {
"TP_UNIQUE_NUM": "hello",
"SENDER_ID": "hello",
"TRANSMISSION_FORMAT": "hello",
"RECEIVER_ID": "hello",
"HEADER": {
"door": "hello",
"notes": "hello",
"wareHouseReference": "hello"
},
"TP_TRANSMISSION_TYPE": "hello",
"FILE_NAME": "hello",
"TRANSMISSION_DATE_TIME": "hello",
"TRANSACTION_COUNT": "hello"
}
}

How to combine a property type, to match another properties type

I have the following use case with a JSON schema. I have a metadata object of a setting. In our case a setting can be of type string/real/integer/boolean.
In this object I have 4 fields: default/minimum/maximum each define a property of the setting.
Now what I want to achieve is that when the type of de default value is an integer, also the minimum/maximum values are integers.
The schema I have come up with so far:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"setting-value": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"setting-meta": {
"type": "object",
"required": [
"name",
"type",
"default"
],
"properties": {
"name": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"Real",
"Integer",
"Boolean",
"String"
]
},
"minimum": {
"$ref": "#/definitions/setting-value"
},
"maximum": {
"$ref": "#/definitions/setting-value"
},
"default": {
"$ref": "#/definitions/setting-value"
},
"value": {
"$ref": "#/definitions/setting-value"
}
}
}
}
}
Here it is possible for the #/definitions/setting-meta to have support for the different types. However it does not define that if for example the value of TYPE is equal to Real/Integer that the types of minimum/maximum/default/value should all be of type number.
I would use these definitions as follows
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "schema-definition-above.json#/definitions/setting-meta"
}
According the the current schema, all examples below are VALID, however they should be valid/invalid as suggested:
Valid JSon object:
{
"name": "Enabled",
"type": "Boolean",
"minimum": false,
"maximum": true,
"default": true,
"value": true
}
Invalid json object, minimum/maximum/default don't have the same type:
{
"name": "Enabled",
"type": "Boolean",
"minimum": false,
"maximum": 1,
"default": "value",
"value": true
}
Invalid json object: type, does not match the actual type of the values
{
"name": "Enabled",
"unit": "enabled/disabled",
"configId": "Accumulator",
"displayName": "Enable or disable this machine",
"type": "Integer",
"minimum": false,
"maximum": true,
"default": true,
"value": true
}
My question:
Is it possible to put these kinds of dependencies into a JSON schema? The only kind of dependency I have foudn so far is with property dependencies indicating that if one property is set, another should also be set.
Any help would be much appreciated.
EDIT:
Extended that use case with some JSON objects that should be validated or invalidated with the referenced schema.
In order to do conditional validation where you have a known set of possible conditions, you should use the if/then/else keywords, in combination with with allOf.
In this schema, the first schema in allOf defines your general structure and overall requirements. The second schema applies the then constraint if the if schema validates successfully.
You would need to replicate the second schema for each condition that you have.
You can see this schema working at https://jsonschema.dev (link is preloaded with the below schema and sample data)
(The use of patternProperties is just a space saver. You could define each property individually.)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"allOf": [
{
"properties": {
"type": {
"enum": [
"Real",
"Integer",
"Boolean",
"String"
]
}
},
"required": [
"type",
"default",
"name"
]
},
{
"if": {
"properties": {
"type": {
"const": "String"
}
}
},
"then": {
"patternProperties": {
"^(minimum|maximum|default|value)$": {
"type": [
"string"
]
}
}
}
}
]
}

Can't understand this JSON schema from the Swish QR Code API

I'm trying to use an API but the documentation is really bad. I got this JSON schema but I don't understand it. What am I supposed to include in the request?
url: https://mpc.getswish.net/qrg-swish/api/v1/prefilled
I have tried this but it doesn't work:
{
"payee":{
"editable":{
"editable":"false"
},
"swishString":{
"value":"0721876507"
}
},
"size":600,
"border":20,
"transparent":false,
"format":"png"
}
Here's the JSON schema
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Swish pre-filled qr code generator",
"description": "REST interface to get a QR code that the Swish app will interpret as a pre filled code",
"definitions": {
"editable": {
"description ": "Controls if user can modify this value in Swish app or not",
"type": "object",
"properties": {
"editable": {
"type": "boolean",
"default": false
}
}
},
"swishString": {
"type": "object",
"properties": {
"value": {
"type": "string",
"maxLength": 70
}
},
"required": [
"value"
]
},
"swishNumber": {
"type": "object",
"properties": {
"value": {
"type": "number"
}
},
"required": [
"value"
]
}
},
"type": "object",
"properties": {
"format": {
"enum": [
"jpg",
"png",
"svg"
]
},
"payee": {
"description": "Payment receiver",
"allOf": [
{
"$ref": "#/definitions/editable"
},
{
"$ref": "#/definitions/swishString"
}
]
},
"amount": {
"description": "Payment amount",
"allOf": [
{
"$ref": "#/definitions/editable"
},
{
"$ref": "#/definitions/swishNumber"
}
]
},
"message": {
"description": "Message for payment",
"allOf": [
{
"$ref": "#/definitions/editable"
},
{
"$ref": "#/definitions/swishString"
}
]
},
"size": {
"description": "Size of the QR code. The code is a square, so width and height are the same. Not required is the format is svg",
"value": "number",
"minimum": 300
},
"border": {
"description": "Width of the border.",
"type": "number"
},
"transparent": {
"description": "Select background color to be transparent. Do not work with jpg format.",
"type": "boolean"
}
},
"required": [
"format"
],
"anyOf": [
{
"required": [
"payee"
]
},
{
"required": [
"amount"
]
},
{
"required": [
"message"
]
}
],
"additionalProperties": false,
"maxProperties": 5
}
The API should return a QR code.
To be honest, I have not taken the time to learn JSON schema, but your example should probably look something like this:
{
"payee": {
"value": "0721876507",
"editable": false
},
"size": 600,
"border": 20,
"transparent": false,
"format": "png"
}
There are other parameters you may choose to utilize:
{
"payee": {
"value": "1239006032",
"editable": false
},
"message": {
"value": "LIV",
"editable": true
},
"amount": {
"value": 100,
"editable": true
},
"format": "png",
"size": 300,
"border": 0,
"transparent": true
}
Honestly, I think the developers behind the Swish APIs are trying to look smart by complicating things. They should, of course, have provided example JSON data instead of forcing consumers to understand their JSON schema. Also, I believe their published schema is wrong. The second example I provided works even though it doesn't validate according to the JSON schema ("Object property count 7 exceeds maximum count of 5").
Here is a minimal and pretty useless request that returns a valid QR-code
{
"format": "png",
"size": 300
}
And here is a more usable example that works
{
"format": "png",
"size": 300,
"transparent": false,
"amount": {
"value": 999.99,
"editable": true
},
"payee": {
"value": "0701000000",
"editable": false
},
"message": {
"value": "Hello",
"editable": false
}
}

Json schema field order

I know that fields listed in a json schema object have no defined order, since they are not an array, but I am looking for a way to be able to display them in the proper order in my application UI.
Workarounds I have found so far include things like using a different serializer, or even hard-coding a number into the field name.
I would like to come up with something that works with my current setup.
Hibernate, Spring Boot, and a react-app front end.
given this GET request:
/profile/personEntities
with header: Accept: application/schema+json
I will receive this:
{
"title": "Person entity",
"properties": {
"birthday": {
"title": "Birthday",
"readOnly": false,
"type": "string",
"format": "date-time"
},
"lastName": {
"title": "Last name",
"readOnly": false,
"type": "string"
},
"address": {
"title": "Address",
"readOnly": false,
"type": "string",
"format": "uri"
},
"firstName": {
"title": "First name",
"readOnly": false,
"type": "string"
},
"email": {
"title": "Email",
"readOnly": false,
"type": "string"
},
"cellPhone": {
"title": "Cell phone",
"readOnly": false,
"type": "string"
}
},
"requiredProperties": [
"firstName",
"lastName"
],
"definitions": {},
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#"
}
I have tried adding #JsonProperty(index=2) to the field, but nothing changes.
Thank you much for any tips.
If you're using Jackson to handle your serialization/deserialization you can use #JsonPropertyOrder - from their docs:
// ensure that "id" and "name" are output before other properties
#JsonPropertyOrder({ "id", "name" })
// order any properties that don't have explicit setting using alphabetic order
#JsonPropertyOrder(alphabetic=true)
See: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonPropertyOrder.html

js-beautify config for Arrays of Objects

Is there any way to configure js-beautify to keep the following format:
"structure": [
{
"name": "heading",
"text": "",
"default": "",
"type": "string"
},
{
"name": "flickr-album-id",
"text": "",
"type": "string"
},
]
js-beautify pulls in the curly bracket of the first object into the first line. I know of the option keep_array_indentation but i dont want to disable the general auto indentation because errors wont get fixed otherwise.
The result of js-beautify - that i want to prevent - will be
"structure": [{
"name": "heading",
"text": "",
"default": "",
"type": "string"
},
{
"name": "flickr-album-id",
"text": "",
"type": "string"
},
]