SAPUI5 filterbar initialise Event not triggered - sapui5

I try to set initial values in a filterbar and use the initialise Event of the filterBar Control. But the event is not triggered.
This is the XML:
<fb:FilterBar id="myFilterBar" reset="onReset" search="onSearch" initialise="onInitialise" showRestoreButton="true" showClearButton="true">
<fb:filterGroupItems>
<fb:FilterGroupItem name="FieldA" groupName="FilterGroup" label="SelectionA" visibleInFilterBar="true">
<fb:control>
<Input type="Text" value="{viewModel>/valueA}"/>
</fb:control>
</fb:FilterGroupItem>
<fb:FilterGroupItem name="FieldB" groupName="FilterGroup" label="SelectionB" visibleInFilterBar="true" >
<fb:control>
<Input type="Text" value="{viewModel>/valueB}"/>
</fb:control>
</fb:FilterGroupItem>
</fb:filterGroupItems>
</fb:FilterBar>
and the controller.js
onInit: function() {
var oModel = new sap.ui.model.json.JSONModel();
this.getView().setModel(oModel, "viewModel");
oModel.setProperty("/valueA", "My Value A");
oModel.setProperty("/valueB", "My Value B");
console.log("this is onInit");
},
onInitialise: function(){
console.log("this is onInitialise");
oModel = this.getView().getModel("viewModel");
oModel.setProperty("/valueB", "Value from Initialise");
},
});
The values can also be set in the onInit Event of the application, but the initialise Event seems to be the more appropriate place. In the final application the selection should be triggered from there after the initial Selection Values are loaded from the backend.
I created a jsfiddle for this: https://jsfiddle.net/6svwcb0z/1/
Only the initial values definied in onInit are displayed. The value in Field 'SelectionB' should change in the 'initialise' Event. I would also expect the console to show that the onInitialise Method is executed.
What am I missing to trigger the initialise event?

Related

SAP UI5 : Unable to bind a controller variable in xml

Button on click of which the variable is getting changed:
<f:content>
<Button icon="sap-icon://edit" press="editClick" type="Transparent"></Button>
</f:content>
xml code where i need 2-way binding:
<VBox class="sapUiSmallMargin">
<form:SimpleForm id="SimpleFormDisplayColumn_oneGroup">
<form:content>
<Label text="{i18n>contextofusage}"/>
<Text text="{contextofusagetext}" visible="{!isInfoEditable}"/>
<Input type="Text" visible="{isInfoEditable}" value="{contextofusagetext}"></Input>
</form:content>
</form:SimpleForm>
</VBox>
controller:
var isInfoEditable=false;
return Controller.extend("abc.controller.Detail", {
editInfoClick: function(event){
if(isInfoEditable){
isInfoEditable=false;
}
else{
isInfoEditable=true;
}
}
});
It seems like you have tried nothing, but I will try to guide you:
You cannot simply declare a variable in your controller and then use it in your view. That's not how UI5 works. Instead create a model and bind it to your view. I also give my models a name, in this case "view":
onInit: function() {
var oViewModel = new sap.ui.model.json.JSONModel({
isInfoEditable: false
});
this.getView().setModel(oViewModel, "view");
}
Then use it in your view. Make sure that you use the name of your model ("view") in your bindings. If you want to do more than simply use the raw value (e.g. negate it) you have to use expression binding. Also you have to use an absolute path starting with /:
<form:SimpleForm id="SimpleFormDisplayColumn_oneGroup">
<form:content>
<Label text="{i18n>contextofusage}"/>
<Text text="{contextofusagetext}" visible="{= !${view>/isInfoEditable} }"/>
<Input type="Text" visible="{view>/isInfoEditable}" value="{contextofusagetext}"></Input>
</form:content>
</form:SimpleForm>
When you click on the button you have to modify/toggle the value in your model:
editClick: function (oEvent) {
var oViewModel = this.getView().getModel("view");
var bIsEditable = oViewModel.getProperty("/isInfoEditable");
// negate the current value and set it as the new value
oViewModel.setProperty("/isInfoEditable", !bIsEditable);
}
I suggest strongly reading on the basics of UI5. Your approach looks more like Vue.js, but UI5 has its own paradigms.

How to add a Autofill filter in FilterBar

