Apex buttons in Interactive Reports break when built-in search filter used - oracle-apex-5

In Apex 5.0.2. I have created a copy-to-clipboard function in my interactive report. The user can copy the value of a hidden column by clicking on this button that is set in a column and is repeating in every row (see image below).
The copy column is edited with an HTML Expression which does the following:
<button class="copytoclipboard
t-Button
t-Button--noLabel
t-Button--icon
t-Button--stretch" customid="#COPY#" type="button">
<span class="t-Icon fa fa-copy" aria-hidden="true">
</span>
</button>
My Dynamic Action with the event 'click', jQuery selector .copytoclipboard has 2 true actions. 1 sets the value of a page item (text_field) by getting the customid from that row with:
this.triggeringElement.getAttribute("customid")
The second one then copies this value to the clipboard.
This works fine and when I inspect the button element, I see the correct HTML output, with the correct value. However, as soon as I use the built-in search filter in the Interactive Report, my button breaks and clicking this button does not trigger my dynamic actions anymore, however, inspecting the element still returns the expected HTML output.
Can somebody please clarify why this is happening, and how this could be avoided?
Thank you in advance.

I found the solution. I had to put the Event Scope of the Dynamic Action to Dynamic, which is set to Static by default. Using the built-in page filter does a PPR of the report, thus when static, the event handler is longer bound to the triggering element.
Static (default) - Binds the event handler to the triggering elements
for the lifetime of the current page, but will no longer be bound if
the triggering elements are updated via Partial Page Refresh (PPR).
Dynamic - Binds the event handler to the triggering elements for the
lifetime of the current page, including any triggering elements that
are recreated via Partial Page Refresh (PPR).
Once - Binds the event
handler to the triggering elements for a once only event.

Related

Make button text A/B testable - Sitecore MVC

I have an MVC/angularJS page with a button, the button needs to call code to process the current page and proceed to the next step in the application, but they want the button text to be a/b testable with different variations. I'm new to Sitecore so am struggling to know the best way of doing things.
I thought of having a simple text component/template which just has a single line text property, but if I add that to the page template then it doesn't seem a/b testable because when you click on the test option it asks you to select content. Whereas the content was text they entered as part of the page template.
The only way I know of making a/b testable content so that they can click on the page in page editor and choose to select content / add test variation. I wouldn't add the button to the placeholder as it needs to call specific angular code and always be there, but should I be adding a placeholder where the text is? It seems like overkill to have to define a placeholder there, define a rendering, create a partial view, define placeholder settings to limit it to the simple text component, and then hope they don't try adding multiple items to the placeholder.
I would make a separate template (ie with the text field for your button) to represent your form, then either create the two test variation items as children of your page, or maybe place them in a shared components folder outside of your 'home' node.
EDIT
In order to move your form component into a new A/B testable component you would need to create a new Sublayout in Sitecore, then create a new ascx control for the sublayout. In the Page_Load handler of this control, you would use the following code to retrieve the datasource of the sublayout:
//assume you have a button on your usercontrol called btnSubmit
//assume your template has a single-line text field called 'SubmitButtonText'
Guid dataSourceId;
Sitecore.Data.Items.Item dataSource;
if (Guid.TryParse(sublayout.DataSource, out dataSourceId))
{
dataSource = Sitecore.Context.Database.GetItem(new ID(dataSourceId));
btnSubmit.Text = dataSource["SubmitButtonText"];
}
So I created a new template which just had a single line of text as a field, and added a content item in a shared data node.
In my partial view:
#model Digital.Models.SimpleTextItem
<button ....>
<span class="hidden-xs">#Model.SimpleText_Value<br></span>
</button>
In my main page - I was trying to statically bind it so that they could only change content rather than add new controls to the placeholder, but that only worked if I specified the datasource in this page.
Using a rendering, and in the page layout adding the rendering to the placeholder with a specified data source:
#Html.Sitecore().Placeholder("PremiumQuoteApplyNowPlaceHolder")
Not sure if it was the best approach but it achieves what I need it to.
A/B testing could be applied only to controls(XSLT renderings, sublayouts, action controller renderings, view renderings). If you want to make A/B testing only for button then you should create additional control for it as you did.
Technical details for MVC: A/B testing is applied on mvc.customizeRendering pipeline where rendering arguments are processed. This pipeline operates on renderings level. It means that you are not able to create A/B testing for particular field(button) without your own customization.

