using jscolor.js on dynamic input - jscolor

i'm using color picker from http://jscolor.com/
i'm trying to attach it to some dynamic inputs, but to no avail. dynamic inputs in terms of, on page load the input doesn't exist, only after the user click on something the input will become available. for example, I have a rows of data, and each row has different background color. this row of data are loaded using ajax. at the end of each row, there's an edit button. by clicking the edit button, it will display an input text box for the clicked row. I want to call the jscolor picker when the user clicks on the input text box. how can I do this?
thanks

For some reason jscolor.init() did not work for me, and looking at the code I called
jscolor.installByClassName("jscolor");
function.
So...
$(document).ready(function() {
jscolor.installByClassName("jscolor");
});
Hope it helps

I just had this problem too but luckily it's easy to fix. You need to (re)init jscolor after you have dynamically created your inputs:
jscolor.init()

This helped me
<script>
$(document).on('click', '#myPickerId', function () {
var obj = $(this)[0];
if (!obj.hasPicker) {
var picker = new jscolor.color(obj, {}); //
obj.hasPicker = true;
picker.showPicker();
}
});
</script>
In my case, the picker control was dynamic because it is inside Knockout.js 'with' statement which hides and recreates the picker when it needs.

Got the same problem upon adding input fields dynamically
Managed to make it work by calling
jscolor.install();
PS: jscolor v2.4.5

As of 2020, the original problem should be solvable by dynamically creating an input element, and then calling new jscolor(input). Using JQuery (you could use vanilla JS as well):
var color_input = $('<input class="jscolor" spellcheck="false">');
new jscolor(color_input[0]);
This will make the popup picker appear on click, and everything appears to work just fine. However, you cannot manipulate it programmatically. To set the color using the objects above, you would normally use a method like: color_input[0].jscolor.fromString("#B7B7B7"). But that will fail for dynamically created objects, as color_input[0].jscolor is undefined. I believe this is a bug in Jscolor (and probably very easily solvable), as the missing object is actually available with color_input[0]._jscLinkedInstance. So you can just set the object yourself on instantiation with:
var color_input = $('<input class="jscolor" spellcheck="false">');
color_input[0].jscolor = new jscolor(color_input[0]);
And then everything looks to be working as expected. Hopefully this helps someone else that comes across this answer page as I did.

Related

How can you change current tab programmatically with Acumatica?

When I launch a custom Framework page, i would to be able to activate one of the tabs programmatically depending on certain conditions. Am i stuck using javaScript or is there another way?
There are a few posts already on this question with answers:
This is the best answer: How to conditionally hide PXTabItem inside an Acumatica screen?
Also, searching hide tab you will find what you need.
For information, this can be achieved statically with PXTab control SelectedIndex property:
You can do this using a Javascript function and attaching it to the corresponding client event on your Acumatica form.
Here, I wanted the tab to change based on the index of the active cell in a grid. So I set the aftercellchange and cellclick grid-events(client events) to my gridclick Javascript function. Finally, added this script to my aspx page:
<script type="text/javascript">
function gridClick()
{
var index = px_alls["grid"].activeCell.getIndex();
if(index<=2) px_alls["tab"].items[0].select();
if(index>=3 && index<=5) px_alls["tab"].items[1].select();
if(index>=6) px_alls["tab"].items[2].select();
}
</script>

EditBox fieldInput.getValue() and spaces

