SAPUI5 List CustomListItem / Rerender Issue - list

I got a split-app, left Hand side a master list with persons. right-hand side a Detail page with info and RatingIndicator element. Two lists on the detail-page which are bound via associations: /Master/Detail/Rating.
Whenever I use the Rating Indicator, it seems like the page is rerendering, which makes everything slow at the end. I tried both, two-way binding and one-way-binding with manually updating the model. It still rerenders/reloads the page every time I use the Rating indicator.
Any idea someone?
SAPUI5 library is on Version 1.28.31.
Edit: In the meantime I reduced complexity (no lists within lists, thought this might be the issue, but it isnt), and still the issue occurs. Even now when I use the Rating indicator the whole Detail page reloads/rerenders.
What can I do?
Before Clicking the Rating indicator:
Directly after cliking the Rating indicator, right-hand Detail page disappears and reappears withing seconds.
View:
<mvc:View controllerName="split.controller.Detail" xmlns="sap.m"
xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns:footerbar="sap.ushell.ui.footerbar"
xmlns:f="sap.ui.layout.form" xmlns:l="sap.ui.layout">
<Page id="page" navButtonPress="onNavBack" showNavButton="{device>/system/phone}"
title="{i18n>detailTitle}" busy="{detailView>/busy}"
busyIndicatorDelay="{detailView>/delay}" class="sapUiResponsiveContentPadding">
<content>
<List items="{ path: 'WorklistToDocument' }">
<CustomListItem>
<VBox class="sapUiSmallMargin" }">
<Title titleStyle="H3" text="{Title}" }" />
<Text text="{Description}" }" />
</VBox>
<VBox class="sapUiSmallMargin">
<Text text="{Description}" />
<CheckBox selected="{NotApplicable}" select="onNACheckBoxSelect" />
<RatingIndicator value="{RatingValue}" maxValue="{MaxValue}" change="onRatingChanged" />
<Text
text="{ path: 'RatingValue', formatter: '.formatter.ratingText' }" />
</VBox>
</CustomListItem>
</List>
</content>
</Page>
Controller:
onRatingChanged: function(oEvent) {
var oSource = oEvent.getSource();
var oModel = this.getModel();
var sPath = oSource.getBindingContext().sPath;
var sCtxPath = sPath + "/RatingValue";
var sCtxPathNA = sPath + "/NotApplicable";
var iValue = oEvent.getParameter("value");
oModel.setProperty(sCtxPath, iValue);
oModel.setProperty(sCtxPathNA, false);
},

Is this line
var sCtxPath = sPath + "/RatingValue";
not leading to another "change" event trigger?
Additionally, is there a loop in your formatter that could cause a 'hang'?
And what about any events in your master with the same odata path?

Related

How to make components rendered via {{component}} helper independent

