Object Page with blocks - sapui5

I've got this ObjectPageLayout:
request.view.xml
<ObjectPageLayout>
<headerTitle>
...
</headerTitle>
<headerContent>
...
</headerContent>
<sections>
<ObjectPageSection
mode="Collapsed">
<subSections>
<ObjectPageSubSection title="fooBlock">
<blocks>
<blockdetail:FormBlock columnLayout="auto" /> <!-- MY BLOCK -->
</blocks>
</ObjectPageSubSection>
</subSections>
</ObjectPageSection>
</sections>
</ObjectPageLayout>
FormBlockCollapsed.view.xml (MY BLOCK)
<mvc:View xmlns:f="sap.ui.layout.form" xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout" xmlns="sap.m"
controllerName="NAMESPACE.blocks.DetailsBlockCommon">
<FlexBox>
<HBox>
<VBox>
<f:SimpleForm >
<f:content>
<CheckBox class="sapUiSmallMarginBegin sapUiSmallMarginTop" id="myCheckbox" />
</f:content>
</f:SimpleForm>
</VBox>
</HBox>
</FlexBox>
...
</mvc:View>
So far, everything is fine. My Object page looks good a the checkbox is shown.
In my Controller request.controller.js i want to validate the checkbox in FormBlockCollapsed.view.xml
validateBlockForm: function(format){
console.log( oView.byId("myCheckbox").checked() ); //oView.byId("myCheckbox") is undefined
}
But i've no access to my checkbox in the block.
Cannot read property 'checked' of undefined
Further infos
FormBlock.js
sap.ui.define(['sap/uxap/BlockBase'], function (BlockBase) {
"use strict";
var MultiViewBlock = BlockBase.extend("NAMESPACE.blocks.FormBlock", {
metadata: {
views: {
Collapsed: {
viewName: "NAMESPACE.blocks.FormBlockCollapsed",
type: "XML"
}
}
}
});
return MultiViewBlock;
}, true);
DetailBlockCommon.js
sap.ui.define([
"NAMESPACE/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("NAMESPACE.blocks.DetailsBlockCommon", {
});
});

You can access the elements in a section by having the block's id and element's id.
First we have to define an id for the block in the xml view:
<blocks>
<blockdetail:FormBlock id="formBlock" columnLayout="auto" /> <!-- MY BLOCK -->
</blocks>
Then we generate the id of the elements like the following in the view controller. The state of the art here is to add -Collapsed-- as part of the id that adds by SAPUI5 to sections elements.
var sFieldId = this.getView().createId("formBlock") +
"-Collapsed--myCheckbox";
var oCheckbox = sap.ui.getCore().byId(sFieldId);

Check if oView is defined.
you can easily get it by this.getView()

Related

How to get $count into a tile

