empty array in angular-schema-form - angularjs

I'm using angular-schema-form in my project and trying to add an empty array in my model.
I expected that array type schema form will not contain any items but it actually pushed one object in my array and showed it in from.
How can I init form with no items in array?
html
<div ng-app="app" ng-controller="Controller as ctr">
<form sf-schema="ctr.schema" sf-form="ctr.form" sf-model="ctr.model"></form>
{{ctr.model.comments}} - Where this object come from? This array was empty. Is it possible to keep it empty on load?
</div>
js
var myApp = angular.module('app', ['schemaForm'])
.controller("Controller", function() {
this.schema = {
"type": "object",
"title": "Comment",
"properties": {
"comments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"comment": {
"title": "Comment",
"type": "string",
"maxLength": 20,
"validationMessage": "Don't be greedy!"
}
}
}
}
}
};
this.form = [{
"key": "comments",
"items": [
"comments[]"
]
}];
this.model = {
comments: [] // Empty array defined
};
});
Jsfiddle

The value you are looking for is startEmpty: true this will avoid pre-populating the array with an object.
Angular Schema Form: Array Documentation
The pre-population is defaulted to ensure that the form fields within an array are available when the form loads. The startEmpty: true value can override this behaviour.

Related

How to add required to sub array in a json schema?

I'm creating a json schema to define necessary data with data types. There is some data need to be set into required filed. But didn't find how to do it in its document.
For this json schema:
{
"type": "object",
"required": [
"version",
"categories"
],
"properties": {
"version": {
"type": "string",
"minLength": 1,
"maxLength": 1
},
"categories": {
"type": "array",
"items": [
{
"title": {
"type": "string",
"minLength": 1
},
"body": {
"type": "string",
"minLength": 1
}
}
]
}
}
}
json like
{
"version":"1",
"categories":[
{
"title":"First",
"body":"Good"
},
{
"title":"Second",
"body":"Bad"
}
]
}
I want to set title to be required, too. It's in a sub array. How to set it in json schema?
There are a few things wrong with your schema. I'm going to assume you're using JSON Schema draft 2019-09.
First, you want items to be an object, not an array, as you want it to apply to every item in the array.
If "items" is a schema, validation succeeds if all elements in the
array successfully validate against that schema.
If "items" is an array of schemas, validation succeeds if each
element of the instance validates against the schema at the same
position, if any.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-02#section-9.3.1.1
Second, if the value of items should be a schema, you need to treat it like a schema in its own right.
If we take the item from your items array as a schema, it doesn't actually do anything, and you need to nest it in a properties keyword...
{
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"body": {
"type": "string",
"minLength": 1
}
}
}
Finally, now your items keyword value is a schema (subschema), you can add any keywords you can normally use, such as required, the same as you have done previously.
{
"required": [
"title"
],
"properties": {
...
}
}

Logic app- how to retrieve json data from dynamic property name

