In the source of an xpage I have, RIGHT after the opening view tag...the following:
<xp:this.data>
<xp:dominoDocument
formName="myform"
var="document1"
</xp:this.data>
I need to be able to pull the value of any field for various functions. In a 'Server JavaScript' library I have this function, as a test:
function testThis(){
debugger;
var mystring = document1.getElementById("#{id:employeeTitle}");
console.log(mystring);
(...expecting everything in the element to be logged in the console.)
You can see I have the XPage bound to a DominoDocument with the variable name of 'document1'.
The function is called via a button, and stops for the debugger...so I can step through it.
In Firefox debugger, it is 'Paused at an exception' that says:
ReferenceError: document1 is not defined
I am sure this is something simple staring right at me, but I just don't get it. Any ideas?
Thank you.
I think you are mixing up ServerSide JS and client side. The Firefox debugger only knows about client side debugging (which is code that executes in the browser). For debugging server side JS I suggest the Debug Toolbar plugin that you can find at open NTF.https://www.openntf.org/main.nsf/project.xsp?r=project/XPage%20Debug%20Toolbar
You can also write to the server log with _dump, see https://xcellerant.net/2014/10/15/using_dump_to_write_to_server_console/
Finally, note in your code that if SSJS, you would use document1.getItemValueString("whatever") to access document values. The document object is of type NotesXSPDocument. See https://www.ibm.com/support/knowledgecenter/en/SSVRGU_9.0.1/reference/r_wpdr_xsp_xspdocument_r.html
You get the DOM element of the rendered field employeeTitle on client side in your CSJS code with
var element = document.getElementById("#{id:employeeTitle}");
and the content value with element.innerHTML.
Use document (entry point to web page loaded in the browser) instead of document1 (usually named XPage's data source on server side).
Your function testThis() has to be a part of the XPage, Custom Control or a SSJS library. This makes sure that #{id:employeeTitle} gets replaced with the real DOM id on server during rendering. If you want to put testThis() into a CSJS library you have to deliver the id as parameter to the function like
function testThis(id){
var element = document.getElementById(id);
...
and call the function in XPage like
testThis("#{id:employeeTitle}");
Related
If I use
context.redirectToPrevious()
It works great, but If I call an xagent with or without state between opening the document and doing a close of the document. I end up navigating to the xagent.
And If I go directly to the view behind I loose opened categories in the view.
Is there a way to block an xpage to end up in the navigation/history tree?
There are two approaches that would work.
The first is to use client-side JavaScript to open the XAgent. How you handle that will depend on whether there are values set in the browser that you are passing to sessionScope for the XAgent to use. If not, you can just use client-side JavaScript to open the relevant XAgent page. If you do need values, there are two options:
Pass them as query string parameters to the XAgent instead of storing them as sessionScope variables.
Perform a partial refresh to store the values in sessionScope and open the XAgent page via client-side JavaScript either in the onComplete() event (will trigger every time) or using view.postScript(), passing the relevant CSJS as a string (will only trigger if validation is successful).
The second is to set the previous page in the beforePageLoad event and then use that value in context.redirectToPage().
I am using the Receipts page (IN301000) for reference purposes:
I would like to be able to obtain a field's information on the client side with the GetElementByID() method.
When I inspect the field, and identify the rendered ID, I obtain data:
However, if I refresh the page and invoke the method again, I obtain NULL:
Does anyone know how to make that information always available?
The final goal here is being able to pass data to the client side. I can - for instance -populate an unbounded field with the FieldSelecting event, and would like to ideally read data out of it.
If there are client variables that could be set from the graph, it would work as well.
Thanks!
You likely get null because the script is executed in the top iFrame instead of the main iFrame which contains the control.
The JavaScript global variable px_alls contains the editor controls and can be indexed by editor control ID.
px_alls["edTransferNbr"].getValue();
document.getElementById("ctl00_phF_form_t0_edTransferNbr_text").value;
Script executed in main iFrame context:
When the script is executed in the context of the top iFrame you would have to select the main iFrame.
var mainframe = document.querySelector('[name=main]').contentDocument;
mainFrame.getElementById('ctl00_phF_form_t0_edTransferNbr_text').value;
Script executed in top iFrame context:
I have been going around in circles with this, so I would appreciate some help
This is what I want to achieve
User presses my extension ison
Popup appears with two buttons, 'run function a' and 'run function b'
When they press a button it runs the function in my own js file, that I have injected.
Function a for example, could be to count the number of elements of a certain type in the active tab
So, I can inject my js file on page load (this is in my contentscript.js)
var s = document.createElement('script');
s.src = chrome.extension.getURL('temp-file.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
This works, and I can see the js being excuted
But what I can do is to have a function run that is in temp-file.js
For example in the popup I have
chrome.tabs.executeScript(null, {code:"shows();"});
I get this: Uncaught ReferenceError: shows is not defined
If I enter shows(); into the console, it works as expected
I presume that the issue is all about the context. I tried various things in the popup.js page to also inject the file but nothing seemed to work
Is anyone able to point me in the right direction please
Thanks
Grant
I presume that the issue is all about the context.
You're right about it.
The file "temp-file.js" has been injected into host page, so it is now part of host page context. Extension can mess with it - since it is in different context.
Run a function from injected js
Solution:
Not sure about what you are trying to achieve. pick what suits you:
Split injected file
Code/functions you want to execute on a page - use them as contentscript.
In this case split you "temp-file.js" - part extension has execute (becomes part of contentscript) and part host page has to execute(your code snippet).
use custom event
Use custom event - generate custom event in contenscript - listen for it injected script. custom event
Your question does not say what exactly you are trying to achieve.
This is what I understood. You want to execute a function on your contentscript.js from your popup.js.
If that is the case then you can call a method on contentscript from popup.js like mentioned here https://developer.chrome.com/extensions/messaging
Why does context.redirectToPage behave differently when executed in a view root-event instead of an event handler?
This question came up when I tried to set the language of an xpages application to the language saved in the user profile, once the user is logged in. I use a properties-file with translated strings in a resource bundle, and retrieve the strings like this:
<xp:text value="${langString['WELCOME_TEXT']}" />
When the language is changed and so a different properties-file is loaded, the page needs to be refreshed in order to update those strings. This worked fine when I added a full-refresh event handler to the login button, that executed a server side context.redirectToPage(). No luck with client side refreshes like location.reload or window.location.href=window.location.href (the login-function itself is a client side function though).
But of course the user expects that he is also logged in when he presses the enter key instead of the button after he has entered his credentials. So I added an onkeypress-event to the username and password input fields, and checked for the enter key (if (thisEvent.keyCode==13) dosomething...) before executing the login function.
But now the event handler is called every time a key is pressed and of course I do not want the context.redirectToPage to be executed all the time.
Thus I removed the server side event handlers and changed the login function so that it terminated with a partial refresh of the div containing the whole page:
var p = {"execLogin":"true"}; XSP.partialRefreshPost( '#{id:wholePage}', {params: p} );
The parameter sent via the partial refresh now triggers an event in which our context.redirectToPage is executed:
<xp:this.beforeRenderResponse><![CDATA[#{javascript:if (param.containsKey('execLogin') && param.get('execLogin').toString().equals('true')) {
print("test");
context.redirectToPage(context.getUrl().toSiteRelativeString(context),true);
}}]]></xp:this.beforeRenderResponse>
The page is refreshed and "test" is printed out, but I still see the old language strings. I have to refresh the page manually again to make the new user language take effect.
Any idea how to execute a genuine full refresh this way, or maybe another way to update the strings retrieved from the property bundle?
Thanks in advance. Regards,
Sarah
EDIT
I now have:
<xp:inputText id="cc_login_panel_login_username" styleClass="span2">
<xp:eventHandler event="onkeypress" submit="true" refreshMode="complete">
<xp:this.script><![CDATA[if (thisEvent.keyCode!=13) {
return false;
} else {
doLogin();
return true;
}]]></xp:this.script>
<xp:this.action><![CDATA[#{javascript:context.redirectToPage(context.getUrl().toSiteRelativeString(context));}]]></xp:this.action>
</xp:eventHandler>
Because context.reloadPage() didn't even log me in somehow (strange) I got back to using redirectToPage. The server side event is fired once and at the right time *thumbs up*, but the language properties-bevaviour is still the same.
$ is only set on page load, whereas # is set each time during the partial refresh.
I don't think a partial refresh will work at all though. This will refresh the computed field. However, it will need a full refresh to refresh the part of the XPage that includes the properties file. In other words, you would be refreshing the computed field, but using the same properties file.
I wonder if context.redirectToPage or context.reloadPage is somehow going to the same page but with the cached properties files.
If you're always wanting to come back to the same page, a full refresh instead of partial refresh may be the best option.
I think this has something to do with using the $ parameter. this tells the runtime to retrieve the language file the first time the current page is created in the back-end. When a user does a refresh it is actualy retrieving a saved version of the page you are viewing.
I see you're calling "context.redirectToPage(context.getURL().toSiteRelativeString(context)))" within an xp:this.action tag for the xp:eventHandler.
Try using xp:this.onComplete in place of xp:this.action.
According to the Designer tooltip for the action, the expected return is a string to be passed to the navigation handler. So instead giving the onComplete will execute the redirect command when it's done with the eventHandler group of events.
Thanks for all the helpful answers, in fact all of them did work, the problem turned out to be my misunderstanding of when the properties-file is loaded. It is loaded in an early phase, long before my new language is set to the sessionScope (that sessionScope variable is then used as a part of the name of the properties-file to be loaded, via the VariableResolver).
Now I use a double full refresh to load the new file. When the login function terminates successfully, it executes:
window.location.href = window.location.href + "?doRefresh=true";
And to the view root element I added the following event:
<xp:this.beforeRenderResponse><![CDATA[#{javascript:
if (context.getUrlParameter("doRefresh")!=null&&context.getUrlParameter("doRefresh").equals("true")) {
var url = context.getUrl().toSiteRelativeString(context);
url = url.replace("?doRefresh=true","");
context.redirectToPage(url);}
}]]></xp:this.beforeRenderResponse>
This is not a very sophisticated solution, but at least it works :-)
I am setting a viewScope variable in a server side javascript (SSJS) button.
viewScope.put("branchName",doc.getItemValueString("BranchName"))
How can I access that variable on the client side?
If you need to access the viewScope variable from a client side script you can use the xp:scriptBlock tag to setup a number of global javascript variables.
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[var myVar = #{javascript:viewScope.get("scopeVar")}]]></xp:this.value>
</xp:scriptBlock>
The main problem with this method is that the inner server side javascript is only computed when that element is initially rendered or when a partial refresh is performed on the element so there is no guarantee that the client side JS variable is set to the correct value.
You can't access viewScope Variables directly, but you could bind it to a hidden field
then access that value via csjs
XSP.getElementById("#{id:inputHidden1}").value
There are other ways to access it also, using something like rpc or an ajax request.
use the below code:
var value = "#{javascript:viewScope.variablename}"
I would take a look at the JSON RPC included with the extension library. This component will allow you to define a SSJS function that may/may not accept arguments. Let's say you add the RPC with an ID of myRPC and a method called getViewScopeVar that accepts a single String argument and returns the value of the viewScope variable with the name that you include as the argument. You can then call that method like:
myRPC.getViewScopeVar("branchName")
This is the easiest most effective way to interact with server side elements from client side javascript. Plus it gives you the option of all the required methods being in one place as long as you place that RPC on a strategic custom control (i.e. like a layout custom control that every xpage is based off of).
If you need frequent updates you can use the Ajax service from the extension library.