Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default values in dependency are ignored #768

Closed
1 task done
OmasBraten opened this issue Nov 16, 2017 · 4 comments · Fixed by #1304
Closed
1 task done

Default values in dependency are ignored #768

OmasBraten opened this issue Nov 16, 2017 · 4 comments · Fixed by #1304
Labels

Comments

@OmasBraten
Copy link

OmasBraten commented Nov 16, 2017

Prerequisites

Description

When using dependencies, the default values in the dependency object are ignored.

Steps to Reproduce

{
    "title": "Person",
    "type": "object",
    "properties": {
        "Do you have any pets?": {
            "type": "string",
            "enum": [
                "No",
                "Yes: One",
                "Yes: More than one"
            ],
            "default": "No"
        }
    },
    "required": [
        "Do you have any pets?"
    ],
    "dependencies": {
        "Do you have any pets?": {
            "oneOf": [
                {
                    "properties": {
                        "Do you have any pets?": {
                            "enum": [
                                "No"
                            ]
                        },
                        "title" : {
                            "type": "string",
                            "title": "Title",
                            "default": "A new task"
                        }
                    }
                },
                {
                    "properties": {
                        "Do you have any pets?": {
                            "enum": [
                                "Yes: One"
                            ]
                        },
                        "How old is your pet?": {
                            "type": "number"
                        }
                    },
                    "required": [
                        "How old is your pet?"
                    ]
                },
                {
                    "properties": {
                        "Do you have any pets?": {
                            "enum": [
                                "Yes: More than one"
                            ]
                        },
                        "Do you want to get rid of any?": {
                            "type": "boolean"
                        }
                    },
                    "required": [
                        "Do you want to get rid of any?"
                    ]
                }
            ]
        }
    }
}

In this case I used the given Person Example and added a Title field with a default value.
But this default value is ignored.

I figured out that the computeDefaults function is never called for the elements in the dependency object.

Version

1.0.0

@elenaHristova
Copy link

Hi, @OmasBraten! I ran across the same issue. Do you have an update on this? I will look at what I can do to achieve the desired result.

@OmasBraten
Copy link
Author

Hi @elenaHristova, since i wrote the issue i don't done any research to find a fix for this bug. I guess that it should be enough to call the computeDefaults method right after the depencies are resolved. But last week i did not found the part where the dependencies are resolved.
So let me know if you achieve some progress.

@n7best
Copy link

n7best commented Nov 24, 2017

Just came to this issue, it looks like the computeDefaults did not account for the dependencies.

I did some debug and made a quick fix on the complied utils.js to fix the issues.

you have first passed the formData to the computeDefault function inside getDefaultFormState

function getDefaultFormState(_schema, formData) {
  var definitions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

  if (!isObject(_schema)) {
    throw new Error("Invalid schema: " + _schema);
  }
  var schema = retrieveSchema(_schema, definitions, formData);
  var defaults = computeDefaults(schema, _schema.default, definitions, formData);
  if (typeof formData === "undefined") {
    // No form data? Use schema defaults.
    return defaults;
  }
  if (isObject(formData)) {
    // Override schema defaults with form data.
    return mergeObjects(defaults, formData);
  }
  return formData || defaults;
}

and then check if it's a dependency and resolve the default

function computeDefaults(schema, parentDefaults) {
  var definitions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  var formData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};

  // Compute the defaults recursively: give highest priority to deepest nodes.
  var defaults = parentDefaults;
  if (isObject(defaults) && isObject(schema.default)) {
    // For object defaults, only override parent defaults that are defined in
    // schema.default.
    defaults = mergeObjects(defaults, schema.default);
  } else if ("default" in schema) {
    // Use schema defaults for this node.
    defaults = schema.default;
  } else if ("$ref" in schema) {
    // Use referenced schema defaults for this node.
    var refSchema = findSchemaDefinition(schema.$ref, definitions);
    return computeDefaults(refSchema, defaults, definitions, formData);
  } if (schema.hasOwnProperty("dependencies")) {
    const resolvedSchema = resolveDependencies(schema, definitions, formData);
    return computeDefaults(resolvedSchema, defaults, definitions, formData);
  } else if (isFixedItems(schema)) {
    defaults = schema.items.map(function (itemSchema) {
      return computeDefaults(itemSchema, undefined, definitions, formData);
    });
  }
  // Not defaults defined for this node, fallback to generic typed ones.
  if (typeof defaults === "undefined") {
    defaults = schema.default;
  }

  switch (schema.type) {
    // We need to recur for object schema inner default values.
    case "object":
      return Object.keys(schema.properties || {}).reduce(function (acc, key) {
        // Compute the defaults for this node, with the parent defaults we might
        // have from a previous run: defaults[key].
        acc[key] = computeDefaults(schema.properties[key], (defaults || {})[key], definitions, formData[key]);
        return acc;
      }, {});

    case "array":
      if (schema.minItems) {
        if (!isMultiSelect(schema, definitions)) {
          var defaultsLength = defaults ? defaults.length : 0;
          if (schema.minItems > defaultsLength) {
            var defaultEntries = defaults || [];
            // populate the array with the defaults
            var fillerEntries = new Array(schema.minItems - defaultsLength).fill(computeDefaults(schema.items, schema.items.defaults, definitions, formData));
            // then fill up the rest with either the item default or empty, up to minItems

            return defaultEntries.concat(fillerEntries);
          }
        } else {
          return [];
        }
      }
  }
  return defaults;
}

@MatinF
Copy link

MatinF commented Feb 8, 2019

Would be great to get this resolved. Currently, if we do use default values in this scenario, the editor looks like it's correctly selected these - but since they don't render in the formData, it can lead to some rather serious errors if users/developers are not aware of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants