I am using SAP UI5 1.52. My formatter file is a separate file and loaded in the controller. But logging this in the formatter returns view instance rather than control instance.
I have referred this question before and tried using absolute path and changed the way object is returned in formatter. It throws an error saying function not found.
UI5 1.69+
View
<MyControl xmlns:core="sap.ui.core" core:require="{ format: 'demo/model/format' }"
property="{
path: '...',
formatter: 'format'
}"
/><!-- Note: remove the dot (.) in front of the formatter function name -->
Formatter
sap.ui.define([], function() { // location: "demo/model/format.js"
"use strict";
return function(data) {
// this === control instance
};
});
As of UI5 1.69, we can require modules directly in the view definition. Requiring and assigning the formatter directly in the binding info lets us to use this as the corresponding control instance.
The documentation mentions it as well:
From the API reference sap/ui/base/ManagedObject#bindProperty:
When the formatter for a property binding (simple or composite) is called, the managed object will be given as this context
From the topic Property Binding:
The this context of a formatter function is generally set to the
control (or managed object) that owns the binding.
In a control's property, you typically write formatter:'.formatter.functionName'
Just change it to: formatter:'namespace.controllerFolder.controllerName.prototype.formatter.functionName'
And this will now refer to the control instance rather than your controller.
Simple and easy :)
Related
I am using SAP UI5 1.52. My formatter file is a separate file and loaded in the controller. But logging this in the formatter returns view instance rather than control instance.
I have referred this question before and tried using absolute path and changed the way object is returned in formatter. It throws an error saying function not found.
UI5 1.69+
View
<MyControl xmlns:core="sap.ui.core" core:require="{ format: 'demo/model/format' }"
property="{
path: '...',
formatter: 'format'
}"
/><!-- Note: remove the dot (.) in front of the formatter function name -->
Formatter
sap.ui.define([], function() { // location: "demo/model/format.js"
"use strict";
return function(data) {
// this === control instance
};
});
As of UI5 1.69, we can require modules directly in the view definition. Requiring and assigning the formatter directly in the binding info lets us to use this as the corresponding control instance.
The documentation mentions it as well:
From the API reference sap/ui/base/ManagedObject#bindProperty:
When the formatter for a property binding (simple or composite) is called, the managed object will be given as this context
From the topic Property Binding:
The this context of a formatter function is generally set to the
control (or managed object) that owns the binding.
In a control's property, you typically write formatter:'.formatter.functionName'
Just change it to: formatter:'namespace.controllerFolder.controllerName.prototype.formatter.functionName'
And this will now refer to the control instance rather than your controller.
Simple and easy :)
I have the following XMLView:
<mvc:View
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:data="sap.chart.data"
xmlns:viz="sap.viz.ui5.controls"
xmlns:con="sap.suite.ui.commons"
controllerName="MY_NAMESPACE.controller.ChartView"
xmlns:html="http://www.w3.org/1999/xhtml"
>
<!-- Panel here -->
</mvc:View>
Now, in my controller, I want to dynamically add a sap.m.Panel to the view.
In my onInit function, I pass the object of the current view to the method that creates the Panel and adds it to the view.
onInit: function() {
var sUrl = "/sap/opu/odata/sap/MY_ODATA_SERVICE/",
oModel = new ODataModel(sUrl), // v2
oCurrentView = this.getView();
this.getView().setModel(oModel);
this._createPanel(oCurrentView);
this._createChartContainer();
this._initializeCharts();
this._showCharts();
},
_createPanel: function(currentView) {
var sId = this._globals.panelId;
var oViewPanel = new Panel(sId, {
width: "auto"
}).addStyleClass("sapUiSmallMarginBeginEnd");
this._globals.panelState = oViewPanel;
currentView.addContent(oViewPanel);
return currentView;
},
However, the Panel is never rendered:
But when I call the getContent function of the view, the panel is listed as an entry.
Clarification:
Creating a sap.m.Panel in the XMLView isn't a problem. Placing this bit of XML into the XMLView works.
<Panel id="chartPanel"
class="sapUiSmallMarginBeginEnd"
width="auto"
></Panel>
But, I need to create and append the sap.m.Panel object to the XMLView at runtime (in the controller), not in the XMLView.
Now, the problem:
With above posted controller code, the panel objects gets created. In fact, it even gets registered as a content aggregation of the XMLView, but it simply doesn't get rendered (see picture above).
Any suggestion on why and how this behaviour occurs are greatly appreciated.
Issue
this.getView().addContent(/*...*/) doesn't work.
Why
Currently, XMLView won't allow manipulating its content via APIs as the documentation warns:
Be aware that modifications of the content aggregation of this control are not supported due to technical reasons. This includes calls to all content modifying methods like addContent etc., but also the implicit removal of controls contained by the content aggregation. For example the destruction of a Control via the destroy method. All functions can be called but may not work properly or lead to unexpected side effects.
This is, at the time of writing (v1.64), still the case.
PS: The above limit applies only to XMLView. Other view types, such as JSView*, are not affected.
* sap.ui.core.mvc.JSView and sap.ui.jsview are deprecated. Use Typed Views instead (Applicable since v1.90).
try to put the Panel inside the XML view and give it a property visible="false".
<Panel id="panelId" visible="false">
</Panel>
In your function you could do something like this:
_createPanel: function(){
var oPanel = this.getView().byId("panelId");
oPanel.setVisible(true);
// Other Methods for Panel
}
With the oPanel instance you can execute all methods listed in the API:
https://sapui5.hana.ondemand.com/#/api/sap.m.Panel
Hope this helps :-)
Best regards
I am trying to convert a string value to Boolean while binding it from a JSONModel. Ideally the value in my model is "true"/"false" and I want to bind it to the visible property of an item. The model is defined to be TwoWay binding but I guess that does not matter in this case
I have declared "complex binding" in the index.html.
data-sap-ui-xx-bindingSyntax="complex"
Then I create my XML view and bind the property from the model as below:
<P13nColumnsItem>
columnKey="{tableVariantAFModel>Fieldname}"
visible="{path:'tableVariantAFModel>Visible', type: 'sap.ui.model.type.Boolean', mode: 'sap.ui.model.BindingMode.TwoWay'}"
index="{tableVariantAFModel>DisplayOrder}">
<P13nColumnsItem>
When I run my app,it throws the below error:
Is there any step I am missing?
Also, I need to add this app to the Fiori Launchpad, so I need to define the complex binding in manifest.json file rather than in index.html . Where can I define it in the manifest file.
For simple use cases like this you can use an expression binding instead of implementing additional logic somewhere.
<P13nColumnsItem>
columnKey="{tableVariantAFModel>Fieldname}"
visible="{= ${tableVariantAFModel>Visible} === 'true'}"
index="{tableVariantAFModel>DisplayOrder}">
<P13nColumnsItem>
i would advise to use a formatter. See here. In the formatter you could write:
visible="{path:'tableVariantAFModel>Visible', formatter: '.formatter.stringToBoolean'}"
in the formatter you could create the function like:
stringToBoolean: function(_stringBoolean){
(_stringBoolean === "true") ? return true : return false;
}
You have to make sure that you instantiate the formatter in your controller, or optionally you could choose a function in your controller itself.
I have a section of my view (html) that is generated programmatically by a viewmodel/class. This uses the Aurelia DOM (Aurelia Docs - pal :: Dom) functionality to generate and add the raw HTML elements to the view.
However, I am unable to get events within the generated html to call back to the viewmodel. An example:
let deleteButton = this.dom.createElement("button");
deleteButton.setAttribute("onclick", "cancelCreditNote(`${ row.creditNoteId }`)");
A click on the generated button won't call back to the viewmodel, which does have a cancelCreditNote function. Various other things like deleteButton.setAttribute("click.delegate", "cancelCreditNote('${ row.creditNoteId }')"); do not work either.
Does anyone know how to access a viewmodel class from essentiall 'raw' html in aurelia?
Unfortunately in this instance I cannot use the standard aurelia templating to generate the HTML.
The DOM property on PAL is just an abstraction for the browser's DOM object, create element is likely just calling document.createElement which doesn't afford any Aurelia binding to the created element.
You could try using aurelia.enhance(context, element) which takes an existing DOM element and runs it through the templating engine.
With this method you can also pass a binding context to apply to the element.
In my HTML I use this:
<div id="collapsesidebar" click.delegate="toggleSidebar()">
In my view-model I have this method:
toggleSidebar(){
alert('hi');
}
You could also do this from your view-model with JQuery like this:
attached() {
$('main').on('click', ()=> alert('hi'));
}
The last option is ONLY available áfter the attached() method is triggered: before that the binding needs to do its job and only after that the elements are located inside of the dom.
In other words: this will not work:
activate(){
$('main').on('click', ()=> alert('hi'));
}
because the constructor and the activate method both get fired before the attached method.
I'm trying to assign a class to a row in my sap.m.Table dynamically using my view model SearchResults.
Unfortunately it's ignoring my class properties (see below).
How do I do this in my XML view ?
<ColumnListItem class="{SearchResults>typeClass}">
To apply CSS properties to row, you will also need take predefined CSS class of table .sapMListTbl along with your custom CSS class like I have done here.
I would suggest you to use formatter to apply these classes along with class from your model.
Unfortunately the class attribute is not bindable since it is not a property.
As a workaround you could do sth. like this:
<ColumnListItem visible="{
path: 'SearchResults>typeClass',
formatter: 'my.formatter.formatClass'
}" />
my.formatter.formatClass = function(typeClass) {
// in a static formatter this refers to the control, here your ColumnListItem
this.addStyleClass(typeClass);
// just always return true for the visible property
return true;
}
Note: The formatter can't be a member of your controller since then you won't be able to refer to the control (this will be the controller itself). Hence the formatter needs to be a static function.
Solution found!!!!
http://scn.sap.com/community/developer-center/front-end/blog/2016/05/17/coloring-table-rows-conditionally-in-sap-ui5-xml-views-based-on-odata-service
Hopefully this help anyone who's had the same problem...