3
votes

Using 8.5.3 UP1. I'm having an issue with an SSJS script library that I am using for "hide/whens" or more exactly in xpages "show/ifs". In any case the global variables seem to take the value of the last time I saved the script library. They don't seem to compute based on the documents current value. Is this a known thing (obviously not known to me.). Here is a sample page and script library to demonstrate the issue:

Example XPage:

<xp:this.resources>
    <xp:script src="/ssjsVisTest.jss" clientSide="false"></xp:script>
</xp:this.resources>
<xp:inputText id="inputText1" value="#{document1.StatusTX}"></xp:inputText>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:button value="Save" id="SaveBtn">
    <xp:eventHandler event="onclick" submit="true"
        refreshMode="complete">
        <xp:this.action>
            <xp:saveDocument var="document1"></xp:saveDocument>
        </xp:this.action>
    </xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:label id="label1" value="Status is Draft"
    rendered="#{javascript:statusVisibleDraft()}">
</xp:label>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:label id="label2" value="Status is Pending"
    rendered="#{javascript:statusVisiblePending()}">
</xp:label>
<xp:br></xp:br>
<xp:br></xp:br>
</xp:view>

Sample SSJS script library:

var status = document1.getItemValueString('StatusTX');

function statusVisibleDraft() {

x = (status == "Draft") ? 1 : 0;

if(x > 0) {
    return true;
} else {
    return false;
}
}

function statusVisiblePending() {

x = (status == "Pending") ? 1 : 0;

if(x > 0) {
    return true;
} else {
    return false;
}
}

Any ideas? Thanks

3

3 Answers

4
votes

Variables in script libraries are transient in nature. Depending on system load the libraries might get unloaded between calls. The right place for global variables are the scopes (this is what they are made for). In your example it seems the view scope would be appropriate. Also Sven is right about computation. Furthermore it is good practise not to have side dependencies. If you add another data source with a different name you can't reuse your ssjs lib. You would hand over the data source as parameter e.g. in beforeRenderResult: setstatusDraftVisible(document1,'Status','draft') Inside such a function you check if the field (2nd param) exists and has the value of the 3rd param and then set: viewScope.statusDraftVisible=true; // or false

Then you have rendered="#{JavaScript:viewscope.statusDraftVisible}"

When your application is more complex and you have a lot of these checks, you might consider a viewScope 'backing bean' aka managed bean. This could reduce rendered to rendered="#{beanName.statusDraftVisible}"

Which is faster.

2
votes

I believe this is because the status variable is not set on each call to the statusVisibleDraft() and statusVisiblePending() functions since it is outside of the functions.

Move the assignment of the status variable inside each function:

var statusVisibleDraft = function() {

  var status = document1.getItemValueString('StatusTX');

  x = (status == "Draft") ? 1 : 0;

  if(x > 0) {
      return true;
  } else {
      return false;
  }
}

var statusVisiblePending = function() {

  var status = document1.getItemValueString('StatusTX');

  x = (status == "Pending") ? 1 : 0;

  if(x > 0) {
      return true;
  } else {
      return false;
 }
}
2
votes

The code in the SSJS library will only be executed if the library is being loaded. The domino server caches the library internally. Only if you save the SSJS library or the embedding XPage the library will be reloaded and executed again.

If you reload the XPage in your browser the SSJS library will not be reloaded or executed again. Even if you close the browser and reopen your XPage, domino will not refresh them.

Just add some print statements to your SSJS library and you can see the behaviour on the server console.

Maybe this is the answer you are looking for.

Hope this helps Sven

Edit: This means that your global variable status will be only computed the first time the SSJS library is loaded.