Using play's wsclient to make a call to fetch a RSS feed and return a collection - scala

I am making a request to a URL to grab the RSS xml data:
val items: List[Item] = ws.url("http://www.example.com/rss.xml").get().map { response =>
}
Now I want to loop through all the nodes and create a collection of Items.
My Item case class is:
case class Item(title: String, link: String, description: String, guid: String)
The format of the XML is like below:
<rss ...>
<channel>
<title>
</title>
<link />
<description />
<item>
<title>hello</title>
<description> ... </description>
<guid> ... </guid>
</item>
<item>
...
</item>
</channel>
</rss>
I'm not sure what to do with the response in the call to .map to iterate through the items and how to return a collection of Item case classes.

You should basically use the xml api to extract the relevant NodeSeq, which works like any collection.
Then you map each node to extract the relevant subtag content and create an object out of it.
val itemNodes = response.xml \\ "item" //will get all item nodes as a NodeSeq
val item = itemNodes.map(node =>
Item(
(node \ "title").text,
"", // there's no link tag in the item
(node \ "description").text,
(node \ "guid").text
)
)
If not exactly this, something similar

Related

UI5 i18n support for the static model data

I'm exploring the sap.f.ProductSwitch controller on a sample project sap.f.sample.ShellBarProductSwitch.
Everything is clear besides one thing, what should be the approach if I want to provide an i18n support for a list of products (model/data.json)?
E.g. additionally to the hardcoded English list of products:
{
"items": [
{
"src": "sap-icon://home",
"title": "Home"
}
]
}
I want to provide a Frech one:
{
"items": [
{
"src": "sap-icon://home",
"title": "Maison"
}
]
}
With a basic dialogues I can rely on the built-in i18n UI5-engine, but here I don't know how to enable i18n in an XML-template:
<f:ProductSwitchItem
src = "{src}"
title = "{title}" />
A home-made solution.
XML-template:
<f:ProductSwitchItem
src = "{src}"
title = "{titleI18NKey}" />
Controller:
const resourceBundle = this.getView().getModel("i18n").getResourceBundle();
const productSwitcherModelData = this.getView().getModel("productSwitcher")?.getData();
productSwitcherModelData.items.forEach((item) => {
item.titleI18NKey = resourceBundle.getText(item.titleI18NKey);
});
this.productSwitcher.setModel(this.getView().getModel("productSwitcher"));
In product switcher model instead of real text I store a key-value pair:
titleI18NKey: i18n_dialogue_key
which is later replaced by the end-text from the i18n-model and set to the productSwitcher model.
P.S. Please, let me know, if there is more elegant implementation based on UI5 functionality.
If you like the data binding approach better, you can use a formatter with the title property binding to retrieve the text from the resource model.
The key to the text of the resource bundle must be defined in your data.json for every item:
The JSON data model:
{
"items": [
{
"src": "sap-icon://home",
"titleI18NKey": "myResourceBundleKeyToThisItem"
}
]
}
The XML-template:
<ProductSwitch
change = "onClickProductSwitcherItem"
items = "{
path: '/items'
}">
<items>
<ProductSwitchItem
src = "{src}"
title = "{
path: 'titleI18NKey',
formatter: '.getText'
}" />
</items>
</ProductSwitch>
The formatter getText needs to be defined in your controller:
getText(i18nKey) {
const dialogue = this.getView().getModel("i18n").getProperty(i18nKey);
return dialogue;
}
If you only have static values I would rather not use list binding but create the product switch items individually:
<ProductSwitch change="fnChange" >
<items>
<ProductSwitchItem src="sap-icon://retail-store" title="{i18n>Title_1}" />
<ProductSwitchItem src="sap-icon://family-care" title="{i18n>Title_2}" />
</items>
</ProductSwitch >
In doing so you can use the resource model for the titles as usual and don't need any further code.

SAPUI 5 - Aggregated control with two data models

