Skip to Content
Technical Articles

UI5 View templating using json model

In this blog I will discuss about the concept of sapui5 view templating using json model with factory function for aggregation binding.

To start with, Let me first talk about some concepts in ui5 for view templating scenarios. the view templating we can think of a requirement of reusing a part/full of a view throughout our application, it may be metadata driven xml templating or it may be a use case of creating dynamic view and its elements as per user’s design need (something like a layout editor). to summarise the concepts we can leverage are.

  • nested views
  • fragments
  • XML templating with oData metadata model
  • through json model and aggregation binding factory function for dynamic need like layout editor ( this we will talk about more in this blog)

Ui5 view templating using json model and factory function:

Pre-requisites

  • understanding of json model sap.ui.model.json.JSONModel
  • ui5 Aggregation binding
  • usage of factory function in aggregation binding

Concept debriefing

  1. I will be creating a view with only an layout defined for it ( I have used grid layout , you can use as per your choice)
  2. I will create a json object structure where I will define the view control hierarchy (with some of their properties, for examples I have kept the list short to few identified controls, we can extend to any number of supported controls) that I want in my resulting view.
  3. I will be using layout data properties in the view content json which will impart the layout’s span indent and line breaks for different screen sizes.
  4. I will do aggregation binding and create factory function in the view’s controller.
  5. Ui5 framework will trigger this factory function call at the time the json data is set in to the view model.
  6. The framework will all the factory function while binding the view recursively as per the control hierarchy defined in the json model.
  7. Finally with all the binding context gets evaluated by the factory and we get the view rendered.

Content json object sample:

{
	"content": [{
		"type": "Panel", 
		"headerText": "Panel100",
		"content": [{
			"type": "Table",
			"headerText": "Table100",
			"columns": [{
				"type": "Column",
				"column": "A",
				"cellType": ""
			}, {
				"type": "Column",
				"column": "B",
				"cellType": ""
			}],
			"rows": [{
				"type": "ColumnListItem",
				"A": 1000,
				"B": 2000
			}, {
				"type": "ColumnListItem",
				"A": 1000,
				"B": 2000
			}],
			"layoutData": {
				"indent": "L0 M0 S0",
				"linebreak": false,
				"span": "L2 M4 S6"
			}
		}],
		"layoutData": {
			"indent": "L0 M0 S0",
			"linebreak": false,
			"span": "L12 M12 S12"
		}

	}, {
		"type": "TextArea",
		"cols": 20,
		"maxLength": 250,
		"rows": 3,
		"value": "abcd",
		"width": "100%",
		"layoutData": {
			"indent": "L0 M0 S0",
			"linebreak": false,
			"span": "L6 M6 S6"
		}

	}, {
		"type": "TextArea",
		"cols": 20,
		"maxLength": 250,
		"rows": 3,
		"value": "abcd",
		"width": "100%",
		"layoutData": {
			"indent": "L0 M0 S0",
			"linebreak": false,
			"span": "L6 M6 S6"
		}

	}]

}

I have created this json sample object tried to keep the controls properties as is so that it’s self explanatory on how i am planning to use them. the type is the control type I am planing to use them in may factory function switch case. The hierarchy is content [] for all the elements and their child element.

Now how my view will look.

view.xml

<App>
    <pages>
      <Page id="page">
	<content>
		<layout:Grid id="grid1" defaultSpan="XL12 L12 M12 S12" defaultIndent="XL0 L0 M0 S0" content="path:'viewContent>/content',templateShareable:'false', factory: '.createDynamicContent'}" class="sapUiNoContentPadding">
		<layout:content></layout:content>						
		</layout:Grid>
	</content>
       </Page>
    </pages>
</App>

I am doing aggregation bingin in my layout which is the only content I have defined in my view page. The factory function createDynamicContent is defined in my controller which will handle the json binding and trigger the content creation for the layout.

this is how my controller factory function looks like

Controller.js

onInit: function () {
			oController = this;
			oController.getView().setModel(new JSONModel("./model/Contents.json"), "viewContent"); // this is the same json object defined above
		},
createDynamicContent: function (sId, oContext) {
			var contextObject = oContext.getObject();
			var type = contextObject.type
			var gridData = contextObject.layoutData;
			switch (type) {
			case "Panel":
				return new Panel({

					expandable: true,
					expanded: false,
					width: "auto",
					headerText: {
						path: 'viewContent>headerText'
					},
					content: {
						path: 'viewContent>content',
						templateShareable: false,
						factory: oController.createDynamicContent
					},

					layoutData: new GridData(gridData)
				});
				break;
			case "TextArea":
				return new TextArea({
					cols: {
						path: 'viewContent>Cols'
					},
					maxLength: {
						path: 'viewContent>maxLength'
					},
					rows: {
						path: 'viewContent>rows'
					},
					value: {
						path: 'viewContent>value'
					},
					width: {
						path: 'viewContent>width'
					},
					layoutData: new GridData(gridData)
				});
				break;
			case "Table":
				return new Table({
					headerText: {
						path: 'viewContent>headerText'
					},
					columns: {
						path: 'viewContent>columns',
						templateShareable: false,

						factory: oController.createDynamicContent
					},
					items: {
						path: 'viewContent>rows',
						factory: oController.createDynamicContent,
						templateShareable: false
					},
					layoutData: new GridData(gridData)
				});			
				break;
			case "Column":

				return new Column({
					header: new Label({
						text: {
							path: 'viewContent>column'
						}
					})
				})
				break;
			case "ColumnListItem":
				{
					var cells = [];
                                        contextObject['columns'].forEach(function (oCell) {
						if (oCell["column"]) {
							cells.push(oContext.getObject().ctrlKey_inedit ?
								new Input({
									value: {
										path: 'viewContent>' + oCell["column"]
									}

								}) : new Text({
									text: {
										path: 'viewContent>' + oCell["column"]
									},
								}));
						} else {
							cells.push(new sap.ui.core.InvisibleText({}));
						}

					});

					return new ColumnListItem({
						cells: cells

					});
					break;
				}

			default:
				return new Text({
					text: "no contoll defined in factory for this type"+type
				});
			}
		}

putting them together in action this is the view I got rendered dynamically for me.

dynamic%20view

dynamic view

Take away is , the json is impacting the view the way we wanted, for user requirement of giving master user the flexibility to design their own template is something we can achieve through this concept; just we need to identify the number of controls that the layout editor is going to support and we will capture all the data required for this json above through user action to create this json dynamically and then use that hson in the views they want.

these might be a need of the hour in our consulting life while client looks for scalable solution and don’t  want to depend on a developer to extend their application template for future need, rather how they can design on their own ( without heaving knowledge of ui5 technology ).

 

/
dynamic%20view
Be the first to leave a comment
You must be Logged on to comment or reply to a post.