Musson Industrial's Embr-Periscope Module

Json View Component

The latest release of Periscope (0.5.4) now includes a Json View component.

This component allows you to render a view by providing view.json content into the component's properties.

Example View JSON
{
  "custom": {
    "text": "Neat!",
    "type": "ia.input.text-field"
  },
  "params": {},
  "propConfig": {
    "custom.text": {
      "binding": {
        "config": {
          "bidirectional": true,
          "path": "/root/Text/TextField.props.text"
        },
        "type": "property"
      },
      "persistent": true
    },
    "custom.type": {
      "binding": {
        "config": {
          "bidirectional": true,
          "path": "/root/Type/TextField.props.text"
        },
        "type": "property"
      },
      "persistent": true
    }
  },
  "props": {
    "defaultSize": {
      "width": 325
    }
  },
  "root": {
    "children": [
      {
        "meta": {
          "name": "JsonView"
        },
        "position": {
          "basis": "300px"
        },
        "propConfig": {
          "props.viewJson.root.children[1].type": {
            "binding": {
              "config": {
                "path": "view.custom.type"
              },
              "type": "property"
            },
            "persistent": true
          },
          "props.viewParams.text": {
            "binding": {
              "config": {
                "bidirectional": true,
                "path": "view.custom.text"
              },
              "type": "property"
            }
          }
        },
        "props": {
          "viewJson": {
            "custom": {},
            "params": {
              "text": "Text"
            },
            "propConfig": {
              "params.text": {
                "paramDirection": "inout",
                "persistent": true
              }
            },
            "props": {},
            "root": {
              "children": [
                {
                  "meta": {
                    "name": "Label"
                  },
                  "position": {
                    "basis": "auto"
                  },
                  "propConfig": {
                    "props.text": {
                      "binding": {
                        "config": {
                          "path": "view.params.text"
                        },
                        "type": "property"
                      }
                    }
                  },
                  "type": "ia.display.label"
                },
                {
                  "meta": {
                    "name": "TextField"
                  },
                  "position": {
                    "basis": "auto"
                  },
                  "propConfig": {
                    "props.text": {
                      "binding": {
                        "config": {
                          "bidirectional": true,
                          "path": "view.params.text"
                        },
                        "type": "property"
                      }
                    }
                  },
                  "props": {
                    "style": {
                      "minHeight": "50px"
                    }
                  },
                  "type": "ia.input.text-field"
                }
              ],
              "meta": {
                "name": "root"
              },
              "props": {
                "direction": "column",
                "style": {
                  "gap": "1rem"
                }
              },
              "type": "ia.container.flex"
            }
          }
        },
        "type": "embr.periscope.embedding.json-view"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": "50px"
            },
            "props": {
              "text": "Text"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "TextField"
            },
            "position": {
              "grow": 1
            },
            "props": {
              "text": "Neat!"
            },
            "type": "ia.input.text-field"
          }
        ],
        "meta": {
          "name": "Text"
        },
        "position": {
          "basis": "32px"
        },
        "type": "ia.container.flex"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": "50px"
            },
            "props": {
              "text": "Type"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "TextField"
            },
            "position": {
              "grow": 1
            },
            "props": {
              "text": "ia.input.text-field"
            },
            "type": "ia.input.text-field"
          }
        ],
        "meta": {
          "name": "Type"
        },
        "position": {
          "basis": "32px"
        },
        "type": "ia.container.flex"
      }
    ],
    "meta": {
      "name": "root"
    },
    "props": {
      "direction": "column"
    },
    "type": "ia.container.flex"
  }
}

But Why?

This started as an exercise in trying to understand the full process of view loading. Then, I realized this component was possible and that I already had solved the hardest parts during the development of the Embedded View + component.

What Does This Enable?

This component allows you to programmatically generate views from within Ignition. You've always been able to modify the view.json files from an external editor, but you don't get any visual feedback until you import them; this component re-renders as the viewJson property changes. The idea is:

  1. Generate the viewJson structure however you want (scripting, bindings, database queries, manually, etc.).
  2. Copy the viewJson property and paste it to a view using the Paste JSON option.
  3. Enjoy your new view.

The component does work in the client, you could generate the viewJson at runtime to have completely dynamic view structure. I don't think this is a good idea, but I can't stop you, so do whatever you want :man_shrugging:.

If you do decide you want to use dynamic views in the client, you can provide parameters using the viewParams property. Passing parameters works like any other view (input, output, in-out, etc.).

Known Issues

  1. The property tree does not allow you to use periods in object keys. This causes an issue when defining a component's propConfig properties. (I'd like to recommend that IA drop this limitation, as well as the limitation against string numbers as keys. JSON keys are strings, and strings containing periods and numbers are strings).

Download

5 Likes