Here is the issue. I have an editBox which I am trying to retrieve the value from by server side JavaScript via the onClick event of a button named Add. It works until space is in the value, then it retrieves nothing. Code for the onClick events is as follows:
println("Button Clicked");
try{
var forkNumberInput:com.ibm.xsp.component.xp.XspInputText =
getComponent("forkNumberInput");
var forkNum = forkNumberInput.getValue();
viewScope.ForkNum = forkNum;
println(forkNum);
} catch(e){
println( Error in Add button: " + e.toString());
}
When a space is in the text the viewScope doesn't get populated and nothing is written to the server log not even "Button Clicked". No error is written to server log.
If "Button Clicked" is not printed, the likeliest cause is that there are validation errors. Add a Display Errors control to make sure that's not the case.
I second Paul's suggestion to add the Errors control. Besides that: Try to avoid to use getComponent() when all you want to do is grabbing the value. The idea of JSF, extending to XPages, is "data binding". Controls are bound to some data source for their value and you interact with those. getComponent() is meant to be used when you need to manipulate anything else.
So you would go and bind your control that scope variable viewScope.forkNum and you are done. Your button then grabs the value from there and does what it needs to do.
So in summary: Controls want to be bound. Data lives in models (not controls)
Thanks Paul - you led me to the right direction. It turned out that there was a validateConstraint under Properties > data > validators. I removed the validateConstraint and it started working. That's what happens when you copy design elements from one custom control to another.

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();
}
});

How can we use ONLY client side script for "hide/whens"?

I am working on a large, worldwide application, which includes access from areas of low bandwidth. As such, I want to use a minimum of SSJS or partial refreshes for all the complex hide/when calculations. Here is what I have so far for a simple "hide/when":
A Yes/No radio button, with CSJS to show a panel ("Yes") or hide the
panel ("No").
The panel has a formTable inside it, and the values are shown or hidden, as per #1.
In the XPage's onClientLoad, the following code is run:
// "getRadioValue" is a simple script to return the value of a radio button
var v_value = getRadioValue("#{id:radioButton}");
v_div = '#{javascript:getClientId("radioButtonPanel")}';
// show or hide div simply use dojo to change the display of the panel
if (v_value == 'Yes') {
showDiv(v_div);
} else {
hideDiv(v_div);
};
For a new document, the onClientLoad script will hide the "radioButtonPanel" successfully. Changing the radio button to "Yes" will show the radioButtonPanel, just as clicking "No" will hide it. It works great! :-)
Once the document is saved and reopened in read mode, though, the onClientLoad CSJS event should read the saved value in the document, and decide to show the panel or not. When the document is opened in edit mode, the onClientLoad fires, reads the radioButton value and successfully shows or hides the panel.
This is what I've tried so far, to get it to work in read mode:
In CSJS, using "#{javascript:currentDocument.getItemValueString('radioButton'}" to get the value,
Doing some calculations in the "rendered" or "visible" properties, but that's SSJS and, if hidden, prevents any of the "show/hideDiv" CSJS visibility style changes.
Adding an old fashioned "div" to compute the style (which is what I used to do before XPages), but since I can't do pass-thru html any more, I can't seem to get a CSJS calculation for the style. Ideally, I can do something like this:
<div id="radioButtonPanel" style="<ComputedValue>">
Where the ComputedValue would read the back end value of the document, and decide to add nothing or "display:none".
Note that I don't want to use viewScopes, since this long form would need many of them for all the other hide/when's.
Is there any way to make this 100% CSJS? I feel like I'm very close, but I wonder if there's something I'm just missing in this whole process.
First, rather than computing style, I'd recommend computing the CSS class instead -- just define a class called hidden that applies the display:none; rule. Then toggling visibility becomes as simple as a call to dojo.addClass or dojo.removeClass.
Second, I see that you're using the #{id:component} syntax to get the client ID of the radio button but using SSJS to get the client ID of the panel. Use the id: syntax for both; this is still just a server-side optimization, but if there are many instances of these calculations, it adds up. Similarly, replace #{javascript:currentDocument.getItemValueString('radioButton'} with #{currentDocument.radioButton}. Both will return the same value, but the latter will be faster.
Finally, any attribute of a pass-thru tag (any component with no namespace, like xp: or xc:) can still be computed, but you'll need to populate the expression by hand, since the editor doesn't know which attributes for valid for these tags, and therefore doesn't provide a graphical expression editor. So if the ideal way to evaluate the initial display is by wrapping the content in a div, the result might look something like this:
<div class="#{javascript:return (currentDocument.getValue('radioButton') == 'Yes' ? 'visible' : 'hidden');}">
<xp:panel>
...
</xp:panel>
</div>

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.

Resources