I am an ABAP developer who is just trying to take the first steps in SAPUI5/Fiori.
So my very simple task is to create a fiori app with a single tile to show the number of EDIDC records.
View1.controller.js:
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("QuickStartApplication.controller.View1", {
onGetValue: function ( ) {
var oTileValue = this.getView().byId("tile1");
this.getModel().read("/EDIDCSet/$count", {
success: $.proxy(function (oEvent, oResponse) {
// var count = Number(oResponse.body);
var count = "1337";
oTileValue.setValue(count);
}, this)
});
}
});
});
View1.view.xml:
<mvc:View xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
controllerName="QuickStartApplication.controller.View1">
<App id="idAppControl">
<pages>
<Page xmlns="sap.m" id="pageId" title="TileTest" floatingFooter="true">
<content>
<Button xmlns="sap.m" text="Button" id="button0" press=".onGetValue"/>
<GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Country-Specific Profit Margin" subheader="Expenses"
press="press" id="tile1">
<TileContent unit="EUR" footer="Current Quarter">
<NumericContent scale="M" value="1000" valueColor="Error" indicator="Up" withMargin="false"/>
</TileContent>
</GenericTile>
</content>
</Page>
</pages>
</App>
</mvc:View>
As you can see, I can't even pass the value "1337" that I hardcoded.
​My first mistake was to adress the tile and not the numeric content of the file. So first, I gave the ID to the numeric content:
​
<NumericContent scale="M" value="" valueColor="Error" indicator="Up" withMargin="false" id="num1"/>
​
​Then, I've adjusted the line, to access the object:
var oTileValue = this.getView().byId("num1");
​The last thing I learned was, that the model is connected to the view. So to access this, I changed the line to:
​this.getView().getModel().read("/EDIDCSet/$count", {
​Now I can call my function onGetValue and it's working.

VizFrame doesn't update when the bound model changes

I have a sap.viz.ui5.controls.VizFrame with its data property bound to a two-way JSON model in my view. Additionally, I have a Button and a Text element in the same view. The Text element displays the values of the model, which is bound against the VizFrame, and the Button has a press event handler, which increases the value of one property of the model.
So, when I press the button, the Text updates automatically, unlike the VizFrame. Do you have any suggestions on how to fix this? I saw this vizUpdate method, but it looked very complex and is probably overkill. However, changing the whole model also changes the displayed data of the VizFrame.
Code Example
Main.view.xml
<mvc:View controllerName="demo.chart.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m"
xmlns:viz="sap.viz.ui5.controls" xmlns:viz.data="sap.viz.ui5.data" xmlns:viz.feeds="sap.viz.ui5.controls.common.feeds">
<Shell id="shell">
<App id="app">
<pages>
<Page id="page" title="{i18n>title}">
<content>
<VBox>
<viz:VizFrame id="vizFrame" uiConfig="{applicationSet:'fiori'}" vizType='donut'>
<viz:dataset>
<viz.data:FlattenedDataset data="{data>/}">
<viz.data:dimensions>
<viz.data:DimensionDefinition name="Type" value="{manipulatedData>type}"/>
</viz.data:dimensions>
<viz.data:measures>
<viz.data:MeasureDefinition name="Amount" value="{manipulatedData>amount}"/>
</viz.data:measures>
</viz.data:FlattenedDataset>
</viz:dataset>
<viz:feeds>
<viz.feeds:FeedItem uid="color" type="Dimension" values="Type"/>
<viz.feeds:FeedItem uid="size" type="Measure" values="Amount"/>
</viz:feeds>
</viz:VizFrame>
<Button text="+1 Foo" press="onButtonPress"/>
<Text text="Foo: {data>/0/amount} | Bar: {data>/1/amount}"/>
</VBox>
</content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>
Main.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel"
], function (Controller, JSONModel) {
"use strict";
return Controller.extend("demo.chart.controller.Main", {
onInit: function () {
this.mData = new JSONModel([{
type: "foo",
amount: 23
}, {
type: "bar",
amount: 20
}]).setDefaultBindingMode("TwoWay");
this.getView().setModel(this.mData, "data");
},
onButtonPress() {
this.mData.setProperty("/0/amount", this.mData.getProperty("/0/amount") + 1);
}
});
});
I guess I figured it out. You have to rebind the data to the dataset aggregation after you changed the model:
Working Example
Main.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel"
], function (Controller, JSONModel) {
"use strict";
return Controller.extend("demo.chart.controller.Main", {
onInit: function () {
this.mData = new JSONModel([{
type: "foo",
amount: 23
}, {
type: "bar",
amount: 20
}]).setDefaultBindingMode("TwoWay");
this.getView().setModel(this.mData, "data");
},
onButtonPress() {
this.mData.setProperty("/0/amount", this.mData.getProperty("/0/amount") + 1);
this.byId("vizFrame").getDataset().bindData({
path: "data>/"
});
}
});
});

How to extend "sap.m.Dialog" to add custom content to Dialog footer?