Seaside calling a component inside javascript

I have a seaside application with a master-detail page. The master page has a table that consists of a list of tr records. When the user clicks a particular tr element, I want to call a detail component, which'll show the individual record's data.
Since I cannot make a tr element with callback or have it contain an anchor with a callback, I want the tr's onClick property to have some JavaScript which'll call: subcomponent . When I tried this, I got an error saying call: can only be used in callbacks and tasks.
Using ajax is a workaround, however it breaks the back button.
Edit:
More generally, I'd like to know how to set callback like behaviour for various JavaScript events.
Well, you cannot render a component in a tr element, but you could add some anchor or other element in one of its td children.
For my project I did roughly the following: I added an anchor to each row with a special css class, e.g. '.dblclick-action'. This anchor has a normal Seaside callback.
Then I bound a dblclick handler to the tr element that does something like document.location=$(this).find('.dblclick.ction').get(0).href;
I am not close to a Smalltalk image now to give you source code, but I hope you get the idea: you don't use Ajax to click the link in that particular row, but instead have the browser navigate to the callback that is associated to the link in that row. You could say you use the tr.'s dblclick handler to click the link and then let the normal Seaside stuff do its work. No magic there. You can find a little bit more info here.
If you don't want the anchor to be visible you may want to experiment with making the anchor invisible (display: none) or the like.
If you are a bit more experiment friendly, you can also try saving a callback on the server and render its url with callback id as an attribute of the tr element and use the dblclick handler to follow the link from that attribute you extract the value of an attribute in query using attr().
I forgot to answer your initial question: you cannot issue a call: from javascript. But you can use the document.location trick to re/misuse an existing link to a callback on the page using the technique I described in my first answer.

disabling a submit button till validation

