I want to achieve mergeDuplicates in Multi Select table, just like guideline said:
But in my DEMO, there is still border-top in my checkbox, what should I do? I don't want to overwrite UI5 CSS.
<Table
id="table"
mode="MultiSelect"
growingScrollToLoad="true">
<columns>
<Column mergeDuplicates="true"><Text text="column1"/></Column>
<Column><Text text="column2"/></Column>
<Column><Text text="column3"/></Column>
</columns>
</Table>
IMHO, the concept of mergeDuplicates is bound to the cell content and therefore doesn't extend to the selector cell. But obviously, the guideline and the control concept then don't fully match.
I would suggest to slightly modify Ash Kander's proposal. As the table might render individual ColumnListItems individually and at different points in time, attaching to the onAfterRendering of the table won't help.
Instead, attach to the onAfterRendering of the items by using a delegate. To make this fully work, you have to do this early enough on the template for the items, before data binding starts cloning that template.
In your DEMO, this is easily possible in onInit before you create and attach the model (I gave the template the id "cli"):
this.byId("cli").addEventDelegate({
onAfterRendering: function(e) {
var $dom = e.srcControl.$();
if ( $dom.has(".sapMListTblCellDup") ) {
$dom.find("td.sapMListTblSelCol").css("border-topcolor",
"transparent");
}
}
});
See http://plnkr.co/edit/eNb83KvF1BpAp5eGSpOS?p=preview .
Seems like a bug in the table renderer. No way you can address it NOW without touching the CSS.
This will work, but this overrides the css (in your controller):
onAfterRendering: function() {
$('.sapMListTblSelCol').each(function(index, col) {
if ($(col).next().hasClass('sapMListTblCellDup')) {
$(col).css('border-top-color', 'transparent')
}
});
},
Related
situation:
2 diferent tables, 1 view;
want to achieve:
I've got to change the table when I change the selectedKey in a select.
I already tried to create fragments with each table and call the one I want when I change the select.
fragment1 - table 1
fragment2 - table 2
select - oEvent (onChangeSelect) - getSelectedKey - if(key === 1) - call fragment1, if(key === 2) - call fragment2, but it gives me an error.
I don't know if this is correct and I'm not finding any infos related online.
If someone can show some links or give me just an idea on how can I do this, it would be perfect.
You could use the concept of binding to achieve this without coding. assume you have something like that in your view:
<Select><!-- ... --></Select>
<core:Fragment ... /><!-- table 1 -->
<core:Fragment ... /><!-- table 2 -->
First, add a model to your app, which will contain the information about the status of the app (which of the fragments is visible currently). Easiest way is to start with an empty JSON model. If you are familiar with manifest.json config, add it there. if not, you could add this in your Components init method:
this.setModel(new JSONModel(), "config");
This way, the new empty model is available under the name "config" in all the views of the app.
Now, we will add a visibility flag, which will control the visibility of your fragments (tables), and can be changed by the select:
<Select selectedKey="{config>/selectedFragmentKey}">
<core:Item key="" text="Please choose one" />
<core:Item key="showFragment1" text="Show Fragment 1" />
<core:Item key="showFragment2" text="Show Fragment 2" />
</Select>
This new version will store the key of the selected item in the config model in the path /selectedFragment. Add visibility flag to fragments (tables):
<!-- table 1 is only visible if "Show Fragment 1" was selected -->
<Table visible="{= ${config>/selectedFragmentKey} === 'showFragment1'}" .../>
<!-- table 2 is only visible if "Show Fragment 2" was selected -->
<Table visible="{= ${config>/selectedFragmentKey} === 'showFragment2'}" .../>
and you're done.
Main lesson here: learn to use bindings.
If I understood the question correctly, you have a selection control (which has 2 entries), and a table in the view. Based on the selection item, you want to display ONE of the tables at any given point of time. I am also assuming here, that the tables are purely used in the current view only & not really a "re-useable" thing - which gets used in different places of the app (which then renders the use of fragments an overkill).
I am assuming, both tables are bound (although to different data sets).
In that case, consider using the "visible" property of the appropriate table to "false".
Remember - all UI components, including tables inherit from sap.ui.core.Control - which has the "visible" property.
In API reference for table : https://sapui5.hana.ondemand.com/#/api/sap.ui.table.Table%23methods/Summary
If you scroll down to "Borrowed from:" section, you will see the "setVisible" and "getVisibe" methods.
So, in the event fired during selection change, you can grab the table control & set the visibility using the aforementioned methods.
Alternatively, you can also set an expression binding directly on the table control in XML, which evaluates to "true" or "false" (perhaps using a formatter).
Let me know if you need further info on this.
Best Regards,
Gopal Nair.
I want to fetch data from News API (https://newsapi.org/) in my SAPUI5 application like done here (https://www.nathanhand.co.uk/blog/post/creating-a-news-app-using-ui5), but without express and Node.js. The fetching process itself works and I got the data from the API in JSON. The Problem seems to be the lifecycle of UI5 especially the asynchronous loading of the API data. I cannot display the data at the moment in my view, since it arrives to late it seems to be initialized with the view.
I have tried to work with the "attachRequestCompleted" event handler, to make sure the data is there and further actions are only taken when the data has arrived. But that did not solve the problem, the data gets properly bound to the view, but too late it seems.
return Controller.extend("newsapitest.newsapitest.controller.View1", {
onInit: function () {
var thisContext = this;
var articleModel = new JSONModel("https://newsapi.org/v2/top-headlines?country=DE&category=business&apiKey=*********");
articleModel.attachRequestCompleted(function(oEvt) {
var model = oEvt.getSource();
thisContext.getView().setModel(model, "articles");
});
}
});
<content>
<GenericTile backgroundImage="{articles>/1/urlToImage}"
frameType="TwoByOne" press="onArticlePress">
<TileContent footer="{articles>/1/publishedAt}">
<NewsContent contentText="{articles>/1/title}"
subheader="{articles>/1/description}" />
</TileContent>
</GenericTile>
</content>
So I was expecting that the tiles in my view will display the information for each article that is stored in the model. But at the moment there is just an empty tile and no data is shown there.
Solution
I did a mistake with the binding of the model to my control. That was one mistake. The other thing I changed is how the data gets loaded into my model.
return Controller.extend("newsapitest.newsapitest.controller.View1", {
onInit: function () {
var articleModel = new JSONModel();
articleModel.loadData("https://newsapi.org/v2/top-headlines?country=DE&category=business&apiKey=37a02aae93684d58810e0b996954f534");
this.getView().setModel(articleModel);
},
});
<content>
<GenericTile
backgroundImage="{/articles/0/urlToImage}"
frameType="TwoByOne" press="onArticlePress">
<TileContent footer="{/articles/0/publishedAt}">
<NewsContent
contentText="{/articles/0/title}"
subheader="{/articles/0/description}" />
</TileContent>
</GenericTile>
</content>
Did you check that your binding paths are correct? Anyway, the way you did the bindings will only create one tile with the information stored on the second position (position 1) of your array of articles.
If you want to create create a number of tiles dynamically depending on the number of positions of an array, I think you can't use the "Generic Tile" component, instead you could use the "Tile Container" as follows (It's a deprecated component but I think there's no other way to do so, at least on the view):
<TileContainer
tiles="{articles>/}">
<StandardTile
title="{articles>title}"
info="{articles>publishedAt}"
infoState="{articles>description}" />
</TileContainer>
It would be nice if someone else knows a way to do that without using a deprecated component :).
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'm trying to add data attributes to elements in a XML View as below:
<core:FragmentDefinition
xmlns="sap.m"
<VBox data-help-id="Some.String.Here">
...
</VBox>
</core:FragmentDefinition>
but couldn't find how to do it, unless I assign them via Controller.
Tried using CustomData namespace, but it only adds data, without adding the HTML attribute to the DOM element.
Any idea?
Thanks!
actually you can do something very close and associate data to your xmlView. This is available for xml views and more. Check this url for more details: Custom Data - Attaching Data Objects to Controls
What you would need to do is add a custom namespace to your xmlView:
xmlns:dataHelp="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"
...
<core:FragmentDefinition
xmlns="sap.m"
<VBox dataHelp:id="Some.String.Here" id="myBox"
...
</VBox>
</core:FragmentDefinition>
you are then able to set and consume this attribute in your binding and javascript/controller/event handler:
sap.ui.getCore().byId("myBox").data("id") // = Some.String.Here
You can only influence the attributes written to the DOM using the standard control properties. If the standard properties don't provide you with a way to set the right HTML attibutes, and you still want to get your own HTML attributes in the DOM, you'll need to subclass the control and write your own renderer. When you write your own renderer, you have full control over what's written to the DOM.
You can find more information on writing custom controls in Step 34 of the SAPUI5 Walkthrough.
I'm trying to make a simple extension of the table element. Where you can click a td, then it becomes editable, and when you edit the data it gets automatically persisted via a REST service.
Here's what I got so far
As you can see, you can click the td's and edit them, but the data does not get persisted to the other side (which is firebase in this case). That's because the data in the td's aren't bound anymore to the data-property from which they came. Can somebody tell me how I can bind them to that property again? Or any other way I can persist the data to the correct row and key?
As far as I know contenteditable change events are not supported by polymer.
You could use the onkeys to update the model manually.
In a on-* handler, you can access the named model instance using: e.target.templateInstance.model.:
<polymer-element name="x-foo">
<template>
<template repeat="{{user in users}}">
<div on-click="{{clickHandler}}">{{user.name}}</div>
</template>
</template>
<script>
Polymer('x-foo', {
clickHandler: function(e, detail, sender) {
console.log(sender.templateInstance.model.user.name);
}
});
</script>
</polymer-element>
Sevesta told me that it could only be done manually, so I gave every td extra data-attributes so I could identify them and then at the stopEditing() function I update the models manually.
See here.