Callback "headerContext" not working in Tabulator 5.2 - tabulator

Im using the headerContext-Callback on specific columns for the purpose of hiding/showing a set of additional columns. This worked fine in Tabulator 5.1.8 but somehow lost its functionality since I updated to version 5.2. Instead of calling the specified function it just opens the browsers default right-click-popup.
{title: exampleColumnGroup, columns:[
{title:"exampleAdditionalColumn", field:"xxx", visible:false},
{title:"exampleToggleColumn", field:"yyy", headerContext:headerClickfunc},
],},
Additional info: I chose to use a callback on specific columns instead of tableEvents because I couldn't get tableEvents to work in combination with ColumnGroups.
Any thoughts what im doing wrong or maybe overlooked some deprecated functionality?
edit:
i forgot to show an example of the function that should be called on rightclick:
function headerClickfunc(e, column){
e.preventDefault();
switch(column.getField()) {
case "yyy":
table.toggleColumn("xxx");
}};
Problem is, that this function is never called via headerContext:headerClickfunc since i upgraded to Tabulator 5.2
I can manage to get the function called via:
table.on("headerContext", function(e, column){
headerClickfunc(e, column);
});
but in this case the colum.getField() results in "undefined" which is somehow related to the use of a columngroup (tested it whithout the use of columngroups which works fine).
edit2:
Here is a jsfiddle of the not working Code (headerContext does nothing) with Tabulator 5.2.7
Here is a jsfiddle of the working code (headerContext calls the intended function) with Tabulator 5.1.8
The Code on both jsfiddles is exactly the same. Only difference is the version of tabulator.min.js i used as external ressource (via cdn-link in the ressoruces tab on the left).

The headerContext option, is simply a click listener, if you want to prevent the default browser context menu from opening then you need to call the preventDefault function on the event
{title:"exampleToggleColumn", field:"yyy", headerContext:function(e){
e.preventDefault() ///prevent browser context menu from opening
}},
If you were using Tabulators built in Menu System then you should be using the headerContextMenu option, not the headerClick option.
Also the 5.2 release introduced the concept of popups to allow the built in triggering of custom popup elements. Checkout the Popup Documentation for more info on these

Related

Office web add-in : Office.initialize() function

