ColumnListItem - Event Handler "press" NOT Triggered - sapui5

I am using ColumnListItem to display a list of Sales Orders in Overview.view.xml. When the user clicks on an item of the list (of Sales Orders), the App should navigate to the Detail.view.xml.
I have defined the onPress event handler in Overview.Controller.js. But the App did not execute the function (I put an alert() there and it was not triggered). Why the onPress() is not triggered? How do I debug?
<Table items="{myOdata>/SalesOrderSet}">
<ColumnListItem type="Navigation" detailPress=".onPress">
<!-- ... -->
</ColumnListItem>
<columns>
<!-- ... -->
</columns>
</Table>
onPress: function (oEvent) {
//This code was generated by the layout editor.
alert("In");
var loOverview = "Data from Overview";
var oItem = oEvent.getSource();
var loRouter = sap.ui.core.UIComponent.getRouterFor(this);
loRouter.navTo("Detail", {
value: oItem.getBindingContext("oModel").getPath().substr(1)
});
},

The press function is not working as you have not written the correct handler for it. As per your code, the handler is written for detailPress. Just a typo, change the handler to press and it should just work.
Current:
<ColumnListItem type="Navigation" detailPress=".onPress">
Change required:
<ColumnListItem type="Navigation" press=".onPress">

the property that you should bind on the Table control is itemPress and your ColumnListItem need to have the type equals to Navigation
Can you check those?

Related

How to register contextmenu event if cell of sap.ui.table is of type input

I try to get an context menu on a table cell which is of type input.
The right mouse click only works in the part outside of the input field.
Is there a way to propergate the event from the input field to the cell below?
Also there does not seem to be an click event on an input field.
My tries can be seen in the plnkr
https://plnkr.co/edit/BMozXm7uRPNlgzUf
codewise:
<t:Table rows="{/}" visibleRowCount="100"
minAutoRowCount="10" visibleRowCountMode="Auto" id="table0"
filter="onTableFilter" class="sapUiNoMargin sapUiNoContentPadding"
beforeOpenContextMenu="onContextMenu">
<t:columns>
<t:Column width="4em" filterProperty="CompCode"
sortProperty="CompCode" resizable="true" autoResizable="true"
class="sapUiLargeNegativeMarginBeginEnd"
click="oninputclick"
press="oninputclick">
<Label text="Comp Code" wrapping="true" class="test_maybe_he"/>
<t:template>
<Input value="{CompCode}" class="test_maybe_he" click="oninputclick"
press="oninputclick"/>
</t:template>
</t:Column>
I have the beforeOpenContextMenu="onContextMenu" in the table tag.
And click="oninputclick" press="oninputclick" in the input tag.
right click is only registerd outside of the input field. (In the sapui5 samples with an Text tag it seems to work.)
I suggest a custom control which inherits from sap.m.Input.
This control should have a new event (e.g. rightPress) and this event should be fired when the native browser event onContextMenu is triggered. Also the native context menu should not be shown.
sap.ui.define([
"sap/m/Input"
], function (Input) {
"use strict";
return Input.extend("gsan.ruleedit.control.MyInput", {
metadata: {
events: {
rightPress: {}
}
},
renderer: {},
oncontextmenu: function(oEvent) {
this.fireRightPress();
oEvent.preventDefault();
}
});
});
You can then use your custom control like any other
<mvc:View xmlns:my="gsan.ruleedit.control"
... />
<my:MyInput value="{CompCode}" rightPress="onContextMenu" />
Working sample: https://plnkr.co/edit/XAfC7SGpdf3RxiDF

Control event not triggered even though control property is updated from model

I have an input box as you can see in the code below.
The data inside the input box is set using model#setProperty, but my onValueChange gets triggered only when I enter the value directly into the input box. It's not triggered when the value is manipulated via binding.
<!-- ... -->
<table:Column xmlns:table="sap.ui.table">
<Label xmlns="sap.m" text="{i18n>ItemCode}" required="true" />
<table:template>
<Input value="{model1>itemCd}" change=".onValueChange" />
</table:template>
</table:Column>
<!-- ... -->
onValueChange: function(oEvent){
console.log("inside function onValueChange");
},
Try with liveChange beacause from library doesn't exist event change, but event liveChange. Perhaps is deprecated?
As #Marc mentioned change event is part of the Input, not of the model. So it is only triggered if you change the actual Input and not the bound value. Its true but there is a workaround for it.
You can achieve it using input fireLiveChange event and formatter.
View.xml
<Input value="{path: 'ipModel>/text', formatter: 'assets.util.Formatter.triggerLiveChange'}"
liveChange="ipLiveChange" />
Controller.js
onInit: function() {
this.setInputModel();
},
setInputModel:function() {
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({ text: "Test Value"});
this.getView().setModel(oModel, "ipModel");
},
ipLiveChange: function(oEvent) {
console.log("LiveChange triggered!!");
}
Formatter.js
jQuery.sap.declare("assets.util.Formatter");
assets.util.Formatter = {
triggerLiveChange: function (value) {
this.fireLiveChange();
return (value);
}
};

How to set the input of a combobox to read-only