I'm trying to implement filters using SAPUI5 FilterBar. I want to add a field which works like a dropdown filter only when you type something in it. When you put the cursor, it should not show any results, but as you start typing something, the matching results should show up in the dropdown.
Here is a working example: Plunker
You could use a Input object in the filterGroupItems aggregation of the FilterBar control.
Note: The filterItems aggregation is deprecated as of version 1.48
<fb:FilterBar id="filterBar">
<fb:filterGroupItems>
<fb:FilterGroupItem
groupName="GroupExample"
name="regionGroup"
label="Example"
visibleInFilterBar="true">
<fb:control>
<Input showSuggestion="true">
<suggestionItems>
<core:Item key="001" text="Russia"/>
<core:Item key="002" text="America"/>
<core:Item key="003" text="Australia"/>
<core:Item key="004" text="Germany"/>
</suggestionItems>
</Input>
</fb:control>
</fb:FilterGroupItem>
</fb:filterGroupItems>
</fb:FilterBar>
Which produces:
Be sure to add the visibleInFilterBar="true" attribute if you want your input field to be visible without having to add it in the Filters prompt.
If you want to add the Input items dynamically, add an aggregation binding to the <items>.
To do that, change the Input control as follows:
<Input suggestionItems="{path: '/dropdownData'}" showSuggestion="true">
<suggestionItems>
<core:Item key="{key}" text="{text}"/>
</suggestionItems>
</Input>
And set the model according to your datasource (here it's a JSONModel) in the controller:
onInit: function() {
this.oModel = new JSONModel("/data.json");
var oView = this.getView();
oView.setModel(this.oModel);
}

Data Binding from TableSelectDialog to Form

I'm using TableSelectDialog to view some Carrier details. All I need is: If I select any item (row), then all the values from that row should get automatically populated to the form input fields.
In the attached image, if Carrier Name is selected from TableSelectDialog, then the remaining fields should be populated based on that value.
You can achieve the required functionality using the Binding context that you receive from the TableSelcect Dialog.
But for binding context to work properly, both form and the table select dialog should refer to the same Model.
Below is the working code:
VIEW.XML:
Has a Button to trigger the table select dialog.
Has a form.
<l:VerticalLayout class="sapUiContentPadding" width="100%">
<l:content>
<Button class="sapUiSmallMarginBottom" text="Show Table Select Dialog"
press="handleTableSelectDialogPress">
</Button>
<VBox class="sapUiSmallMargin">
<f:SimpleForm id="SimpleFormDisplay354">
<f:content>
<Label text="Supplier Name" />
<Text id="nameText" text="{SupplierName}" />
<Label text="Description" />
<Text text="{Description}" />
<Label text="ProductId" />
<Text text="{ProductId}" />
<Label text="Quantity" />
<Text id="countryText" text="{Quantity}" />
</f:content>
</f:SimpleForm>
</VBox>
</l:content>
</l:VerticalLayout>
Controller:
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);
},
handleTableSelectDialogPress: function (oEvent) {
if (!this._oDialog) {
this._oDialog = sap.ui.xmlfragment("sap.m.sample.TableSelectDialog.Dialog", this);
}
this.getView().addDependent(this._oDialog);
// toggle compact style
this._oDialog.open();
},
handleClose: function (oEvent) {
var aContexts = oEvent.getParameter("selectedContexts");
if (aContexts && aContexts.length) {
// MessageToast.show("You have chosen " + aContexts.map(function(oContext) { return oContext.getObject().Name; }).join(", "));
this.byId('SimpleFormDisplay354').setBindingContext(aContexts[0]);
}
oEvent.getSource().getBinding("items").filter([]);
}
Now, we also have a Select dialog and on click of any Item we call method : handleClose
In handleClose, we obtain the clicked Item binding context and then tell the form : hey! refer to this context ( which is present in the model). Binding context has a path which tells the form from where to do the relative binding.
Please feel free to contact for more information.

ValueHelpDialog error adding element with duplicate id