I have a generic tile control that the tile get created base on number of entity available (e.g.: SCARRSet), which is normal. Then in the nested Tile content i need to show the airline logo where the image path is stored in a JSON file. My idea is to use the key in SCARRSet/Carrid to lookup the JSON file to find the image path. So the right image will be displayed for the airline.
Previously i put the image path in Url field which was fine, but that field was meant for something else. Now i want to do it properly.
<l:HorizontalLayout id="hLayout1" allowWrapping="true" content="{flight>/SCARRSet}">
<GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout"
header="{flight>Carrname}"
subheader="{flight>Carrid}"
press="onTilePressed"
backgroundImage="">
<TileContent unit="{flight>Currcode}" footer="">
<ImageContent src="{flight>Url}" />
</TileContent>
</GenericTile>
</l:HorizontalLayout>
The JSON file looks like following. Is there a way to iterate through each tile to lookup Key = SCARRSet/Carrid then populate imageContent src=(e.g.:"/image/AA.gif")?
{
"icon": [
{
"Key" : "AA",
"Path" : "/image/AA.gif"
},
...
]
}
I would use a formatter function to do the lookup:
src="{formatter: '.formatter.getIconUrl', path: 'flight>Carrid'}"
In the formatter getIconUrl you get the Carrid as input parameter.
For performance reasons I would also suggest to reformat the JSON once to have a hash access to the url: jsonData[carrid] returns the url.

SAPUI5 XML View Binding with parameters from same model

I have the following Problem:
I want to develop a shopping cart and have problems with the counter of the product card and I have problems to show the data in the summary view.
For this project I use XML views and I've already readed a lot about binding. When I want to bind a static path I have no problems. The data comes from a JSON model named "cartData".
Example (from the goToCart Button)
...
text="{cartData>/currentUser}";
...
Everything shows correctly (in the example), but for my project I need to bind a main binding (for counter of the cart) and this path need a parameter for the user. Which is saved at the path like in the example.
I've already tried a lot of combinations to accomplish this bug, but now I have no more ideas :-(
A example of my tried combinations:
text="{ ${cartData>/cartOfUser/} + {cartData>/currentUser} + '/roles/counter'}"
EDIT:
Some dummy parts of my code:
My Button (doen't work yet how I need...):
<m:Button
id="details.Btn.ShowCart"
text="{ parts: [
{path: 'cartProducts>/cartEntries/'},
{path: 'cartProducts>/currentChoice/'},
{path: '/addedRoles/counter'}
]}"
type="Emphasized"
icon="sap-icon://cart-3"
iconFirst="true"
width="auto"
enabled="true"
visible="true"
iconDensityAware="false"
press="showCart"/>
How my JSON Model in LocalStorage look like:
{
"cartEntries": {
"counter": 2,
"UserId12": {
"UserId": "UserId12",
"Email": "Email12",
"dateCreated": "2017-07-14T13:18:13.632Z",
"dateUpdated": "2017-07-14T13:18:13.632Z",
"addedRoles": {
"counter": 0
},
"existingRoles": {
"counter": 0
}
},
"UserId14": {
"UserId": "UserId14",
"Email": "Email14",
"dateCreated": "2017-07-14T13:18:30.415Z",
"dateUpdated": "2017-07-14T13:18:30.415Z",
"addedRoles": {
"counter": 0
},
"existingRoles": {
"counter": 0
}
}
},
"currentChoice": "UserId14"
}
My JSON Data with comment:
I need to grab the value from "currentChoice", to search with this information in cartEntries for the right counter
How the Button look now:
It show the data not in the correct way. Please ignore the zero at first...
The goal is to take the value of "currentChoice" and use it as a 'parameter' to call the information for the right user..
What I also tried:
text="{= ${= 'cartProducts>/cartEntries/' + ${cartProducts>/currentChoice/} + '/addedRoles/counter' } }"
What works, but I need it more "dynamic" is:
text="{cartProducts>/cartEntries/UserId14/addedRoles/counter}"
I hope you guy's now know what I mean... :-/
Best regards
The Solution
How I solve the problem:
Add a formatter to the button:
/',
formatter: '.formatter._getCartInt'
}"
type="Emphasized"
icon="sap-icon://cart-3"
iconFirst="true"
width="auto"
enabled="true"
visible="true"
iconDensityAware="false"
press="showCart"/>
Implement the formatter in my formatter.js file:
_getCartInt: function (sP1) {
var sCurrent = sP1.currentChoice;
var sFinalString = "cartProducts>/cartEntries/" + sCurrent + "/addedRoles/counter";
this.getView().byId("btn.ShowCart").bindProperty("text",{path: sFinalString, type: new sap.ui.model.type.Integer()}); }
Try to use the following approach:
in i18n file:
cartInfoTitle=User: {0} has: {1} items in the cart
in XML view:
<Text text="{
parts: [
{path: 'i18n>cartInfoTitle'},
{path: 'modelName>/property1'},
{path: 'modelName>/property2'}
],
formatter: 'jQuery.sap.formatMessage'
}" />
So you declare the i18n entry and then use the predefined formatter to replace the placeholders with the values from the "parts" array (Documentation article).
Ok so to answer : you cannot use expression in a binding (same applies for classes). So to have the output you want you will indeed need a formatter + include the needed top level elements of your JSON model in the binding parts (so that it updates properly).
XML (I assume your model is called 'cartData')
<Text text="{
parts: [
'cartData>/cartEntries',
'cartData>/currentChoice'
],
formatter: '.myFormatter'
}" />
JS Controller
controller.prototype.myFormatter = function (cartEntries, currentChoice) {
if (cartEntries && cartEntries[currentChoice]) {
return cartEntries[currentChoice].addedRoles.counter;
}
}
[code not tested]