I am trying to make a custom dialog to show some text and link in the footer along with buttons. I don't know how to change the existing rendering for this, so I wrote a simple renderer to check the behavior. This is my code:
sap.m.Dialog.extend("EnhancedDialog",{
metadata:{
properties:{
footerLabelText:{type:"string",defaultValue:null},
footerLinkText:{type:"string",defaultValue:null},
footerLinkHref:{type:"string",defaultValue:null}
},
aggregations:{
_label:{type:"sap.m.Label",multiple:false,visibility:"hidden"},
_link:{type:"sap.m.Link",multiple:false,visibility:"hidden"}
},
events:{}
},
init:function(){
this.getAggregation("_label", new sap.m.Label({text:"Check"}));
this.getAggregation("_link",new sap.m.Link({text:"Link"}));
},
setFooterLabelText:function(oLabelText){
this.setProperty("footerLabelText",oLabelText,true);
this.getAggregation("_label").setText(oLabelText);
},
setFooterLinkText:function(oLinkText){
this.setProperty("footerLinkText",oLinkText,true);
this.getAggregation("_link").setText(oLinkText);
},
setFooterLinkHref:function(oLinkHref){
this.setProperty("footerLinkHref",oLinkHref,true);
this.getAggregation("_link").setHref(oLinkHref);
},
renderer:{
render:function(oRM,oControl){
oRM.write("<div");
oRM.writeControlData(oControl);
oRM.writeClasses();
oRM.write(">");
oRM.renderControl(oControl.getAggregation("_label"));
oRM.renderControl(oControl.getAggregation("_link"));
oRM.write("</div");
}
}
});
var enhancedDialog=new EnhancedDialog();
var btn=new sap.m.Button({
text:"Click Here!",
press: function(){
enhancedDialog.open();
}
});
But I am getting the error
Dialog.js:6 Uncaught TypeError: Cannot read property 'setInitialFocusId' of undefined
when I am clicking the button.
Can someone point out what I am doing wrong?
And how to change the existing renderer behavior to show text in the footer?
This is what I want to make:
The error you are seeing is because you have overwritten the init() method and not called the overwritten init() of Dialog. So the internal popup and other stuff does not get initialized. You have to call the base.init() this way:
init:function(){
sap.m.Dialog.prototype.init.apply(this,arguments);
this.getAggregation("_label", new sap.m.Label({text:"Check"}));
this.getAggregation("_link",new sap.m.Link({text:"Link"}));
},
However you will need to copy most of the DialogRenderers code to get a fully functional dialog.
Alternatively you could use the unmodified DialogRender and overwrite the Dialog._createToolbarButtons() method to add your Label and Link to the beginning:
_createToolbarButtons:function () {
Dialog.prototype._createToolbarButtons.apply(this,arguments);
var toolbar = this._getToolbar();
var toolbarContent = toolbar.getContent();
toolbar.removeAllContent();
toolbar.addContent(this.getAggregation("_label"));
toolbar.addContent(this.getAggregation("_link"));
// insertContent is not implemented correctly...
toolbarContent.forEach(function(control){toolbar.addContent(control)});
},
renderer:DialogRenderer
Full example on Plunker.
[...] show some text and link in the footer along with buttons.
Having a customizable Dialog footer is now supported since UI5 1.110. Simply define sap.m.Toolbar in the new <footer> aggregation of your sap.m.Dialog. For example:
<Dialog xmlns="sap.m" title="Title" initialFocus="okButton">
<!-- ... -->
<footer> <!-- Since UI5 1.110: -->
<Toolbar>
<Text text="Some text!" />
<ToolbarSpacer />
<Button id="okButton" text="OK" type="Emphasized" />
<Button text="Cancel" />
</Toolbar>
</footer>
</Dialog>
Sample demo:
globalThis.onUI5Init = () => sap.ui.require([
"sap/ui/core/mvc/XMLView",
], async (XMLView) => {
"use strict";
const control = await XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
displayBlock="true"
height="100%"
>
<App autoFocus="false">
<dependents>
<Dialog id="myDialog"
class="sapUiResponsiveContentPadding sapUiResponsivePadding--header sapUiResponsivePadding--content sapUiResponsivePadding--footer"
initialFocus="okButton"
title="Title"
draggable="true"
resizable="true"
>
<Text text="Content ..." />
<footer>
<Toolbar>
<Text text="Some text in the footer!" />
<ToolbarSpacer />
<Button id="okButton" text="OK" type="Emphasized" />
<Button text="Cancel" />
</Toolbar>
</footer>
</Dialog>
</dependents>
</App>
</mvc:View>`,
afterRendering: function () {
this.byId("myDialog").open();
}
});
control.placeAt("content");
})
<script id="sap-ui-bootstrap"
src="https://sdk.openui5.org/nightly/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core,sap.m,sap.ui.unified,sap.ui.layout"
data-sap-ui-async="true"
data-sap-ui-oninit="onUI5Init"
data-sap-ui-theme="sap_horizon"
data-sap-ui-compatversion="edge"
data-sap-ui-excludejquerycompat="true"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>

How to push the data in XML view into the newly created JSON model?

How to push the data in XML view into the newly created JSON model? I have created the comboBox and retrieved the data from JSON model and also created the text area when I select the item in combo box and insert data into the text area and submit a button both the data should be pushed to newly created JSON model in sapweb ide ui5
page.view.xml:
<mvc:View height="100%" controllerName="pro.controller.Page" xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m">
<Page title="{i18n>title}">
<content>
<l:VerticalLayout>
<ComboBox items="{ path: '/ProductCollection', sorter: { path: 'Name' } }">
<core:Item text="{Name}" /> </ComboBox>
<TextArea value="" rows="8" />
<Button type="Accept" text="Submit" press="onPress" /> </l:VerticalLayout>
</content>
</Page>
</mvc:View>
page.controller.js
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
], function(jQuery, Controller, JSONModel) {
"use strict";
var PageController = Controller.extend("pro.controller.Page", {
onInit: function() {
// set explored app's demo model on this sample
var oModel = new JSONModel(jQuery.sap.getModulePath("pro", "/model/model.json"));
this.getView().setModel(oModel);
}
});
return PageController;
});
add a 'key' attribute to the combobox item. Also give the combobox and teaxarea some IDs.
<ComboBox id="selectBox" items="{ path: '/ProductCollection', sorter: { path: 'Name' } }">
<core:Item key="{Naame}" text="{Name}" /> </ComboBox>
<TextArea id="textArea" value="" rows="8" />
On click of submit, get the selected values from the combobox and text area and push them into the model. I assume that you wanted to push this new data to the existing model and also your existing model is an array of objects.
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
],function(jQuery, Controller, JSONModel) {
"use strict";
var PageController = Controller.extend("pro.controller.Page", {
onInit: function() {
var oModel = new JSONModel(jQuery.sap.getModulePath("pro", "/model/model.json"));
this.getView().setModel(oModel);
},
onPress: function() {
//get the value of the selected item in the combobox
var selectedVal = this.getView().byId("selectBox").getSelectedKey();
//get the textarea value
var textAreaVal = this.getView().byId("textArea").getValue();
this.getView().getModel().oData.push({
key: selectedVal,
value: textAreaVal
});
}
});
return PageController;
});

Pass data from one view to another view, using target

I am new to sapui5, i am trying to make an app with two views.one view with multicomboBox and another with dynamic table , after selection of items from multicomboBox i have to click submit button. on submit button click i have to navigate to another view and create a table with column name, column name will be selected values of multicomboBox.
i am using target to navigate and used xml view.
The problem is i am getting the selected items, how to pass the selected data to another view and create the table is the issue i am facing.
i am posting the views and controllers below. The below code is taken from sapui5 Explored, i have combined multicomboBox and Target Program. Thanks in advance
View1.xml
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:l="sap.ui.layout"
xmlns:html="http://www.w3.org/1999/xhtml"
controllerName="sap.ui.core.sample.trial.targetsApp.controller.View1"
xmlns:form="sap.ui.layout.form">
<App>
<Page title="Example 1">
<MultiComboBox selectionChange="handleSelectionChange" selectionFinish="handleSelectionFinish" width="500px"
items="{
path: '/Collection',
sorter: { path: 'Name' }
}">
<core:Item key="{ProductId}" text="{Name}" />
</MultiComboBox>
<footer>
<Bar>
<contentRight>
<Button text="Submit" press="onToView2" />
</contentRight>
</Bar>
</footer>
</Page>
</App>
</mvc:View>
View2.xml
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:l="sap.ui.layout"
xmlns:html="http://www.w3.org/1999/xhtml"
controllerName="sap.ui.core.sample.trial.targetsApp.controller.View2"
xmlns:form="sap.ui.layout.form">
<App>
<Page title="TableView"
showNavButton="true"
navButtonPress="onBack">
<footer>
<Bar>
<contentRight>
<Button text="Submit" press="onToView2" />
</contentRight>
</Bar>
</footer>
</Page>
</App>
</mvc:View>
controller for view1
sap.ui.define([
'jquery.sap.global',
'sap/m/MessageToast',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
], function(jQuery, MessageToast, Controller, JSONModel) {
"use strict";
var PageController = Controller.extend("sap.ui.core.sample.trial.targetsApp.controller.View1", {
onInit: function () {
// set explored app's demo model on this sample
var oModel = new JSONModel(jQuery.sap.getModulePath("sap.ui.demo.mock", "/products.json"));
this.getView().setModel(oModel);
},
onToView2 : function () {
this.getOwnerComponent().getTargets().display("page2");
},
handleSelectionChange: function(oEvent) {
var changedItem = oEvent.getParameter("changedItem");
var isSelected = oEvent.getParameter("selected");
var state = "Selected";
if (!isSelected) {
state = "Deselected"
}
MessageToast.show("Event 'selectionChange': " + state + " '" + changedItem.getText() + "'", {
width: "auto"
});
},
handleSelectionFinish: function(oEvent) {
var selectedItems = oEvent.getParameter("selectedItems");
var messageText = "Event 'selectionFinished': [";
for (var i = 0; i < selectedItems.length; i++) {
messageText += "'" + selectedItems[i].getText() + "'";
if (i != selectedItems.length-1) {
messageText += ",";
}
}
messageText += "]";
MessageToast.show(messageText, {
width: "auto"
});
},
handleNav: function(evt){
this.getOwnerComponent().getTargets().display("page2");
}
});
return PageController;
}, true);
controller for view2
sap.ui.define( ["sap/ui/core/mvc/Controller"], function (Controller) {
"use strict";
return Controller.extend("sap.ui.core.sample.trial.targetsApp.controller.View2", {
onBack : function () {
this.getOwnerComponent().getTargets().display("page1");
}
});
},true);
Edited controller2.js
sap.ui.define( ["sap/ui/core/mvc/Controller"], function (Controller) {
"use strict";
return Controller.extend("sap.ui.core.sample.trial.targetsApp.controller.View2", {
onInit:function(){
//console.log(sap.ui.getCore().AppContext.selectedArray);
//console.log(sap.ui.getCore().AppContext.selectedArray.length);
var oTable = new sap.m.Table();
for(var i = 0;i < sap.ui.getCore().AppContext.selectedArray.length;i++){
oTable.addColumn(new sap.m.Column({
demandPopin : true,
header:new sap.m.Text({text:sap.ui.getCore().AppContext.selectedArray[i]})
}));
}
//not working i want to place it in view2.xml
//oTable.placeAt("content");
},
displayPress : function(){
console.log(sap.ui.getCore().AppContext.selectedArray);
console.log(sap.ui.getCore().AppContext.selectedArray.length);
console.log(sap.ui.getCore().AppContext.selectedArray[0]);
console.log(sap.ui.getCore().AppContext.selectedArray[1]);
},
onBack : function () {
this.getOwnerComponent().getTargets().display("page1");
}
});
}, true);
edited view2.xml
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:l="sap.ui.layout"
xmlns:html="http://www.w3.org/1999/xhtml"
controllerName="sap.ui.core.sample.trial.targetsApp.controller.View2"
xmlns:form="sap.ui.layout.form">
<App>
<Page title="TableView"
showNavButton="true"
navButtonPress="onBack">
<l:HorizontalLayout id="tableid">
</l:HorizontalLayout>
<footer>
<Bar>
<contentRight>
<Button text="Add New Rows" press="displayPress" />
<Button text="display" press="displayPress" />
</contentRight>
</Bar>
</footer>
</Page>
</App>
</mvc:View>
Use in handleNav function:
//yourData can be any variable or object
this.getOwnerComponent().getTargets().display("page2", yourData);
Read more here:
display(vTargets, vData?): sap.ui.core.routing.Targets