Is there a way using dojo/dijit to disable the submit button till all the fields in a form are valid. Kind of like having a dojo > method > onChange inside the form? So the submit button only becomes enabled when all the form elements have meet their criteria?
Are you using a dijit.form.Form widget as your form? If you are, I would suggest connecting to the Form's onValidStateChange event. The docs for this event specifically state your use case:
onValidStateChange
Defined by dijit.form._FormMixin
Stub function to connect to if you want to do something (like disable/enable a submit button) when the valid state changes on the form as a whole. Deprecated. Will be removed in 2.0. Use watch("state", ...) instead.
The best way to see what events are available for a given widget is to look at the API Documentation for the widget you are interested in under the "Event Summary" heading. The dojocampus reference documentation often leaves out examples for references to some of the more obscure features of the widgets.
I would suggest to have a hidden button which will submit the form. When you click visbile button run a javascript function that validates all the input and then clicks on the hidden button to submit the form. Please find the pseudo code below
<form action="register">
<input dojoType="dijit.validation.TextBox"/>
<button onClick="validateall()">submit</button>
<button id="submitForm" type="submit" hidden="true"/>
</form>
function validateAll(){
if(AllOk){
clearErrorMessage();
dojo.byId('submitForm').click();
}else{
showErrorMessage();
}

What's the difference between .select, .show, and .load in jquery-ui tabs?

I see that there are three events fired when a tab is selected and I see the order in which the events are fired but I'm rather confused about which event to use or how these are truly different. If all three are fired, couldn't I just put my code in any of the events?
I must be missing something here. Can someone clarify?
So after messing with this more I'm going to share what I ended up doing in the hopes that it might help someone else.
I had to generate dynamic tabs based on data returned in an Ajax call. It's basically data by date where the tabs are the date and they display whatever data falls within that date.
Generating the tabs from the returned data was easy but I couldn't figure out how to write out the associated data. Finally (and I should have started here), I looked that the generated dom and noticed that a dynamically created tab also creates a div. Maybe that's obvious to some (it wasn't to me) and if it was in the documentation I missed it. Anyway, this code will generate tabs from an array and then append html to the associated div when the tab is clicked. I don't need all the variables but I thought that might make it more readable. Put the function for show before adding the tabs or it wont work!
var _sessionDates = getSessionDates(sessionData.Sessions);
var $tabs = $("#sub-tabs");
$tabs.tabs({
show: function(event, ui) {
var selected = $tabs.tabs('option', 'selected');
var _sessionDates = getSessionDates(sessionData.Sessions);
var grid = buildGrid(_sessionDates[selected]);
$('#' + _sessionDates[selected]).html(grid);
}
});
$(_sessionDates).each(function(i, dayOfShow) {
var d = dateFormat(dayOfShow, "mediumDate");
$tabs.tabs('add', '#' + dayOfShow, d);
});
Finally, I have to "scroll" through my data shown in the tab and I was able to do that with these two lines. The first line gives me the id of the div element corresponding to the selected tab (which is really the important part) and the second line just calls my method and passes in the id of the div less the '#'. My date is also my id. There's a global variable that I've changed outside of this that makes it work. I know that's bad and I'll remove it when I refactor it.
var $el = $($('#sub-tabs a')[$('#sub-tabs').tabs('option', 'selected')]).attr('href');
$($el).html(buildGrid($el.replace('#', '')));
select is triggered when a tab is clicked on, but before the tab has been shown
load is triggered after the contents of a remote tab have been loaded (i.e. a tab whose content is not part of the initial page payload, but that is loaded via an ajax call when the user clicks on the related tab)
show is triggered after a tab has been shown
The jQuery documentation makes this relatively clear, but I had to experiment in order to fully understand the difference between select and show.
This has been made more clear since the original question was asked so now the following is true:
Effectively, the functionality for "show" is now provided by "activate" and "select" is done with "beforeActivate" while "load" is still the same.
activate: (previously show) Triggered after a tab has been activated (after animation completes)
beforeActivate: (previously select) Triggered immediately before a tab is activated.
load: Triggered after a remote tab has been loaded.
Also provided are:
beforeLoad: Triggered when a remote tab is about to be loaded, after the beforeActivate event.
create: Triggered when the tabs are created.

Click DIV doesn't make a “real” click operation in IE

Browser: Internet Explorer 8 with compatibility view turned on (the tested application was written for IE7). I have a div element, which looks like a checkbox in the browser. When I manually click it the checkbox ticks itself. Here is how this looks like: http://img593.imageshack.us/g/divunchecked.jpg/ When clicked manually the div element also changes it's class attribute from "x-grid3-check-col" to "x-grid3-check-col-on". When I run a Watin test and make a Div.Click() operation the element doesn't check itself. Html of that element:
<DIV class=x-grid3-check-col onclick=booleanInterviewColumnRender_OnClick(this);> </DIV>
I have tried to:
- click 2 of the div's parents (it is placed in 2 other divs)
- Div.MouseDown();
Div.MouseUp();
- Div.Firevent("onclick");
- NameValueCollection eventProperties = new NameValueCollection();
eventProperties.Add("button", "0");
Div.FireEvent("onmousedown", eventProperties); //left mouse click
- Div.SetAttributeValue("class", "x-grid3-check-col-on");
Div.Refresh();
without luck.
Any ideas how to workaround this would be great.
The last workaround is to run directly the javascript call.
if you put an id on your div element: elementID
then you call
div.Document.Eval("document.getElementById(\"elementID\").fireEvent(\"onclick\")");
And it will call the onclick call back you put in your attribute (you can first try in the console to be sure that the javascript call your callback).
However, I think that the WatiN mehod .FireEvent on the Element does the same thing, so I don't understand why you need this workaround.