Add Custom Data Type/Field in Jaydata

How can I add a custom data type in Jaydata wherein I can just add anything on it and have it output in http://localh.ost/blahblah/$metadata ?
Like
$data.Entity.extend("Office", {
Id: { type: "id", key: true, computed: true },
OfficeName: { type: "string", maxLength:50, alternativeName:"office_name" }
});
Like I want to add the alternativeName and have it output in the browser so that when I type the http://localh.ost/blahblah/$metadata, I can see it as one of the fields.
Like:
//other XML output here
<Property MaxLength="50" Name="OffName" Type="Edm.String" alternativeName="office_name"/>
//other XML output here
Right now, I can only see this:
<Property MaxLength="50" Name="OffName" Type="Edm.String" />
So how can I achieve this?
Start the custom attribute name with $ sign

Unexpected Decoding of = in Controller

From the front-end, I'm performing a jQuery POST with the following data:
[{name: "Kevin", age: 100, favoriteOperator:"="}]
This POST hits /sample URL.
In my controller, I read in the POST's body using:
def submit = Action { implicit request =>
val maybeRequestAsFormUrlEncoded: Option[Map[String, Seq[String]]] =
request.body.asFormUrlEncoded
Printing out map shows:
Map([{"name" : "Kevin", "age" : 100, "favoriteOperator" :" -> List("}])
Why is my favoriteOperator showing up as " -> List(" rather than "="?
Quite sure asFormUrlEncoded expects input like:
queryString=abc,def
anotherQueryString=blabla
which then is transformed into your map as:
Map("queryString" -> List("abc", "def"), "anotherQueryString" -> List("blabla"))
(I'm actually not so sure if abc,def and blabla really are deserialized into a list, that idea just comes because you get a list in your sample). Anyways, important is that asFormUrlEncoded expects key-value pairs separated by a = sign, that's why your string is taken apart like that. See also http://en.wikipedia.org/wiki/Url_encoding.
You might want to look into Json deserializers in play, as your request has a Json format:
http://www.playframework.com/documentation/2.2.x/ScalaJson