Refresh InfoPath field after code-based calculation - infopath2010

I have an InfoPath 2010 form that creates a new Sharepoint list item. The form has, in essence, one input field and one output field. If something gets entered in the input field then some calculation is performed and I want the result to show up in the output field.As the calculation is somewhat complicated I need to do it in code, not through rules.
private void CalculateOutput()
{
XPathNavigator main = MainDataSource.CreateNavigator();
XPathNavigator service = main.SelectSingleNode("my:meineFelder/my:serviceValue", NamespaceManager);
double serviceValue = service.ValueAsDouble;
double output = 3*serviceValue; // much abbreviated version
// output now has the correct value
XPathNavigator outputNav = main.SelectSingleNode("my:meineFelder/my:output", NamespaceManager);
//Remove the "nil" attribute (otherwise we get an error when the field is a double instead of a string)
if (outputNav.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance")) outputNav.DeleteSelf();
outputNav.SetValue(output.ToString());
}
My problem is that everything works fine in the InfoPath preview but once I deploy the form and run it in the browser the output field does not get updated, i.e. I cannot see the result of my calculations.
I have tried .ReplaceSelf (with OuterXML), with zero result. I have also played with assigning the result to another field and thereby firing an "set field value" rule, also to no avail.
If I submit the form, the output value is saved OK but I'd really like the user to see the output field before submitting.
Any Ideas?
Thx a lot.

In case of browser enabled form, ensure that you have set the "Postback Setting" to refresh "Always"
To do this right Click on the control on which the postback is to be triggered. (in your case Service value). Go to Browser Forms tab and set the Postback Setting to Always.

Related

Cognos 10 Report Studio: On Page Prompts & Performance

I have a report page which displays a crosstab. This is filtered by 5 paramaters. These paramaters are submitted by the user through on page checkbox prompts.
The requirement is to return the data with all values in all paramaters selected on the first run. If I leave default selections blank this behaviour is achieved but all the checkboxes are unchecked which gives misleading feedback to the user.
As an alternative I've manually specified all the values in default selections. However, this has a performance impact.
Does anyone have any alternative suggestions?
I've been looking for a way to specifically link a reprompt button to a value list so only those paramaters are resubmitted (rather than the whole page) but haven't found anything yet.
Thanks in advance - even if the answer is 'no and this is a bad way to go about it'!
One option is to use JavaScript to check all of the checkboxes after the page is rendered with no filtering applied. To do this all filters have to be set to optional. The page is rendered with all data and unchecked checkboxes. The JavaScript fires and checks all checkboxes so that the state of the prompts matches the state of the data. This happens so fast the user likely won't know the boxes weren't checked initially. A reprompt button will, when clicked, enforce whatever choices the user makes after that.
Since version 10.2, Cognos has provided a fairly simple JavaScript API to allow for render-time manipulation of prompt controls. Hopefully, you are working with 10.2 or later otherwise the code provided will not work. Here is a bit of JavaScript code that will loop through all prompts and select all values within them:
var report = cognos.Report.getReport("_THIS_");
var prompts = report.prompt.getControls();
if (typeof firstrun == "undefined") {
var values;
for (var i=0;i<prompts.length;i++) {
values = prompts[i].getValues(true);
prompts[i].addValues(values);
}
var firstrun = false;
}
Notes:
All value prompts behave the same way regarding the 10.2+ JavaScript Prompt API. It doesn't matter whether you choose a drop-down, list, checkbox or radio button interface. The way we code for all of these variations is the same. The provided code would work just as well with a list as it would with checkboxes.
Make sure that you wrap your code in script tags and that the HTML Item object you place on your page to hold the code appears below all prompt controls. If it is placed elsewhere it will not be able to find the prompt controls as they will not have been rendered when the code executes.
The code assumes that the only prompts on the page are the checkboxes you want checked. If there are other prompts on the page then you will have to target individual prompts using the getControlByName() function provided in the API rather than looping through all prompts. More information on the Cognos JavaScript Prompt API can be found here.
The key bits of code here are the getValues() and addValues() Cognos JavaScript Prompt API functions. getValues(true) returns a JSON-formatted object representing all values, selected or not, from a value prompt. addValues(values) takes a JSON-formatted object representing the values to be selected and selects them. Thus, it's a matter of grabbing all values and then passing them in to be selected.
The reason for the if block is that we only want this code to run once at first page render. When the user first runs the report we want all checkboxes checked but after that we want the checkboxes to retain state. If we didn't use the if block the user's choices would be overwritten after a reprompt. For more information on this technique check out this tutorial on my blog: JavaScript: Running Code Only Once.
Addendum
If you don't want any filters to be applied when all boxes are checked in a section even after subsequent reprompts you can do so by tweaking your filter.
Assume that we are checking against a model based item [Item1]. We have a current filter of: [Item1] in ?parameter1?. We also have four checkboxes with values of 'Choice1','Choice2','Choice3', and 'Choice4'.
The following modified filter will only apply the checkboxes to the filter when all four aren't checked:
(
'Choice1' in ?parameter1?
AND
'Choice2' in ?parameter1?
AND
'Choice3' in ?parameter1?
AND
'Choice4' in ?parameter1?
)
OR
[Item1] in ?parameter1?
If all four checkboxes are checked then the first part of the OR is satisfied and all rows will be returned. It should be fast too because most languages, including iterations of SQL, will not test the second component of an OR if the first component is satisfied.

View data being cached/failing to refresh

I have a tabbed panel containing different sections of a form. In one section, users are given the ability to add a child document to the currently open document. In a second section, they are given a listbox, where the options are dynamically generated (via #DbLookup) by looking at a view of all the child documents, filtered by the current document's ID. This functionality all works correctly, however, there is a problem with the dynamic listbox options.
When a user adds a new child document, then switches to the next tab, the listbox is not updated with this new document. If they save/re-edit the main document or refresh the page, it makes no different, the user must load another XPage before going back to the original in order for the listbox to update. I have tried to resolve this by doing full updates of the page, using session.evaluate and "NoCache" in the #DBLookup call, or calling database.getView("My view").refresh(), but without luck.
There is also a similar problem where I have a repeat control which uses a view of child documents (again filtered by main document ID) as a datasource. When a user adds a child document using a button, it partially refreshes the repeat - but doesn't show the new child document until the page is refreshed again (or you leave the page and return).
Is there something crucial I am missing with regards to the JSF lifecycle/the way that view data is cached?
As first measure I would add another formula item to the listbox which simply returns the current time (#Now() should work). That way you can check if the listbox options are refreshed on the update in the first place.
If the options are refreshed fine it's indeed clear that the #DbLookup does some caching, although I'm not aware of any default caching logic.
At least for a test I would change the code to use a NotesView object instead of the #DbLookup, something like this:
var nview = database.getView("someview");
var nc = nview.getAllEntriesByKey(currentDocument.getDocument().getUniversalID(), true);
var a = [];
var ve = nc.getFirstEntry();
while (ve) {
a.push(ve.getColumnValues().elementAt(0)); // value of first column
ve = nc.getNextEntry(ve);
}
return a;
(I wrote the code from memory, there may be syntax errors).
Since the code only works with view entries it should be equally fast than the #DbLookup. And you could even do a nview.refresh() if needed.

In crm 2013 the AttributeInfo.GetValue returns wrong value

We are experiencing a strange issue, which can be reproduced by following below steps:
Open New Task (Or any other entity)
Enter text “Test Subject” in “Subject” field (or use any other field).
Use this Xrm.Page.getAttribute("subject").getValue(); statement to
get the value of subject’s field, it will return “Test Subject”.
Now clear the subject field.
Use this Xrm.Page.getAttribute("subject").getValue(); statement to
get the value of subject’s field, it will return “Test Subject”,
which is wrong value, the subject field is empty.
The Xrm.Page.getAttribute("subject").getValue() returns wrong value. We checked this issue in CRM 2011 and its ok the issue is specific to CRM 2013.
EDIT:
This code is fired from Custom Ribbon Button.
We tried to change the focus to another control and then we checked the value, it not works.
EDIT:
This issue occurs only if the field is a required field.
The logic of CRM page is that it changes data inside of the Xrm.Page.data object only if the edited field lost focus (this event tells CRM that the data entry is done), so it could be that after step 4 you don't lose focus to other field. This behavior is the same as in CRM 2011.
I think you have two problems here although they maybe cause by the same thing. This is unfortunately not an answer to these problems but an attempt to clarify the above.
Problem 1: JavaScript reads previous value when an empty value is entered.
I think this is the same as the original problem of this post.
This is also posted at: http://partnersupport.microsoft.com/en-us/mpndynamics/forum/mpndyncrm/javascript-reads-previous-value-when-an-empty/f7b8dffd-3a21-48ae-8dca-4c5467ea8272
On the Competitor form.
Enter “Oliver” in the name field.
Then read it in JavaScript as below.
function ClickHandler()
{
var nameValue = "";
nameValue = locationValue = parent.Xrm.Page.getAttribute("name").getValue();
var test1 = "";
}
You should get “Oliver” as expected.
Then go back to the Competitor form and manually delete the text with the backspace key.
Now read what is in the name field with JavaScript as was done earlier.
You would expect to get nothing but you get “Oliver”.
Now enter Mark in the name field.
Read the field with JavaScript and you get “Mark” as you should.
So it seems when an empty value is entered following a previous value the JavaScript reads the previous value.
To put it a different way. It seems that there is a problem if the Name field had a value and the text then gets manually deleted. The Xrm.Page object will not update to the empty string. The Xrm.Page object will however update to a non-empty value.
Problem 2: Javascript cannot read the value in the text field if the field has not lost focus.
This is also posted at http://partnersupport.microsoft.com/en-us/mpndynamics/forum/mpndyncrm/javascript-cannot-read-the-value-in-the-text-field/ecc2c9e0-fba0-44f2-93cd-320d042896f0?tm=1389885238744
Javascript cannot read the value in the text field if the field has not lost focus.
On the "Recurring Appointment" form I have an IFRAME that runs Javascript. It reads the value in the location field when a button is pressed. If I change the value in the location field to say "Brunswick Street" and press the button I get nothing read (i.e. in the code below locationValue is null).
However if I change the value in the location field to say "Brunswick Street". I then then click away to somewhere on the form other than the IFRAME so the location field has lost its focus (this can also be achieved by pressing enter/tab after entering the text in the location field). If I then press the button on the IFRAME the Javascript will read the text in the location field correctly.
I gather that this is because parent.Xrm.Page is only updated when focus is lost in a field.
function ClickHandler()
{
var locationValue = parent.Xrm.Page.getAttribute("location").getValue();
}
I tried changing the focus in the JavaScript by setting it to requiredattendees field. But this did not work.
parent.Xrm.Page.getControl("requiredattendees").setFocus();
I used to use parent.document.forms[0].namedItem(srcDataFlds[fld]).value; to get the value in CRM 4 and 2011 but this does not work in CRM 2013. So as the SDK suggested I changed the code to use parent.Xrm.Page however it seems to give the problem above.
The questions are why is the focus not lost when I click the button on the IFRAME? If I click on any field in the form the focus changes so why not the IFRAME.
Also how can I get the JavaScript to read the value in the location field without having to click away from the location field. (Hopefully read the value in a supported way)?
I just want the user to be able to enter the value in the location field and click the button in the IFRAME.
I also noticed that when you click the IFRAME the On Change Event is not fired for the location field.
So far the only way round this is to click on another field (or pressing enter/tab) before clicking on the button that fires the Javascript.
Both these problems have been recognized by Microsoft and have been fixed in “Update Rollup 1 for Microsoft Dynamics CRM 2013 Service Pack 1”

Inline Editing of View data used in a repeat

I have a repeat control using a view as the datasource with a custom control within the repeat. The custom control is made up of a panel with two tables. One table has computed fields with an Edit button and the other has editable fields with a Save and Cancel button. The Edit and Cancel buttons work as needed, but the Save button gives a NotesDocument.save() is null error. I have already narrowed the issue down to the error occurring on the edoc.save() line by commenting out all prior lines. I even tried to do an edoc.lock(), but got the same error.
var edoc:NotesDocument = database.getDocumentByUNID(viewScope.get('docid'));
edoc.replaceItemValue('Ext_1',viewScope.get('ext_1'));
edoc.replaceItemValue('DID',viewScope.get('did'));
edoc.replaceItemValue('Mobile',viewScope.get('mobile'));
try {
edoc.save();
} catch(e) {
print(e.toString());
}
The storage of a DocID in the viewScope and a repeat control doesn't seem right. You want to add a custom property to your custom control called DocID and then instead of
database.getDocumentByUNID(viewScope.get("docid"));
You do:
database.getDocumentByUNID(compositeData.DocID);
This was you can be sure that you get the document that was in that view for that row.
What you also might consider, instead of all the manual steps (the ones you commented out) have a panel with a DocumentDataSource and then simply bind your input fields to that one. Handover of id via custom property and "IgnoreRequestParameter = true
Then you simply do a rowDoc.save() (presuming you named the datasource rowDoc) and you don't need to recycle anything. Let us know how it goes.

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