Building Dynamic Views with Metadata === The metadata framework is a RhoConnect & Rhodes tool which provides synchronized application layouts. For example, if your application had an "account" model with the fields "name" and "address", metadata would allow you to add an additional field "phone" in the source adapter and this new field would automatically display in the Rhodes application. In addition to adding/removing/updating fields, metadata also provides powerful features like handling field validations, data-binding, collections, repeatable elements, and much more. ## How Metadata Works * Metadata is first defined in a [source adapter](/rhoconnect/source-adapters) by implementing an adapter method `metadata` that returns a JSON structure. The JSON structure may contain a hash of hashes, as well as having child elements defined as arrays of hashes. The keys in each object can be any string, however there are some reserved labels and labels used by certain elements. * The metadata for an adapter is synchronized to Rhodes along with the rest of the adapter dataset. Metadata is called before the query method in the [`SyncEngine` workflow](/rhodes/synchronization#syncengine-workflow), so you can tailor your query method based on metadata. * Rhodes uses the synchronized [metadata definition](#metadata-definition) to render views at runtime. These views are driven by the metadata definition, so when a new definition is synchronized, the views will automatically reflect the changes. ## Getting Started with Metadata The first step is to install the rhodes-translator gem: :::term $ gem install rhodes-translator Then add `rhodes_translator` to your extensions in your Rhodes application's `build.yml`: :::yaml extensions: ["rhodes_translator"] Now define some metadata and add this to a `metadata` method your [source adapter model](/rhoconnect/source-adapters). For example: :::ruby def metadata # define the metadata row1 = { :label => 'Address 1', :value => '123 fake street', :name => 'address1', :type => 'labeledrow' } table = { :label => 'Table', :type => 'table', :children => [ row1, row1, row1 ] } view = { :title => 'UI meta panel', :type => 'iuipanel', :children => [table] } # return the definition as JSON {'index' => view}.to_json end ## Metadata Definition The following elements are available for building metadata definitions. ### Reserved Labels The following labels are reserved, used by the metadata framework. * `:type` * `:children` * `:repeatable` * `:validation` ### Children Children of an element are defined by an array of hashes. To specify the children of an element you add the ":children" key and specify the children of that element. The following example shows a table element that has three `row1` elements as `:children`: :::ruby row1 = { :label => 'Address 1', :value => '123 fake street', :name => 'address1', :type => 'labeledrow' } table = { :label => 'Table', :type => 'table', :children => [ row1, row1, row1 ] } ### Repeatable Repeatable elements use [data binding](#data-binding) to specify an array of objects to iterate over. The children of the repeatable element are duplicated for each element in the object referred to by the repeatable hash key. For more information on data-binding see the data binding section on this page. The following example will result in a table with 2 child rows, one row with the value set to '123 fake street' and the second row value set to '321 fake street' :::ruby @addresses = [ { :name => "123 fake street" }, { :name => "321 fake street" } ] row1 = { :label => 'Address 1', :value => '{{name}}', :name => 'address1', :type => 'labeledrow' } table = { :label => 'Table', :type => 'table', :children => [ row1 ], :repeatable => '{{@addresses}}' } ## Controlling How Metadata is Rendered By default, any controller actions that have metadata for a given model with the key corresponding to the action will be rendered with metadata instead of the view. However, you can render arbitrary metadata in the view with the `render_metadata` method. You must specify the action to the metadata. By default, the metadata provided is pulled from the model, however this can be overridden as well. Example: :::ruby <%= render_metadata('indexdata') %> Or, using explicit metadata resource: :::ruby <%= render_metadata('index', Account.metadata) %> ## Data Binding Data binding happens before the elements get translated to html. All of the instance variables in your method are able to be referenced by the data binding keys. A data binding key is always contained within a string. It is indicated by using double bracket enclosure: `{{databinding path here}}` To reference hash keys, or index arrays, the `/` operator is used. You must specify the whole path to the object, the only exception being within [repeatable](#metadata-definition) elements. We will use the following dataset for example: :::ruby @data = { :key1 => [ 'array', 'with', 'elements'], :key2 => { :this => "is", :a => "hash" } } Example data binding keys using this data: `{{@data/key1/0}}` will be replaced with 'array' `{{@data/key1/2}}` will be replaced with 'elements' `{{@data/key1/5}}` will be replaced with an error message `{{@data/key2/this}}` will be replaced with 'is' `{{@data/key2/this}}` will be replaced with 'hash' Within a repeatable element, the root node is replaced with the element that is being repeated. See the example in the repeatable section above. To reference the root element while inside a repeatable a `/` should be prepended to your data binding expression: `{{/@data/key1/0}}` ## Validation Validation is expressed as a key added to an existing metadata definition. Below is a sample showing all of the validations that can be used. :::ruby :validation => { :regexp = "^.+$", :validators = [:required, :number, :currency, :email, :phone], :min_len = 0, :max_len = 100, :min_value = 10, :max_value = 1000 } ## Templates ### Form An HTML form that is used for submitting data: :::html
* **Type** * `form` * **Keys** * `name` - used as name attribute in <form> tag * `action` - used as action attribute in <form> tag * `method` - used as method attribute in <form> tag * **Children** * Children are rendered between the <form> and </form> tags ### Panel Contains children with a <div> tag with the div class set to 'panel': :::html * **Type** * `panel` * **Keys** * `unused` * **Children** * Children are rendered between the <div> and </div> tags ### View Contains children with no extra html. * **Type** * `view` * **Keys** * `unused` * **Children** * Children rendered directly ### Table HTML Table. :::html