The first time I open die ValueHelpDialog and chose an item there are no errors. However when I open the dialog again and click on the same entry I get the following error:
Uncaught Error: Error: adding element with duplicate id
'EQ5IPAKCZJMZR'
at constructor.x.registerElement (Core-dbg.js:2711)...
When I click again i get another error:
Uncaught TypeError: Cannot read property 'getKey' of undefined
at constructor.onVHOK (ValueHelper.js?eval:35)...
When I click a third time it works without an error.
I use
this._dialog.close();
this._dialog.destroy();
in the event handlers for the ok event as well as for the cancel event.
Is the second error related to the first one? I thought closing and destroying the dialog would be enough to avoid those duplicate id errors.
Edit: More code
Controller:
this._ValueHelper = new ValueHelper();
/* Calling valueHelper */
onVH: function(oEvent) {
this._ValueHelper.handleValueHelp(this, {
srcCtrl: oEvent.getSource()
});
},
ValueHelper.js:
handleValueHelp: function(oController, mOptions) {
if (mOptions == null) {
mOptions = {};
}
this._controller = oController;
this._view = oController.getView();
this._model = this._controller.getModel();
this._callback = mOptions.fnCallback;
this._srcCtrl = mOptions.srcCtrl;
if (this._dialog != null) {
this._dialog.open();
} else {
this._buildValueHelp();
}
},
_buildValueHelp: function() {
var oDialog = sap.ui.xmlfragment(
"xxx.view.fragments.valueHelper.ValueHelp",
this
);
this._view.addDependent(oDialog);
this._dialog = oDialog;
this._registerEnterEvent(oDialog);
var oTable = sap.ui.xmlfragment(
"xxx.view.fragments.valueHelper.ValueHelpTable",
this
);
this._table = oTable;
oDialog.setTable(oTable);
oDialog.open();
},
onVHOK: function(oEvent) {
var sId = oEvent.getParameter("tokens")[0].getKey();
this._handleOk(sId);
this._dialog.close();
/*this._dialog.destroy();*/
},
onVHClose: function() {
this._dialog.close();
/*this._dialog.destroy();*/
},
ValueHelp.fragment:
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:vh="sap.ui.comp.valuehelpdialog" xmlns:fb="sap.ui.comp.filterbar">
<vh:ValueHelpDialog key="id" ok="onVHOK" cancel="onVHClose" selectionChange="onVHSelectionChange"
title="Car" supportMultiselect="false" supportRanges="false" supportRangesOnly="false" descriptionKey="Car">
<vh:filterBar>
<fb:FilterBar advancedMode="true" filterBarExpanded="true" search="onVHShipSearch">
<fb:filterGroupItems>
<fb:FilterGroupItem groupName="car" name="n1" label="Name">
<fb:control>
<Input />
</fb:control>
</fb:FilterGroupItem>
<fb:FilterGroupItem groupName="car" name="n2" label="imnr">
<fb:control>
<Input/>
</fb:control>
</fb:FilterGroupItem>
</fb:filterGroupItems>
</fb:FilterBar>
</vh:filterBar>
</vh:ValueHelpDialog>
</core:FragmentDefinition>
ValueHelpTable.fragment:
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:t="sap.ui.table">
<t:Table rows="{path: '/Cars'}" selectionBehavior="Row" selectionMode="Single">
<t:columns>
<t:Column>
<t:label>
<Label text="Number"/>
</t:label>
<t:template>
<Text text="{ path: 'number', formatter: '.formatter.leadingZeroes' }"/>
</t:template>
</t:Column>
<t:Column>
<t:label>
<Label text="Name"/>
</t:label>
<t:template>
<Text text="{name}"/>
</t:template>
</t:Column>
<t:Column>
<t:label>
<Label text="imnr"/>
</t:label>
<t:template>
<Text text="{imnr}"/>
</t:template>
</t:Column>
</t:columns>
</t:Table>
</core:FragmentDefinition>
I thought closing and destroying the dialog would be enough to avoid those duplicate id errors.
Usually, it is. But the dialog is probably still being referenced by other elements. In this case, you could...:
Try to remove the references from all reference holders before destroying it.
For example, if the view has the dialog in its <dependents> aggregation:
this._dialog.attachEventOnce("afterClose", () => {
this.getView().removeDependent(this._dialog);
this._dialog.destroy();
this._dialog = null;
}).close();
But I'm not aware of any effective ways to find all reference holders. Hence ..
Double check if it's really necessary to destroy the dialog every time after closing. Such an attempt is usually a sign of premature optimization. As long as there is no memory issue, I'd keep the dialog in memory so that it can be opened quickly next time.
If you're destroying the dialog for another reason, please add it to your question.
I had the same problem and resolved it by making this sequence of choices.
closeIndicator: function(oEvent) {
this._dialog.close(); // First: close fragment
this._dialog.destroy(); //Second: destoy fragment
this._dialog=null; // Third: null name/pointer
},
The problem is that when you perform the destroy you do not nullify the variable.

add second filter without removing the existing ones