I am struggling to understand, and don't find an example to exactly match what I am trying to achieve. Which is to have an MS Outlook ribbon bar icon, which when clicked displays a Dialogue Box. I played about with a demo, threw out superfluous functionality and got a Hello World going - but it is JQuery and I want to use to use AngularJs, to reuse much of an existing app.
Firstly, the example manifests all seem to have something like
<DesktopFormFactor>
<FunctionFile resid="functionFile" />
This seems to be for functions which are invoked when the user clicks an icon on the ribbon bar. Would I be correct to assume that I don't need that, if I just use a <script src=> tag to include an such files of functions?
My app will have only a single view, so whereas in the demo all *.js files have something like
// The Office initialize function must be run each time a new page is loaded
Office.initialize = function (reason) {
Would I be correct to assume that I need only have such call one, in the controller of my sole view?
Sorry if this seems pretty basic stuff, but all of the demos & docs seem to be close to what I want, but not exactly. Happy holidays!
Use of FunctionFile
FunctionFile specifies the source code file for operations that an add-in exposes through add-in commands(Ribbon buttons) that execute a JavaScript function instead of displaying UI.
Add-ins can decide either to display some UI in task pane or execute a javascript function in background. For UI-less add-ins, you will have to specify a FunctionFile.
In your case, FunctionFile can be ignored.
Use of Office.initialize
Office Add-ins include the Office.js library and the library expects your start-up code not to call any APIs until the library is fully loaded. There are two ways that your code can ensure that the library is loaded.
Use Office.initialize: An initialize event fires when the Office.js library is fully loaded and ready for user interaction. You can assign a handler to it.
Use Office.onReady: Office.onReady() is an asynchronous method that returns a Promise object while it checks to see if the Office.js library is fully loaded.
Examples:
Office.initialize = function () {
// Office is ready
};
Or
Office.onReady(function(info) {
if (info.host === Office.HostType.Outlook) {
// Based on host, decide what to display.
}
if (info.platform === Office.PlatformType.PC) {
// Make minor UI changes, if required.
}
});
In your case, you can use initialize/onReady once.

Auto-collapse any item in PrimeFaces PanelMenu on page loading

I'm writing a Primefaces 5.1 portlet.
It consists in a unique page containing a panelMenu, and I need that it starts with any panel collapsed everytime a user change page (on page loading).
But, if I open a panel, then change page, it will start showing that panel still opened.
I wasn't able to find any option to achieve this goal (e.g. collapsed=true, ignoreCookie=true or something similar).
The only solution I found was the following Javascript code:
PrimeFaces.widgets.myPanelMenu.collapseRootSubmenu(PrimeFaces.widgets.myPanelMenu.headers);
The problem is that this code will collapse any opened panel (so on page loading user is able to see panel menu collapsing animation) but it seems it doesn't store this state in its cookie/localstorage... the result is that on any page loading user can see this animation.
I'm sure it doesn't save its state, because the only way to "solve" the problem is to manually re-open and re-collapse the panels... then, on following page change, these menus start closed (and there is no animation).
I also tried to use PrimeFaces.widgets.sideMenuPanel.saveState() after collapsing, but with no success.
Do you have any idea about?
Thank you...
I found a solution to the problem.
If you read my discussion with Kukeltje (comments on my question), you will find that latest Primefaces' versions will solve the problem.
Otherwise, if you want to avoid upgrade or modify sources, and you need a quick fix based on Javascript only please read the following part of the answer.
It directly works on the component's state using JavaScript.
First of all you need to have a variable reference to your component:
<p:panelMenu model="#{menuBackingBean.menuModel}" widgetVar="sidePanelMenu" />
Then you should add the following JS code on document ready:
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
// following line is commented because it never should be necessary is not necessary (unless unexpected situation I never verified)
//clearSidePanelMenuPreferences();
// 2. Call the "clear preferences" actions on click on two tpe of links: first level are the panel link (used to open/close the menu) and second level are the destination links
// We need to fork also on the first level links to be sure it works after user clicks there then exit from the page in another way
panelMenu.headers.children("a").click(function(){setTimeout(clearSidePanelMenuPreferences, 500)}); // setTimeout is necessary because this event should be fired after preferences are written
panelMenu.headers.siblings().find("a").click(function(){clearSidePanelMenuPreferences();});
The function called to clear preferences are the following:
function clearSidePanelMenuPreferences() {
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState(); // store this information
}
Hope it helps
Please check this block of code
PF('myPanelMenu').headers.each(
function(){
var header = jQuery(this);
PF('myPanelMenu').collapseRootSubmenu(header);
header.removeClass('ui-state-hover');
}
);
I prefer to do this in order to execute this method only once and keep the menu option selected.
$(document).ready(function() {
if(location.pathname == "/cotizador/" || location.pathname == "/cotizador/faces/login.xhtml"){
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState();
}
});

Primefaces autocomplete enter key behavior

when we type into autoComplete, primefaces automatically highlighted first shown item. so when we press enter key that item will be selected. how can i change the behavior of enter key, so when it pressed, just entered text be submitted in backing bean property.
I know we can hit ESC button then continue but but user don't like it.
I am using primefaces 5.0 & jsf 2.1.11
What helped me to solve the same issue where the answers here and here. Basically, you have to override 2 different behaviours.
First one is the default selection of the first result, that can be achieved adding this to your autocomplete (as stated by the accepted answer in the first link, available in primefaces for versions 5.1.5, 5.0.14 and 5.2):
autoHighlight="false"
The second thing you want to override is the behaviour when Enter is pressed, as you want the form that contains the autocomplete to be submitted. For doing so, just add this code to either the containing form or the autocomplete:
onkeyup="if (event.keyCode == 13) {
document.getElementById('[searchFormId]:[submitButtonId]').click();
return false; }"
Change the ids between square brackets for your own ones and it's done.
PS: I know this is a rather old question but it still applies to the current version of primefaces (6.1 when this question was answered). And I also think it can help to have both changes combined in one answer.
Truth be told, this feels like a bug. Richfaces do that implicitly (submit on enter while suggesting). I haven't found an official fix so I did some research and turns out the simplest way is to override the JS function that resolves key presses. The whole autocomplete js is here. You just need to override the bindKeyEvents function so you declare it likewise:
PrimeFaces.widget.AutoComplete.prototype.bindKeyEvents = function () {
Then add the rest of the code for this specific function from the JS I mentioned before. I've omitted that code so it's more readable. Then you want to find a switch that resolves different keys that have some behavior mapped to them. And under the code:
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
Add something like:
if (highlightedItem.length == 0) {
document.getElementById("<your_form_id>").click();
_self.hide();
} else {
highlightedItem.click();
}
Also, make sure that you got forceSelection and the autohighlight off on the autocomplete component.
The problem in the JS is that even though you haven't selected any item from the suggestions it still triggers the event that tries to click the item... which doesn't even exist.
This is the simplest way as I said... you can also create your own autocomplete implementation and override the behavior there. But that's a lot of work and if you only need this one feature I suggest overriding the JS function.
In order to override the original JS with your custom one you need to make sure yours is loaded after the original one. To do that you can either use h:outputScript or simply just load the javascript like you're used to... but in the body (not the head).
Also there's probably a fancier way than having to specify the form id. But I just wasted too much time searching for a solution that I had to get it done real fast.

xpages dojo validation textbox required

I have dojo validation textbox in my xpage with required property computed (compute dynamically) as below
var syn = getComponent("SynCboxGrp").getValue();
if (syn == "Yes")
{return true;
}else{
return false;
}
Here the component SynCboxGrp is radio button. The text box is required based on the radio button value. But its not working properly. Changing radio button value doesnt change the required behaviour.
Appreciate any help
Update
Thanks stwissel, Per Henrik Lausten and Eric.
I only have this ssjs in required property
<xe:djValidationTextBox id="UBOCAgent" value="#{dsRacDoc.UBOCAgent}" disableClientSideValidation="true">
<xe:this.required><![CDATA[#{javascript:var syn = getComponent("SynCboxGrp").getValue();
if (syn == "Yes")
{
return true;
}else{
return false;
}
}]]></xe:this.required>
</xe:djValidationTextBox>
I also tried this partial refresh code on my radio button onclick event XSP.partialRefreshGet("#{id:UBOCAgent}");
This still doesnt change the behaviour. It works based on the initial radio button value. On the negative side since its a get request it updates the field content from the server. I also tried Eric's suggestion disable client validation but that didnt help.
Eric, I am also trying to go with CSJS wherever possible but in this case the required property only has the SSJS option. So not sure how to try CSJS. Should i try creating my own dojo field instead of using one from entension lib? If so i am not sure how to compute required property for that. If you can help me with some sample code that would be great help.
Thanks for your time.
You're doing a partialRefreshGet, which is updating the Dojo Validation Text Box. But you never post back the updated value from the radio, so the server-side value for the radio button is still the initial value. Consequently, required is still false.
Check the markup when required is true on the Dojo Validation Text Box, but the validation triggers client-side, so there should be an attribute in the markup that you can manipulate via CSJS, if that is your preferred route.
Do you have particular latency issues that you need to work around? Picking up on this and the other question you have about doing a lookup to a database on click of a button, you're hitting a few problems. I don't know how experienced you are in XPages development, but it's not an approach I would recommend without a good understanding of client-side output and server-side component trees. The initial page load of your XPage will also be slower and the size of the HTML passed to the browser will be larger, because of the amount of CSJS passed to the browser.
I would recommend using the in-built partial refresh except for situations where browser to server network is a significant issue, and only then falling back to coding your own partial refresh posting a subset of data. In my experience, it's easier and quicker to develop, easier to debug and more flexible.
For this particular scenario, regardless of whether you code the partial refresh yourself or use inbuilt functionality, one point I'm not certain of is this. That once you set validation on the Dojo Validation Text Box, that validation runs client-side and may impact any attempt to un-set the required property by posting to the server. I haven't tested, so can't be certain.
One of two things:
as previously mentioned, to trigger your SSJS value change, ensure a partial (at least) refresh of the element containing your above code; can be done with a container element. Also, check to see if your field's disableClientSideValidation parameter is set (All Properties view).
convert your SSJS code (which merely returns a binary assessment of a Yes or otherwise, I'm assuming No, value) to CSJS
Of late, after the primary development of my current project, I have started favoring the CSJS approach, for the sake of decreasing server-side call backs; most especially in situations where display/rendering of a component is all I'm trying to achieve. If you go this route, remember that dojo.byId("#{id:myControlsServerNameHere}").value (for a text field, see below for scraping a radio button value) combined with setting the display or visible CSS properties can be very handy. As the docs describe, if you want it to exist on the page but not show (for formatting purposes, also, can preserve default value), go the visibility route, otherwise display property.
The CSJS scrape of radio values that I'm currently using is as follows:
var result=null;
for(i=0; i<document.forms[0].elements.length;i++){
if(document.forms[0].elements[i].name=="#{id:serverNameOfRadioElement}"){
if(document.forms[0].elements[i].checked == true){
result=document.forms[0].elements[i].value;
break;
}
}
}
//then handle your result, either with an if, or switch statement
Hope this helps. If there's more you're having trouble with, post back with more code to give the bigger picture.

using tabbedPanels in a formTable

has anyone got an example of using tabbedPanel in a formTable ?
my form has alot of fields, I'm new to Xpages so just looking for a best practice.
thanks
I have a working example of the opposite - a tabbedPanel, each with a formTable inside with validation, and it works well when there are a lot of fields. Keep in mind that if you use the SSJS validation, whenever you click any tab, the current tab's validation will be triggered.
You can try a dojo tabContainer, with formTables inside, too, where if you switch tabs, no validation will be triggered. You may get js errors, if you set the focus to a field which is in a different tab. I'm not using a dojo tabContainer, because this project is for IE7 and I find it's very slow for this browser.

Resources