Here's my json - Here I want to retrieve json content from "Property - Dynamic content". Where, dynamic content part might vary for every json request. How do I filter this by a dynamic name?
{
"Attributes":
{
"Property1": {
"Data1": {
"Value": "50"
}
},
"Property2": {
"Data2": {
"Value": "50"
}
},
"Property - Dynamic content": {
"Data3": {
"Value": "50"
},
"Data4": {
"Value": "50"
}
}
}
}
For your requirement, please refer to my logic app below:
1. I initialized a variable and store the json same with yours to simulate your situation.
2. Then use "Parse JSON".
Please notice the schema of "Parse JSON" show as:
{
"properties": {
"Attributes": {
"properties": {
"Property - Dynamic content": {
"type": [
"object",
"array"
]
},
"Property1": {
"properties": {
"Data1": {
"properties": {
"Value": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
},
"Property2": {
"properties": {
"Data2": {
"properties": {
"Value": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
}
},
"type": "object"
}
},
"type": "object"
}
Please pay attention to the type of Property - Dynamic content in schema above. Since the content of Property - Dynamic content is either "object" or "array", so I set both "object" and "array" as the type of Property - Dynamic content.
3. Then I initialized a variable named "result" to get the value which you want.
As we use both type "object" and "array" in the schema for Property - Dynamic content, so you may not find it in the "Dynamic content" selection. You can input its value by expression as the screenshot above. The whole expression is: body('Parse_JSON')?['Attributes']?['Property - Dynamic content']
I was able to get what I need using inline code - javascript - If anyone else is looking for the same - here it is - This will give json from Property - dynamic content element.
var data = Object.keys(workflowContext.trigger.outputs.body.Attributes);
var key = data.filter(s => s.includes('Property')).toString(); // to get element - Property - dynamic content
return workflowContext.trigger.outputs.body.Attributes[key];

JSON schema for an unnamed array?

I need to create a JSON schema for data that comes as an array directly within the root object, unnamed. An MWE for this kind of JSON would be:
{
[
{
"veggieName": "potato",
"veggieLike": true
},
{
"veggieName": "broccoli",
"veggieLike": false
}
]
}
I have seen examples for schemas which validate such an array which is not nested in an object. I have also seen examples which work when the array is named, for example
{
vegetables : [
{
"veggieName": "potato",
"veggieLike": true
},
{
"veggieName": "broccoli",
"veggieLike": false
}
]
}
This second example can be validated by the schema
{
"$id": "https://example.com/arrays.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "A representation of a person, company, organization, or place",
"type": "object",
"properties": {
"vegetables": {
"type": "array",
"items": { "$ref": "#/definitions/veggie" }
}
},
"definitions": {
"veggie": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
But the problem is, as soon as the name "vegetables" is removed, I was not able to find a way to define a valid schema. How do I properly represent my data structure in a schema?
(MWEs derived from http://json-schema.org/learn/miscellaneous-examples.html).
The schema you are looking for is the following:
{
"$id":"https://example.com/arrays.schema.json",
"$schema":"http://json-schema.org/draft-07/schema#",
"description":"A representation of a person, company, organization, or place",
"type":"array",
"items":{
"type":"object",
"required":[
"veggieName",
"veggieLike"
],
"properties":{
"veggieName":{
"type":"string",
"description":"The name of the vegetable."
},
"veggieLike":{
"type":"boolean",
"description":"Do I like this vegetable?"
}
}
}
}
You also need to modify your base array instance, your original one (the "unnamed" array) was not valid JSON:
[
{
"veggieName":"potato",
"veggieLike":true
},
{
"veggieName":"broccoli",
"veggieLike":false
}
]
Unlike XML, where you are allowed a single root node per document only, in JSON you can have either a type or an array as a root type.

schemaform adding the user input to a schema array

Background
I am making a form using angular-schema-form
Setup
I am trying to make an array of items that a user can make using a form. So, the user can add as many items into the array as they want.
For now the items in the array contain a command type.
Command Type should be a dropdown containing SSH, REST, and whatever the user enters in as the personalized command type.
Code so far
SCHEMA
{
"type": "object",
"properties": {
"personalizedCommandType": {
"title": "Personalized Command Type",
"type": "string"
},
"commands": {
"type": "array",
"title": "Actions",
"items": {
"type": "object",
"properties": {
"commandType": {
"title": "Command Type",
"type": "string",
"enum": [
"REST",
"SSH"
]
}
}
}
}
}
}
FORM
[
{
"type": "help",
"helpvalue": "<h5>Command</h5>"
},
{
"key":"personalizedCommandType"
},
{
"title":"Command",
"key": "commands",
"items": [
"commands[].commandType"
]
}
]
One can test this code here: http://schemaform.io/examples/bootstrap-example.html . Just copy and paste in my code.
Question
As one can see, the code I have now has a field with Personalized Command Type and an array of dropdowns with the 2 options SSH and REST. But I want to drop to also contain the value of the Personalized Command Type once the user has entered it.
NOTE
copyValueTo does not seem to have the functionality that I want given that it can only change values in the model, but I want it to change the enum array in the schema.
Use the onChange option:
[
{
"type": "help",
"helpvalue": "<h5>Command</h5>"
},
{
"key":"personalizedCommandType"
onChange: "updateSchema(modelValue,form)"
},
{
"title":"Command",
"key": "commands",
"items": [
"commands[].commandType"
]
}
]
Update the Schema:
var defaultEnum = ["REST","SSH"];
$scope.updateSchema = function(modelValue,form) {
var currentEnum = $scope.schema.commands.items.properties.commandType.enum;
angular.copy(defaultEnum, currentEnum);
if (modelValue) {
currentEnum.push(modelValue);
};
$scope.$broadcast('schemaFormRedraw');
};

angularjs: extending directive then make modifications

I am working in ServiceNow and am trying to extend an ootb directive, then make some modifications to a couple functions. So far I've figured out how to extend the directive:
function (spModelDirective){
return angular.extend({}, spModelDirective[0], {
templateUrl:'lbl_custom_template.xml'
});
}
Within this directive, there's a function called getNestedFields that I would like to make edits to:
function getNestedFields(fields, containers) {
if (!containers)
return;
for (var _container in containers) {
var container = containers[_container];
if (container.columns) {
for (var _col in container.columns) {
var col = container.columns[_col];
for (var _field in col.fields) {
var field = col.fields[_field];
if (field.type == "container" && container.caption != "")
getNestedFields(fields, [field]);
else if (field.type == "checkbox_container")
getNestedFields(fields, field.containers);
else if (field.type == "field" || container.caption=="")
fields.push(formModel._fields[field.name]);
}
}
}
}
}
Can someone provide some guidance on what the correct syntax for this would be?
More information
Our team cloned the ootb widget-form and am trying to create a custom layout. Basically, we want each form section to be it's own tab much like the back-end form instead of one long form, which is what the ootb widget-form currently does. In the very first line of the sp-variable-layout template, it shows:
<fieldset ng-init="$last ? execItemScripts() : null" ng-show="isContainerVisible(container)" ng-repeat="container in containers">
The ng-repeat of container in containers considers each form section as a separate container (which is perfect), BUT it also considers any splits as a separate container as well. So for example, if my form's layout looks like this:
This will create two tabs: one that has every field within the begin and end splits AND a separate tab with everything after the end split. The JSON object that is created looks like this:
{
"_bootstrap_cells": 6,
"_count": 2,
"visible": true,
"columns": [{
"fields": [{
"name": "type_of_account",
"type": "field"
}, {
"name": "routing_transit_number",
"type": "field"
}]
}, {
"fields": [{
"name": "type_of_payment",
"type": "field"
}, {
"name": "check_digit",
"type": "field"
}]
}],
"caption": "Direct Deposit",
"id": "b456b9d2137ac340177c36328144b0ef",
"scope_name": "x_dnf_table"
}, {
"_bootstrap_cells": 12,
"_count": 1,
"visible": true,
"columns": [{
"fields": [{
"name": "account_number",
"type": "field"
}, {
"name": "account_title",
"type": "field"
}, {
"name": "financial_institution_name",
"type": "field"
}]
}],
"caption": "",
"id": "",
"scope_name": "x_dnf_table"
}
Notice the first "section" has a caption, but ServiceNow treats the split section as its own separate section with no caption at all.
I want to change the spModel directive to produce only containers with captions as their own tab and if a container does NOT have a caption, to append it to the previous container that does have a caption.
I don't think you can edit this function as this is hosted as a file on Servicenow. See https://hi.service-now.com/scripts/app.$sp/directive.spModel.js then just control-f for the getNestedFields.
Per this thread; https://community.servicenow.com/thread/247907#1059129 I believe spModal is just a wrapper for $uibModal.
What you can do is make your own directive on sp_angular_provider.

Resources