I have few instances of component (let's call it <Row />) with given template:
{{component #resultComponentName result=#result}}
I'm calling <Row /> component from <Terminal /> component like this:
{{#each #rows as |row|}}
<Row #result={{row.result}} #confirm={{fn this.confirm}} #resultComponentName={{this.resultComponentName}}/>
{{/each}}
<Terminal /> component has property:
#tracked resultComponentName;
which is handled in action confirm() in <Terminal /> component:
if (cmd.resultComponentName) {
this.resultComponentName = cmd.resultComponentName;
} else {
this.resultComponentName = 'result-component';
}
where cmd is some Ember Model with property:
#tracked resultComponentName = 'other-result';
now I want to change #resultComponentName in only one instance but when I am changing #resultComponentName all of the component <Row /> instances re-render.
How can I prevent that behavior and make every instance independent?
Thanks in advance!
Your problem is that #tracked resultComponentName; exists in your Terminal component, and so only once for the entire list.
Now I'm not sure how your #rows is related to cmd here, because thats the interesting question. If each row is a cmd you could just do this:
<Row #result={{row.result}} #confirm={{fn this.confirm}} #resultComponentName={{row.resultComponentName}}/>
If its different it totally depends how you want to map for which rows you want which resultComponentName and where you want to store that information. You maybe even want to move that login into the Row component itself.

Using SVG Filter Gaussian blur with single page app (Ember)

I'm trying to use d3 to apply a Gaussian blur to an svg circle while on a non-home page of my SPA with Ember.
First I tried using the d3 code
didInsertElement: function() {
var svg = d3.select('#svg');
var filter = svg
.append("filter")
.attr("id", "blur")
.append("feGaussianBlur")
.attr('in', 'SourceAlpha')
.attr("stdDeviation", 3)
.attr('result', 'blur');
svg.append('circle')
.attr('cx', 50)
.attr('cy', 50)
.attr('r', 20)
.style({'fill': 'blue'})
.attr('class', 'cursor')
.attr('filter', 'url(#blur)');
}
but that didn't work. I then tried the example from the mozilla docs,
<svg width="230" height="120"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="blurMe">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
</filter>
<circle cx="60" cy="60" r="50" fill="green" />
<circle cx="170" cy="60" r="50" fill="green"
filter="url(#blurMe)" />
</svg>
Inserted directly into the handlebars template. That didn't work either. Note this has all been on the BridgeBuilderView page.
Then I redid all of that on the index.hbs page that is loaded first when the application starts. When I do that the gaussian blurs work in both cases. I was wondering if anyone has some insight into why this is the case, and how I can get it to work on my non-root page.
Thanks

Get item based on displayname in sitecore

I need to get a specific item based on it's displayname, how do I do that?
For example I want to get this item /sitecore/content/mysite/about
But on the site is translated to multiple languages and could be something like www.site.com/om (in Sitecore it would be /sitecore/content/mysite/om)
There are a couple approaches you can take. The most efficent is to leverage the Content Search API, but the challenge is that Display Name is excluded from the index by default. A simple patch file can fix this:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<contentSearch>
<indexConfigurations>
<defaultLuceneIndexConfiguration>
<exclude>
<__display_name>
<patch:delete />
</__display_name>
</exclude>
</defaultLuceneIndexConfiguration>
</indexConfigurations>
</contentSearch>
</sitecore>
</configuration>
Then your code would be something like:
public Item GetItemByDisplayName(string displayName)
{
var searchIndex = ContentSearchManager.GetIndex("sitecore_master_index"); // sub your index name
using (var context = searchIndex.CreateSearchContext())
{
var searchResultItems =
context.GetQueryable<SearchResultItem>().Where(i => i["Display Name"].Equals(displayName)).FirstOrDefault();
return searchResultItems == null ? null : searchResultItems.GetItem();
}
}
This all is assuming you are on Sitecore 7. If you're on Sitecore 6, your option are limited and are probably not going to perform well if you content tree is large. Nonetheless, your function might look like:
public Item GetItemByDisplayName(string displayName)
{
var query = string.Format("fast:/sitecore/content//*[#__Display Name='{0}']", displayName);
var item = Sitecore.Context.Database.SelectSingleItem(query);
return item;
}
Please note that this will be horribly inefficent since under the covers this is basically walking the content tree.
Often, you wouldn't need to. LinkManager (responsible for generating all your item URLs) has an option to base the URLs on Display Name instead of Item.Name.
var d = LinkManager.GetDefaultUrlOptions();
d.UseDisplayName = true;
This can also be configured in configuration. Find and amend this section in your Web.config (or patch it via include files):
<linkManager defaultProvider="sitecore">
<providers>
<clear />
<add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel"
addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true"
languageEmbedding="never" languageLocation="filePath" lowercaseUrls="true"
shortenUrls="true" useDisplayName="false" />
</providers>
</linkManager>
To truly do exactly what you ask is a quite involved process. If you point DotPeek to Sitecore.Pipelines.HttpRequest.ItemResolver, you can step through the ResolveUsingDisplayName() method. It essentially loops through child items, comparing the URL Part to the "__Display Name" field. You would have to cook up something similar.

Opening GDK Glassware through Mirror API Glassware MenuItem

I have problem integrating GDK Glassware and Mirror API Glassware as described here. I need to open GDK glassware application using Mirroe api Glassware app MenuItem. Can I send data bundle with intent. Does anybody have an idea about that.
Thank you.
I have finally figured out a way to do that
First add your custom scheme to android activity tag in AndroidManifest.xml
<activity
android:name="com.sanath.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="com.sanath.scheme" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/vision_voice_trigger" />
</activity>
Then in Glassware timeline MenuItem add like following
new MenuItem(){
Action = "OPEN_URI",
Payload = "com.sanath.scheme://open/Welcome/2014",
Values = new MenuValue[]
{
new MenuValue()
{
DisplayName = "Open",
State = "DEFAULT"
},
new MenuValue()
{
DisplayName = "Launching",
State = "PENDING"
},
new MenuValue()
{
DisplayName = "Launched",
State = "CONFIRMED"
},
},
},
}
Then inside your Activity OnCreate method you can get data as following
Uri data = getIntent().getData();
List params = data.getPathSegments();
String param0 = params.get(0); // "welcome"
String param1 = params.get(1); //"2014"
String welcomeMsg = param0+" to "+param1;
/*show time line card
* */
Card welcomeCard =new Card(this);
welcomeCard.setText(welcomeMsg);
welcomeCard.setFootnote(param1);
View view =welcomeCard.toView();
setContentView(view);
Hope this will help others
It is not possible to provide data through bundle, but you can use query parameters or hash fragment in your URI to provide the necessary data.
Example:
myscheme://<SOME_PATH>?param1=value1&param2&value2
Then, in your GDK Glassware, simply parse the query parameters and process their values.

use a startdate on a <cfinput type= "datefield"> in ColdFusion

I am using the <cfinput type="datefield"> and I need to limit the dates that can be chosen. I cannot allow a date that can be selected in the past. Any help here?
Thanks!
Well you have two options validating it strictly server side or additionally adding a client side javascript check.
For the serverside, your cfm processing page could use the DateCompare function like so:
<cfif DateCompare(Date1,Date2) EQUAL -1>
<!--- Date 1 < Date 2 --->
<cfelseif DateCompare(Date1,Date2) EQUAL 0>
<!--- Date 1 = Date 2 --->
<cfelseif DateCompare(Date1,Date2) EQUAL 1>
<!--- Date 1 > Date 2 --->
</cfif>
Documentation and sample code is available for this function at:
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_m-r_11.html
Another post suggested using the range functionality, however I was not able to get this to work because the Adobe documentation said it was only supported on type numeric.
Alternatively you can use javascript to check if the date is within range live on the page:
<html>
<head>
<script type="text/javascript">
function withinRange(submittedDate) {
var start = Date.parse("08/10/2009");
var end = Date.parse("09/11/2009");
var userDate = Date.parse(document.getElementById('leaveDate').value);
var previousDate = document.getElementById('calendarWorkaround').value;
if (!isNaN(userDate) && ( previousDate != userDate)) {
document.getElementById('calendarWorkaround').value = userDate;
if (start <= userDate && end >= userDate) {
alert("Your date is correct!");
} else {
alert("Date is incorrect.");
}
}
}
</script>
</head>
<body>
<cfform name="testing" id="vacationForm"action="testprocess">
<cfinput name="date" type="datefield" id="leaveDate">
<input type="hidden" name="workaround" id="calendarWorkaround" value="-1">
</cfform>
<!--- To get around onChange bug with cfinput type datefield --->
<cfajaxproxy bind="javaScript:withinRange({leaveDate})">
</body>
</html>
Now I would use the onChange attribute for cfinput on the datefield, however there is a bug that it does not call the javascript function that seems to be documented on a couple of other pages online. The workaround that I used was the cfajaxproxy call with the bind attribute. If you are using cfeclipse, it will give you an error that the syntax is not correct however it worked fine for me.
The hidden input type is necessary because with the cfajaxproxy tag, everytime you click the calendar icon it will call the javascript function which is not what we want. So I store the last value chosen by the user (or -1 on page load) so that the javascript to check if it is within range is only executed if the value changes. It is a bit of a hack, however the implementation of <cfinput type="datefield"> does not work as documented.
You can also modify this example so that coldfusion dynamical generates the start date and end date so it is not hard coded.
Just remember that whichever way you choose, you should always check the value server side just in case the user has javascript disabled.
Try this:
Three datefields.
One is hidden by the hieght = 0. It is your starting point. I used today plus one so the user can select today in the Date Requested field.
<cfformgroup type="horizontal" height="0">
<cfinput type="datefield" name="firstAvailableDate" value="#dateAdd('d', +1,now())#"
</cfformgroup>
The requested date will be only today or before.
<cfformgroup type="horizontal">
<cfinput type="datefield" name="request_date" id="request_date" mask="mm/dd/yyyy" width="100" label=”Date Requested” onFocus="request_date.disabledRanges=[{rangeStart:firstAvailableDate.selectedDate}];" />
The Due Date can only be after the requested date selected.
<cfinput type="datefield" name="datedue" id="datedue" mask="mm/dd/yyyy" width="100" label=”Due Date” onFocus="datedue.disabledRanges=[{rangeEnd:request_date.selectedDate}];" />
</cfformgroup type="horizontal" >
AFAIK, there is no easy way to prevent the client from picking a day in the past. We have fields like that on a few of our forms that we check against the current date on the server side, though. Just remember to generate the date without the time for comparison, or you end up with [today's date] < now().
At first, I thought <cfcalendar> would help, but seems like the startrage and endrange is for disabled range.
I guess if you Really want to limit the range, use something else like jQuery UI Datepicker
Through experimentation, I was able to customize the supporting javascript files to restrict the selectable dates. However the jQuery option sounds good as well.
I just added 100 years on to the endrange attribute for the cfcalendar component, thinking no one will sit and click through that far to beat your validation :
<cfset startRange = #dateformat(now(), 'dd/mm/yyyy')# >
<cfset endRange = dateadd("yyyy", 100, #Now()#)>
<cfset selectedDate = dateadd("d", -1, #Now()#)>
<cfcalendar name="start_period" mask="dd/mm/yyyy" selecteddate="#selectedDate#" startRange="#startRange#" endrange="#endRange#">
Simon.
You can't make a datefield limit the dates that can be chosen. CFINPUT doesn't have any attribute to define this type of rule. You have to go for Jquery datepicker. If you want to use cfinput, you can work around that.
<script language="JavaScript">
$(function() {
$( "#date" ).datepicker({
changeMonth: true,
changeYear: true,
minDate: new Date(1939, 10 - 1, 25),
maxDate: '-1D'
});
});
</script>
<cfinput name="date" type="text" size="30" id="date" >
You should use server side validation as well, but I believe you can use the "range" attribute of cfinput to limit the valid dates.