In one of my UI5-Dialogs, I implemented a combobox which is invisible when the screen is initially loaded.
In the method onAfterRendering, I start with setting the input to read-only:
onAfterRendering: function(oEvent) {
var oShovel = this.getView("View0200").byId("comboShovel");
oShovel.$().find("input").attr("readonly", true);
this.setVisibleByListKey();
},
After this the method setVisibleByListKey is called, the property visibleShovel will be set to false.
setVisibleByListKey: function(oEvent) {
var oModel = this.getView("View0200").getModel("Data0200");
this.setVisibleByListKey1(oModel);
// ...
},
setVisibleByListKey1: function(oModel) {
oModel.setProperty("/visibleShovel", false);
},
The property is bound to the attribute visible on my combobox.
Because of this behavior, the method onAfterRendering will be called again, the attribute readonly is not available (because of invisibility).
<ComboBox id="comboShovel"
editable="true"
enabled="true"
visible="{Data0200>/visibleShovel}"
valueState="None"
change=".changeCombo">
<items>
<core:Item text="Ja" enabled="true" key="0" />
<core:Item text="Nein" enabled="true" key="1" />
<core:Item text="Nicht erforderlich" enabled="true" key="2" />
</items>
</ComboBox>
I tried to call the set method in onInit or onBeforeRendering but at this time the input attributes can not be changed (because of invisibility again).
So how can I set the input of the combobox to read-only when I set the named visible property?
Solution would be either to use sap.m.Select or to implement a "change" event handler for the sap.m.Combobox and use a coding similar to this sample:
handleChange: function(oEvent) {
var oValidatedComboBox = oEvent.getSource();
var sSelectedKey = oValidatedComboBox.getSelectedKey();
var sValue = oValidatedComboBox.getValue();
if (!sSelectedKey && sValue) {
oValidatedComboBox.setValueState("Error");
oValidatedComboBox.setValueStateText("Please enter a valid country!");
} else {
oValidatedComboBox.setValueState("None");
}
},
Instead of using jquery, use UI5 control's methods and properties:
The sap.m.ComboBox borrows the following two methods from sap.m.InputBase:
setEditable
setEnabled
or since you are using property binding for the visibility, do the same for the editable property, e.g. {Data0200>/editableShovel}

ComboBox in UI5 does not display ValueState

ComboBox is not showing state like Error, Warning with highlight around the borders. But it does change the state. For example, if it is error state, and if I try to enter new value in combobox, it will show that "invalid Entry" tip near the box. But the box borders are never highlighted in red. Below is the code:
XML.view
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout">
<Dialog id......>
<ComboBox id="combo1" change="cChanged" items="{path: '/results'}">
<items>
<core:Item key="{ID}" text="{Name}"/>
</items>
</ComboBox>
</Dialog>
Controller.js
cChanged: function(oEvent) {
var newval = oEvent.getParameter("newValue");
var key = oEvent.getSource().getSelectedItem();
if (newval !== "" && key === null) {
sap.ui.getCore().byId("combo1").setValueState("Error");
oEvent.getSource().setValue("");
sap.m.MessageToast.show("Please select from existing IDs")
flag = false;
} else {
oEvent.getSource().setValueState('None');
}
You can also access combo1 control instance by using oEvent.getSource() event OR use byId() from the sap.ui.core.Fragment class and not sap.ui.getCore().byId()
Also, if you are writing a logic only to validate if what the user input in the combobox is a valid item, consider replacing your ComboBox by the sap.m.Select control.
Both ComboBox and Select has same look and feel, but Select does not allow a manual input. It can also have an empty option if you use the property forceSelection

`sap.m.HeaderContainer` triggers rendering twice

Why are the rendering events of the view (such as onBeforeRendering and onAfterRendering) in the scenario 1 triggered twice?
Scenario 1
Sample.view.xml
<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
controllerName="my.controller.Sample">
<Page id="EmpStat" showHeader="false">
<HeaderContainer>
<!-- ... -->
</HeaderContainer>
</Page>
</mvc:View>
Sample.controller.js
onAfterRendering: function() {
alert("Test"); // called twice
},
Scenario 2
Sample.view.xml
<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns:layout="sap.ui.layout"
xmlns="sap.m"
controllerName="my.controller.Sample">
<Page>
<!-- No <HeaderContainer> -->
<layout:Grid>
<!-- ... -->
</layout:Grid>
</Page>
</mvc:View>
Sample.controller.js
onAfterRendering: function() {
alert("Test"); // called once.
},
HeaderContainer has a borrowed class onAfterRendering from sap.ui.core.control, hence in scenario one headerContainer calls this method once and sap.m.Page calls the method another time.
The only way is it to handle the scenario is bypassing the execution of your code a second time either by using event parent source check or by using the logic I have given below as in most of the cases the event gets called only twice.
You can create a counter in onInit() and then update the value in onAfterRendering() and execute the corresponding code only when the condition is matched with the counter value.
onInit:function(){
this.afterRenderingCount = 0;
},
onAfterRendering: function (oEvent) {
if(this.afterRenderingCount === 1){
this.afterRenderingCount =0;
//method call
this.exampleMethod();
}
this.afterRenderingCount++;
}