json-schema-form / angular-schema-form

Generate forms from a JSON schema, with AngularJS!
https://json-schema-form.github.io/angular-schema-form
MIT License
2.47k stars 653 forks source link

How can I reference the index of the current array item in a condition #35

Closed torstenrudolf closed 10 years ago

torstenrudolf commented 10 years ago

Consider a slightly modified "Array" example from the demo page. The only change is an additional boolean field on the array called show.

I want to show a certain section of the array only if comments[?].show evaluates true.

How can I reference the current item of the array in the condition of the section? comments[$index].show or comments[arrayIndex].show did not work for me.

Form:

[
  {
    "type": "help",
    "helpvalue": "<h4>Array Example</h4><p>Try adding a couple of forms, reorder by drag'n'drop.</p>"
  },
  {
    "key": "comments",
    "items": [
      "comments[].show",
      { "type": "section",
        "condition": "model.comments[???].show",
        "items": [
           "comments[].name",
           "comments[].email"
         ]
      },
      {
        "key": "comments[].comment",
        "type": "textarea"
      }
    ]
  },
  {
    "type": "submit",
    "title": "OK"
  }
]

Schema:

{
  "type": "object",
  "title": "Comment",
  "properties": {
    "comments": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "title": "Name",
            "type": "string"
          },
          "show": {
            "title": "Show",
            "type": "boolean",
            "default": false
          },
          "email": {
            "title": "Email",
            "type": "string",
            "pattern": "^\\S+@\\S+$",
            "description": "Email will be used for evil."
          },
          "comment": {
            "title": "Comment",
            "type": "string",
            "maxLength": 20,
            "validationMessage": "Don't be greedy!"
          }
        },
        "required": [
          "name",
          "email",
          "comment"
        ]
      }
    }
  }
}
davidlgj commented 10 years ago

Hi,

as it is right now you can't. But I see that it would be very useful, checkout the code in section.html, form.condition is evaluated bu using evalExpr which evaluates in the parent scope of the directive sf-schema, this is since sf-schema has a isolated scope it wouldn't be useful do to it in local scope.

I haven't time to try it just now, but the second argument to evalExpr is locals, so adding $index there might work, i.e evalExpr(form.condition,{ model: model, '$index': $index })

torstenrudolf commented 10 years ago

I could not reference the $index there, it doesn't seem to exist in this scope.

But I show you what worked for me, but that is just a quick hack for now (needs probably some work in the decorator?).

I added a field called conditionIndex to the form definition: (number of $parent is dependent on the level of the nesting)

...
      { "type": "section",
        "condition": "model.comments[$index].show",
       "conditionIndex": "$parent.$parent.form.arrayIndex",
        "items": [
           "comments[].name",
           "comments[].email"
         ]
      },
...

And in the section.html I added this to the locals of the expression:

<div ng-if="!form.condition || evalExpr(form.condition,{ model: model, '$index': evalInScope(form.conditionIndex) })">
  <sf-decorator ng-repeat="item in form.items" form="item"></sf-decorator>
</div>
davidlgj commented 10 years ago

Great that you got a workaround. I'll keep the issue open until a fix is released.