Hi i have a searchfield with this code behind it:
onSearch : function (oEvent) {
if (oEvent.getParameters().refreshButtonPressed) {
// Search field's 'refresh' button has been pressed.
// This is visible if you select any master list item.
// In this case no new search is triggered, we only
// refresh the list binding.
this.onRefresh();
} else {
var andFilter = [];
var sQuery = oEvent.getParameter("query");
if (sQuery && sQuery.length > 0) {
// add filters
var oTableSearchState = [];
oTableSearchState = [new Filter("Supplier", FilterOperator.Contains, sQuery), new Filter("BusArea", FilterOperator.Contains, sQuery), new Filter("CostCenter", FilterOperator.Contains, sQuery),
new Filter("FuncArea", FilterOperator.Contains, sQuery)];
andFilter.push(new Filter(oTableSearchState, false));
}
this._applySearch(andFilter);
}
},
And a filter button that should add aditional filters. Something like this:
onSetFilter : function(oEvent) {
var andFilter = [];
andFilter.push(new Filter("BusArea", FilterOperator.EQ, "5000"));
this._applySearch(andFilter);
},
But of course the "BusArea" part should be dependent on what filters are selected. It could be more than 1 filter. the _applySearch function looks like this:
_applySearch: function(andFilter) {
var oViewModel = this.getModel("worklistView");
this._oTable.getBinding("items").filter(andFilter, true);
// changes the noDataText of the list in case there are no filter results
if (andFilter.length !== 0) {
oViewModel.setProperty("/tableNoDataText",
this.getResourceBundle().getText("worklistNoDataWithSearchText"));
}
}
the problem is that when i add a filter via the filter button, the filters from the searchbar disappear and the other way arround. how can i change my code so that i can add the filters without removing the existing ones?
One solution is to get the Filters from the binding info and push back together with the new Filter using and.
this._oTable.getBindingInfo("items").filters.aFilters;
After our conversation on the chat, I have made this snippet using a global model.
https://jsbin.com/pewavuhonu/edit?html,output
The ComboBox and the Button simulates your Dialog.
The input simulates the SearchField
Both are binded against the global "filtersModel", and both call the _calculateFilters() function when submiting the info
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta charset="utf-8">
<title>MVC with XmlView</title>
<!-- Load UI5, select "blue crystal" theme and the "sap.m" control library -->
<script id='sap-ui-bootstrap'
src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js'
data-sap-ui-theme='sap_bluecrystal'
data-sap-ui-libs='sap.m'
data-sap-ui-xx-bindingSyntax='complex'></script>
<!-- DEFINE RE-USE COMPONENTS - NORMALLY DONE IN SEPARATE FILES -->
<!-- define a new (simple) View type as an XmlView
- using data binding for the Button text
- binding a controller method to the Button's "press" event
- also mixing in some plain HTML
note: typically this would be a standalone file -->
<script id="view1" type="sapui5/xmlview">
<mvc:View xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" controllerName="my.own.controller">
<Panel headerText="Filters">
<VBox>
<HBox>
<Label text="Filter by Customer:" class="sapUiSmallMarginTop sapUiSmallMarginEnd"/>
<ComboBox id="comboBox" selectedKey="{filtersModel>/customerFilter}">
<items>
<core:Item key="VINET" text="VINET" />
<core:Item key="TOMSP" text="TOMSP" />
<core:Item key="HANAR" text="HANAR" />
<core:Item key="VICTE" text="VICTE" />
<core:Item key="SUPRD" text="SUPRD" />
</items>
</ComboBox>
<Button text="Apply this Filter" press="_calculateFilters"></Button>
</HBox>
</VBox>
<VBox>
<HBox>
<Input value="{filtersModel>/shipAddressFilter}" id="input" submit="_calculateFilters" width="500px" placeholder="Filter by ShipAddress: Write and enter for filtering"/>
</HBox>
</VBox>
</Panel>
<Panel>
<List id="list" items="{/Orders}">
<StandardListItem title="{CustomerID}" info="{ShipAddress}"/>
</List>
</Panel>
</mvc:View>
</script>
<script>
// define a new (simple) Controller type
sap.ui.controller("my.own.controller", {
onInit: function(){
var oFiltersModel = new sap.ui.model.json.JSONModel();
sap.ui.getCore().setModel(oFiltersModel, "filtersModel");
},
_calculateFilters: function(){
var oSelect = this.getView().byId("comboBox"),
oListBinding = this.getView().byId("list").getBinding("items"),
oFiltersModel = sap.ui.getCore().getModel("filtersModel"),
oCustomerFilterValue = oFiltersModel.getProperty("/customerFilter"),
oShipAddressValue = oFiltersModel.getProperty("/shipAddressFilter"),
oFilters = [];
if(oCustomerFilterValue){
oFilters.push(new sap.ui.model.Filter("CustomerID", "EQ", oCustomerFilterValue));
}
if(oShipAddressValue){
oFilters.push(new sap.ui.model.Filter("ShipAddress", "Contains", oShipAddressValue));
}
oListBinding.filter(oFilters);
}
});
/*** THIS IS THE "APPLICATION" CODE ***/
// create some dummy JSON data
var data = {
actionName: "Say Hello"
};
// instantiate the View
var myView = sap.ui.xmlview({viewContent:jQuery('#view1').html()}); // accessing the HTML inside the script tag above
// create a Model and assign it to the View
var uri = "https://cors-anywhere.herokuapp.com/services.odata.org/Northwind/Northwind.svc"; // local proxy for cross-domain access
var oModel = new sap.ui.model.odata.ODataModel(uri, {
maxDataServiceVersion: "2.0"
});
myView.setModel(oModel);
// put the View onto the screen
myView.placeAt('content');
</script>
</head>
<body id='content' class='sapUiBody'>
</body>
</html>