SAPUI5 offers several simple controls like TextField, Label... and really complex controls like ThingCollecion, Table, etc. All SAPUI5 controls are listed here:
https://sapui5.netweaver.ondemand.com/sdk/#content/Controls/index.html
It is not necessary create a custom control from scratch if:
sap.ui.commons.Button.extend("MyButton", { //inherit Button definition
metadata: {
events: {
"hover" : {} //new event definition hover
}
},
//hover event handler
onmouseover : function(evt) {
this.fireHover();
},
renderer: {} //Standard renderer method is not overridden
});
When our requirements doesn't fit standard SAPUI5 controls and we have no choice we can create custom controls.
A control defines its appearance and behavior. All SAPUI5 controls extend from sap.ui.core.Control. In the other hand sap.ui.core.Element are parts of Controls but without renderer method. For example a Menu (Control) has different MenuItem (Element) and Menu renders its MenuItems.
Main structure of controls:
I need a control that lets us:
Example Google Gmail recipients field:
sap.ui.core.Control.extend("control.AutoCompleteValueHolder", {
metadata : {
properties: {},
aggregations: {},
events: {}
},
init: function() {
},
renderer : {
render : function(oRm, oControl) {
oRm.write('Hello, this is a new control :)');
}
}
});
sap.ui.localResources('control');
jQuery.sap.require("control.AutoCompleteValueHolder");
var yourNewControl = new control.AutoCompleteValueHolder('yourNewControl');
metadata : {
properties: {
"codePropertyName": {type : "string", defaultValue: "code"}, //Define a model property representing an item code
"descriptionPropertyName": {type : "string", defaultValue: "description"}, //Define a model property representing an item description
"path": {type : "string", defaultValue: "/"}, //Define our model binding path
"model": {type : "any", defaultValue: new sap.ui.model.json.JSONModel()} //Define our model
},
aggregations: {
"_layout" : {type : "sap.ui.layout.HorizontalLayout", multiple : false, visibility: "hidden"} //Grouping of selected items and search text field
},
events : {
"selectedItem": {},
"deletedItem": {},
"deletedAllItems": {}
}
}
This method will be called when an AutoCompleteValueHolder is instantiated
init: function() {
var oControl = this;
//Creation of search autocomplete field
var searchField = new sap.ui.commons.AutoComplete(this.getId() + '-searchField',{
maxPopupItems: 5,
displaySecondaryValues: true,
change: function change(event) {
if (event.mParameters.selectedItem != null) { //If user selects a list item, a new item is added to _layout aggregation
//Every new item consist in a TextField and a Image
var newValueField = new sap.ui.commons.TextField({
width: '100px',
editable: false
});
//TextField shares model with other TextFields and Autocomplete. We select correct path (user selection)
newValueField.setModel(event.getSource().getModel());
newValueField.bindProperty("value", event.getSource().getParent().getParent().mProperties.descriptionPropertyName);
newValueField.bindElement(event.mParameters.selectedItem.oBindingContexts.undefined.sPath);
newValueField.addStyleClass('autoCompleteValueHolder_valueField'); //Custom style
//Image let's us delete an Item. Press event will destroy TextField and Image from _layout aggregation
var newValueImage = new sap.ui.commons.Image({
src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKEw06nF/eLQAAAb9JREFUKM9lkkFIFHEUxn//mf3TrJVOLjvu7phBBB0M3VyNTYg85CU6ZLfqmpAwRVBseqg1CI0OzZ47ePRkh9xQiAgWgqIOXUpNhHbBDGdFSxYX2m3+HZoNpe/yHt/73oP3vgfADHsxI8T/XCOZDuIkGHO9SWcMZKM2CnL+VMqZAGO3lgkw8rFDBe/+qMrbllsFsQhiNhZxy9kxlbetwmTQpANcgesnhy6MSF+iW9H0sw2vWtwf7u8aOHsvrCRmsvNI+e2H9Vl4rwOcgI/11dJBX5I+IJtQLU3nTCs6aDVH+L72lYVXr3NLlZ1Hb8DXp4A74C9Xay+P/9zaEeLXoFnXCdcV3nqR4ufFuw/LP7LP4fcUECrJENTqfAKqvo+/+o2atw2AsJqpKsVysOtmWxsCYAjkmXjkcVqoWx0b28xHTUBw3tuiZJm8U1puac3LPIUaALeP2c6Xnk5VAfXicEm3JXGw1M3MdtqqAWulLqlxvyvlnymUw3PZEYSHVpa4l4i4gADEcj7krfT3qSXu8MBCclXFNA+AqGDeP2je6dxkHyOnT/U437AMYF+Ivm5WhPW8wrGmMBIMaeC wB5M5PywZXUzgAAAABJRU5ErkJggg==',
press: function(event){
var valueLayout = event.getSource().getParent();
var autoCompleteHolderLayout = event.getSource().getParent().getParent().getParent().mAggregations._layout;
autoCompleteHolderLayout.removeContent(valueLayout);
//Fire deletedItem event
oControl.fireDeletedItem({
allItems: oControl.getSelectedValues()
});
},
width: '12px'
});
newValueImage.addStyleClass('autoCompleteValueHolder_valueImage'); //Custom style
//Wrapping container for TextField and Image
var valueLayout = new sap.ui.layout.HorizontalLayout({content: [newValueField, newValueImage]});
valueLayout.addStyleClass('autoCompleteValueHolder_valueLayout');
//Insert wrapping layout into 0 position
event.getSource().getParent().getParent().mAggregations._layout.insertContent(valueLayout, 0);
var content = event.getSource().getParent().getParent().mAggregations._layout.getContent();
//fire selectedItem event
oControl.fireSelectedItem({
newItem: {
code: event.mParameters.selectedItem.mProperties.additionalText,
description: event.mParameters.selectedItem.mProperties.text
},
allItems: oControl.getSelectedValues()
});
//Reset value from autocomplete search field
var search = content[content.length-1];
search.setValue('');
}
}
});
searchField.addStyleClass('autoCompleteValueHolder_search'); //Custom style
//_layout aggregation creation
var layout = new sap.ui.layout.HorizontalLayout(this.getId() + '-valuesLayout',{allowWrapping: true});
layout.addContent(searchField);
layout.addStyleClass('autoCompleteValueHolder_valuesLayout');
//Set _layout aggregation into our control
this.setAggregation("_layout", layout);
}
This method will produce html code:
renderer : {
render : function(oRm, oControl) {
var layout = oControl.getAggregation("_layout");
layout.getContent()[0].setModel(oControl.getModel());
var template = new sap.ui.core.ListItem({
text: "{"+oControl.getDescriptionPropertyName()+"}",
additionalText: "{"+oControl.getCodePropertyName()+"}"
});
layout.getContent()[0].bindItems(oControl.getPath(), template);
oRm.write("<span");
oRm.writeControlData(oControl);
oRm.writeClasses();
oRm.write(">");
oRm.renderControl(layout); //Reuse standard HorizontalLayout render method.
oRm.write("</span>");
}
}
This custom methods lets us get selected items or clear all selected items:
getSelectedValues: function() {
var content = this.getAggregation("_layout").getContent();
var result = [];
if (content != null && content.length > 1) {
//Get all selected item into result
for (var i=0; i<content.length-1; i++) {
var model = content[i].getContent()[0].getModel();
var path = content[i].getContent()[0].getBindingContext().sPath;
result.push(model.getProperty(path));
}
}
return result;
},
clearSelectedValues: function() {
if (this.getAggregation("_layout").getContent() != null && this.getAggregation("_layout").getContent().length > 1) {
//Delete all selected items (SubLayouts containing TextField+Image) from _layout aggregation
while (this.getAggregation("_layout").getContent().length > 1) {
this.getAggregation("_layout").removeContent(0);
//fire deletedAllItemsEvent
this.fireDeletedAllItems({});
}
this.getAggregation("_layout").rerender(); //ReRenders _layout aggregation
},
updateModel : function (newModel, newPath, codePropertyName, descriptionPropertyName) {
this.setModel(newModel);
this.setPath(newPath);
this.setCodePropertyName(codePropertyName);
this.setDescriptionPropertyName(descriptionPropertyName);
var layout = this.getAggregation("_layout");
layout.getContent()[0].setModel(this.getModel());
var template = new sap.ui.core.ListItem({
text: "{"+this.getDescriptionPropertyName()+"}",
additionalText: "{"+this.getCodePropertyName()+"}"
});
layout.getContent()[0].bindItems(this.getPath(), template);
}
JS Bin - Collaborative JavaScript Debugging
EDIT (11/02/2014): Added some enhancements (three new events, and repetead item control).
Any suggestion or feedback will be welcome :smile:
Enjoy!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
9 | |
8 | |
7 | |
5 | |
5 | |
4 | |
4 | |
4 | |
3 | |
3 |