I use the value for 'first' on a repeat control to know where I was as
sessionScope.ssCat1First = getComponent("repeatCat1").first;
so I can set the Starting Index value to ssCat1First and I'm on the right page. However, under some conditions I need to reset first on the component
I tried
getComponent("repeatCat1").first.setValue(0);
but I get the error " Error calling method 'setValue(number)' on an object of type 'Number [JavaScript Object]'"
So it looks like where I have 0 in need a Java Object? If so how would I do that?
You get a list of all properties and methods of Xsp components from JavaDoc Package com.ibm.xsp.component.xp.
How you can find the control's component class? Just print the object's class name to servers console with a button. For your repeat control example you'd write:
<xp:button
value="Show class"
id="button2">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:print(getComponent("repeatCat1"))}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
and console will show you something like
HTTP JVM: com.ibm.xsp.component.xp.XspDataIterator#20f620f6.
Now, look for class XspDataIterator in JavaDoc. This class doesn't have a method getFirst() or setFirst() but the parent class com.ibm.xsp.component.UIDataIterator has:
Keep in mind that getComponent("repeatCat1").first is the Expression Language version of getComponent("repeatCat1").getFirst(). That's what really gets executed.
The same applies to a pager. You'd look for XspPager and then for parents class com.ibm.xsp.component.UIPager. There you can see how to set the page number for a pager:
Use setFirst():
getComponent("repeatCat1").setFirst(0);
Related
I have a Xpage with two custom controls containing editable fields tied to the single data source on the Xpage. On the Xpage I use a xe:dialog that contains a button to save the data source document1 (using SSJS). No validation is occurring yet. I use a xe:dialogButtonBar to call the xe:dialog (using CSJS) which opens fine and then click the OK button containing Action Save Document data source.
diablogButtonBar onClick call to open dialog.
XSP.openDialog("#{id:dialogSaveAsDraft}");
With this configuration the document is saved but the editable fields are not created nor data saved. The Xpage has the following two properties set, computeWithForm: onsave, action:editDocument but have tried createDocument too.
Here is the twist: If I take the button in the xe:dialog and place it outside the xe:dialog, the button works and the Xpage and all editable fields save properly.
What am I missing? I have done almost exactly the same thing before but instead of using the xe:dialogButtonBar I used a string of buttons. I wanted to use the xe:dialogButton Bar to organize the UI.
Can some one explain why that would occur?
The problem is about the form submission. When you launch the dialog, editable fields on the other parts of the page are not submitted (dialog is launched upon partial refresh). Therefore the back-end component tree is not aware of the field updates of the client-side.
You can either open the dialog from the SSJS (so it submits the page) or create a "noupdate" submission with onComplete script to launch the dialog.
<xp:link
escape="true"
text="Open Dialog with SSJS"
id="link1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="norefresh"
action="#{javascript:getComponent('dialogSaveAsDraft').show()}">
</xp:eventHandler>
</xp:link>
<xp:link
escape="true"
text="Open Dialog with onComplete"
id="link2">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="norefresh"
onComplete="XSP.openDialog('#{id:dialogSaveAsDraft}');">
</xp:eventHandler>
</xp:link>
If you use ComputeWithForm then you have to have a DisplayErrors control. That is where validation error messages will appear. Do you have that? If not you could be getting a validation error from the formulas on the form and they have no place to display the error messages. By the way, using ComputeWithForm is not really a good thing to do. You should repeat your validation logic directly on the XPage. Otherwise, you got too many things going on, the validation/translation that happens at the XPage level and again at the form level.
I have an inputText which is a required field on my Document.
<xp:inputText value="#{Cdoc.txt_NumeCompanie}" id="txt_NumeCompanie"
required="true" defaultValue="#{javascript:param.value}">
<xp:this.validators>
<xp:validateRequired message="Numele companiei este obligatoriu." loaded="true">
</xp:validateRequired>
</xp:this.validators>
<xp:eventHandler event="onchange" submit="false" disableValidators="true">
<xp:this.script><![CDATA[ XSP.partialRefreshPost("#{id:scrollDiv}", {
onComplete: function() {
XSP.partialRefreshPost("#{id:pers}");
}
});
]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
I also checked the Process data without validation ( from the Server tab ... ). But still no refresh is taking place.
You do not include the required second parameter on your second partialRefreshPost. Try this:
XSP.partialRefreshPost("#{id:scrollDiv}", {
onComplete: function() {
XSP.partialRefreshPost("#{id:pers}", {});
}
});
Update: you can use the onComplete event of the eventHandler to run your 2nd partial refresh. So use the traditional partial refresh of the first component and then run your 2nd partial refresh through the onComplete event:
<xp:inputText value="#{Cdoc.txt_NumeCompanie}" id="txt_NumeCompanie" required="true" defaultValue="#{javascript:param.value}">
<xp:this.validators>
<xp:validateRequired message="Numele companiei este obligatoriu." loaded="true">
</xp:validateRequired>
</xp:this.validators>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="scrollDiv">
<xp:this.onComplete><![CDATA[XSP.partialRefreshPost("#{id:pers}", {});]]></xp:this.onComplete>
</xp:eventHandler>
</xp:inputText>
By setting submit="false", you're preventing any server-side processing from being triggered by the eventHandler itself. That means disableValidators="true" is irrelevant, because the XPages lifecycle is not being processed from the eventHandler.
Instead the refresh is being generated from the client-side code, the XSP.partialRefreshPost. That doesn't have an option to disable validation, as covered here How to disable validators using the XSP.partialRefreshPost method?. disableValidators="true" doesn't and cannot influence the processing of the partialRefreshPost. So chances are your validation is still running. To confirm that, add an errors panel into the initial refresh area.
partialRefreshGet may work, I'm not sure.
My usual approach in these scenarios is to refresh a single area that comprises both areas you wish to refresh. Then set submit="true" and disableValidators="true". But bear in mind that even if validation is disabled, data conversion is still checked so if you enter a text value in a number field, the partial refresh would still fail.
Ok, first thing to do is open your toolbox and look at the network traffic. This will help you to understand what is going on. You can use FireBug in FireFox or Developer tools in Google Chrome.
What network traffic occurs for the above snippet?
Edit:
Still waiting to hear what network traffic is generated...
But just looking at your code... - try set submit="true". I had a look at some of the code I have, and I am not sure that the extra empty param is required :-)
Could you explain what you are trying to obtain?
Edit
Ok, I see what you want. I had a quick view in some code. I am not doing exactly the same that you are. However, when I nest the partial refreshes I typically do it this way:
<xp:button id="button1"
styleClass="btn btn-danger btn-lg#{FishingTripEdit.typeInput eq '1' ? ' inActive' : ''}">
<xp:eventHandler event="onclick" submit="true" refreshMode="partial"
refreshId="inputTypeSelected" disableValidators="true">
<xp:this.action>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:MyBean.setData('0')}]]></xp:this.script>
</xp:executeScript>
</xp:this.action>
<xp:this.onComplete><![CDATA[XSP.partialRefreshGet("#{id:buttonTopHolder}")]]></xp:this.onComplete>
<xp:this.script><![CDATA[return document.getElementById("#{id:triggerAsk}").value!=='1' ? true : confirm("Sure?")]]></xp:this.script>
</xp:eventHandler>
</xp:button>
So for the "first" refresh I use the builtin markup - and onComplete I add the second as plain JavaScript. I know this is an example with a partialRefreshGet (which I prefer to use if at all possible due to less overhead). But perhaps it can give you an idea....
I've just started using the xe:applicationLayout for an application. I have added a "Basic Node" to the "Place Bar". I want to run some server side JavaScript code onClick of the node/button. I have tried computing the onClick property of the Basic Node, but this doesn't do anything and it seems like the onClick only runs client side JavaScript.
Is there a property or node that can run SSJS? Thanks for any help.
Set the submittedValue property of the node. ( the procedure is the same for all places in the application layout; here is an example snippet for the banner.ApplicationLinks )
<xe:this.bannerApplicationLinks>
<xe:basicContainerNode styleClass="firstApplication" label="${langString_CRM['CREATE']}">
<xe:this.children>
<xe:basicLeafNode submitValue="company_new"
Then add an event handler to your page and run your SSJS depending on the submitted value
<xp:eventHandler event="onItemClick" submit="true"
refreshMode="partial" disableValidators="true" refreshId="cois_application_layout"
execMode="partial">
<xp:this.action><![CDATA[#{javascript:
var submittedValue=context.getSubmittedValue();
// evaluate the submitted value here ...
Not the nicest version but it works.
Add buttons to the XPage and hide then using css.
In your application layout add a client side script that gets a handle to the buttons using
dojo.byId and do a click() on them. Then it's easy to have different panels update when you click on different buttons.
I'm having an issue with some server side validation and I can't tell if this is the expected behavior in XPages or if I'm missing something simple here.
I have a field that has a computed validation formula - basically, it becomes required when a viewScope variable gets set.
My submit button sets the viewScope and does a full refresh.
I would expect the form to be submitted, the validation formula gets evaluated, and if it fails the validation failure would be displayed. But when I click my submit button the form is submitted without error. If I click it again, validation fails as expected.
To illustrate my issue I created a simple example:
<xp:inputText id="inputText1" required="#{javascript:viewScope.validate}">
<xp:this.validators>
<xp:validateRequired message="This field is required."></xp:validateRequired>
</xp:this.validators>
</xp:inputText>
<xp:button value="Submit" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true">
<xp:this.action><![CDATA[#{javascript:viewScope.validate=true;}]]></xp:this.action>
<xp:this.script><![CDATA[dojo.attr(dojo.byId("#{id:inputText1}"),"aria-required","true")]]></xp:this.script>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:message id="message1" for="inputText1"></xp:message>
As you can see, I also tried adding the aria-required attribute with csjs within the button in the hopes it would initiate validation.
If validation is working as expected are there any suggestions for getting dynamic validation like this to function properly? I know I can do something with querySave on the data source (I excluded a data source from the example for simplicity) but was hoping there is a simpler solution than that.
It looks like the problem is misunderstanding the lifecycle. You're specifying whether the field is required in a viewScope variable. When the page is first loaded, the viewScope is false, so the field is not required. After you submit, the viewScope variable is set, the page rendered again. Only now does the field become required, but it is only required the next time the form is submitted.
If you want the field to be required, you'll need the required property to be evaluated to true and passed to the browser before the form is submitted.
There are a number of alternatives for the functionality you're trying to manage, running SSJS and failing if certain criteria are met.
One is to use the validator property rather than calculating the required property. The validator allows you to run code but you will need to use this.getSubmittedValue() to check the field's value - the validator runs earlier in the lifecycle before the submittedValue is passed to the value property.
The second option is to put the validation in the Submit button. You can use facesContext.addMessage(). If you google xpages facesContext addMessage there are plenty of examples of how to do it. Then do "return false" to abort.
It looks like you might want conditional validation. I wrote a blogpost about this a while back:
Making validation behave properly
I have the following LINK control on the form and would like to call the managed bean method onclick and do partial refresh (refreshing specifing part of the page). But I just found out, that this doesnt work, I can see that clicking on link sends XHR request to server, but the managed bean method call (entire onClick SSJS event) is not triggered. If I redesign thi as button controll, thigs are working properly, but I need link in this case. Is it some bug or my misuse of concept?
<xp:link escape="true" text="" id="link2" >
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" disableValidators="true" refreshId="create_recipe_form_panel">
<xp:this.action><![CDATA[#{javascript:F.getRecipe().adjustWt()}]]></xp:this.action>
</xp:eventHandler>
</xp:link>
I would say: misuse of concept. A links should "send you somewhere else" while a button "does something for you". So most likely the link destination and the click action get in each others way. Use a button and give it a class. Play with the css until you have the visual you desire.