Xpages & DataTables - datatables

I'm using the dataTables jQuery plugin with xpages and have a custom control I drop onto any page, pass in a custom property of viewName and it will display a table using REST - All based on some great examples by Oliver Busse.
Everything works perfectly if this custom control is used on a basic page, however, if it is within a tab, which is not default, when I then click on the tab containing the control, I receive an error when calling viewjson.getId()
I think the issue is because I set viewjson on beforePageLoad?
Any idea how I can get this to work in a tabbed interface?
Code below:
<xp:this.beforePageLoad><![CDATA[#{javascript:var viewjson = new org.openntf.rest.DynamicView(compositeData.viewName);}]]></xp:this.beforePageLoad>
<table
id="#{javascript:viewjson.getId()}"
class="table table-hover table-striped">
<thead>
<xp:repeat id="repeat1" rows="30" disableOutputTag="true"
var="col">
<xp:this.value><![CDATA[#{javascript:try {
viewjson.getCols()}
catch (e) {
openLogBean.addError(e,this)
}}]]></xp:this.value>
<th>
<xp:text escape="true" disableTheme="true"
value="#{col}">
</xp:text>
</th>
</xp:repeat>
</thead>
<tbody></tbody>
</table>
UPDATE
I've tried the following to try and load jQuery first
<xp:this.resources>
<xp:headTag
tagName="script">
<xp:this.attributes>
<xp:parameter
name="type"
value="text/javascript" />
<xp:parameter
name="src"
value="/xsp/.ibmxspres/.extlib/responsive/jquery/jquery.min.js" />
</xp:this.attributes>
</xp:headTag>
</xp:this.resources>
And also this in xsp properties
xsp.client.script.dojo.djConfig="dojo-amd-factory-scan": false
But I'm still getting a blank page with no dojo elements displaying

I believe the main problem is that for the XPages core controls a non active tab is not actually rendered to the browser until it becomes active. So what you called in the beforePageLoad() was looking for content that didn't exist at the time.
There's probably a CSJS thing that could re-init the data tables. Another option is to not use the tab core control but use the dojo version from the ext. library. I'm pretty sure that the dojo version renders all content and just uses CSS to hide non active tabs.

Custom control's beforePageLoad event gets executed when XPage is loaded already.
When later the tab is activated and with it the table is rendered the variable viewjson is gone.
One approach would be to put Java object into a composite data variable compositeData.viewjson in beforePageLoad and use it in table later. But, you would calculate all views for every tab before rendering page. In addition, this class is not serializable and couldn't be stored in composite data variable. You could make the class serializable though.
The better approach is to instantiate Java bean in table - without a beforePageLoad event:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<table
id="#{javascript:
var viewjson = new org.openntf.rest.DynamicView(compositeData.viewName);
return viewjson.getId();
}">
<thead>
<xp:repeat id="repeat1" rows="30" disableOutputTag="true"
var="col" value="#{javascript: viewjson.getCols()}">
<th>
<xp:text escape="true" disableTheme="true" value="#{col}">
</xp:text>
</th>
</xp:repeat>
</thead>
<tbody></tbody>
</table>
</xp:view>
I tested the custom control above (ccView with property viewName) with this XPage
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:br />
<xp:panel id="tabs">
<xe:djTabContainer id="tabContainer"
selectedTab="djTabPane1" defaultTabContent="one">
<xe:djTabPane id="djTabPaneView" title="one" closable="false"
partialRefresh="true">
tab rendered first
</xe:djTabPane>
<xe:djTabPane id="djTabPane2" title="two" closable="false"
partialRefresh="true">
<xc:ccView viewName="ByCity" />
</xe:djTabPane>
<xe:djTabPane id="djTabPane3" title="three" closable="false"
partialRefresh="true">
<xc:ccView viewName="ByName" />
</xe:djTabPane>
</xe:djTabContainer>
</xp:panel>
</xp:view>
Views in tabs "two" or "three" get loaded per REST services when user clicks the respective tab.

Related

Data Table stateSave refresh continues POST requests after closing dialog

I am using the Data Tables jQuery plugin on XPages to display our price list to users. The administrators of the price list search for similar items, click the item description to modify the item via a dialog box. As there are over 1000 items in the price list it is necessary to save the search and at the same time refresh the table so the user can review the changes in the list after closing before moving to the next item in their search. Due to the large number of entries refreshing the whole page is messy, so when opening the dialog I refresh only the dialog, which has always worked fine until I have introduced the stateSave on the DataTable. The problem being now when I close the dialog the page continues making POST requests to open the dialog again with a random item from the bean.
Any help would be greatly appreciated.
<xp:div style="width:30%" styleClass="mg20">
<xp:panel id="tablePanel">
<table id="keyItemsPLTable">
<thead>
<tr>
<th>Description</th>
<th>Code</th>
</tr>
</thead>
<tbody>
<xp:repeat id="repeat1" rows="10000"
var="rowData">
<xp:this.value><![CDATA[# #javascript:itemBean.getPlItems("All","Price List Sales Cat Only")}]]></xp:this.value>
<tr>
<td>
<xp:link escape="true"
text="#{rowData.description}" id="link3">
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial" refreshId="dialog1" execMode="partial"> //Problem occurs due to this partial refresh
<xp:this.action><![CDATA[#{javascript:itemBean.setPlItem(rowData);
var dialog = getComponent("dialog1");
dialog.show()}]]></xp:this.action>
</xp:eventHandler>
</xp:link>
</td>
<xp:text tagName="td" escape="true"
id="computedField1" value="#{rowData.code}">
</xp:text>
</tr>
</xp:repeat>
</tbody>
</table>
<xp:scriptBlock>
<xp:this.value><![CDATA[
$(document).ready(function() {
var table = $('#keyItemsPLTable').DataTable( {
stateSave: true, //https://datatables.net/reference/option/stateSave
stateDuration: -1//This doesn't seem to work. https://datatables.net/reference/option/stateDuration
});
});
]]></xp:this.value>
</xp:scriptBlock>
</xp:panel>
</xp:div>
<xe:dialog id="dialog1">
<xp:panel id="panelFullDialog" styleClass="mg20">
<xp:div styleClass="mg20">
<xp:inputText id="inputDesc"
value="#{itemBean.plItem.description}" styleClass="wd200">
</xp:inputText>
</xp:div>
<xp:div styleClass="mg20">
<xp:inputText value="#{itemBean.plItem.code}"
id="inputText2" styleClass="wd200">
</xp:inputText>
</xp:div>
<xe:dialogButtonBar id="dialogButtonBar1">
<xp:button value="Cancel" id="button4">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:dialog1}')]]></xp:this.script>
</xp:eventHandler>
</xp:button>
<xp:button id="button1">
<xp:this.value><![CDATA[Save & Close]]></xp:this.value>
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="tablePanel">
<xp:this.action><![CDATA[#{javascript:itemBean.savePLItem();
var dialog = getComponent("dialog1");
dialog.hide();
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xe:dialogButtonBar>
</xp:panel>
</xe:dialog>
On closing the Post requests continue with the dialog reappearing until the page is closed.
200
POST
instant.abc.co.uk testing.xsp?$$ajaxid=view:_id1:tablePanel xhr html 35.47 kB 426.05 kB 2165 ms
200
POST
instant.abc.co.uk testing.xsp?$$ajaxid=view:_id1:dialog1 xhr html 574 B 650 B 1969 ms
200
GET
instant.abc.co.uk testing.xsp?$$ajaxid=view:_id1:dialog1:_content&$$showdialog=true&$$created=true&$$createdialog=false&$$viewid=!6rftmmaw860jebb294nc4ay3y! xhr html 871 B 1.94 kB
6 ms
200
POST
instant.abc.co.uk testing.xsp?$$ajaxid=view:_id1:dialog1 xhr html 574 B 650 B 2057 ms
200
GET
instant.abc.co.uk testing.xsp?$$ajaxid=view:_id1:dialog1:_content&$$showdialog=true&$$created=true&$$createdialog=false&$$viewid=!6rftmmaw860jebb294nc4ay3y! xhr html 873 B 1.94 kB
4 ms
200
POST
instant.networkconnect.co.uk testing.xsp?$$ajaxid=view:_id1:dialog1 xhr html 574 B 650 B
If you're trying to refresh tablePanel after closing the dialog, don't make that the refresh ID. The hide() method takes a parameter of the area to refresh after the dialog has closed. That's because the SSJS needs to post back to the browser to make the call to close the dialog, so it will pass a client-side JavaScript call to make a GET request to refresh whatever ID was passed as a parameter of the hide() method. See https://www.intec.co.uk/xpages-dialog-control-and-partial-refreshes/.

ReactJS.net unable to debug

I've created a small app using ReactJS.Net and ASP.NET 5. If I render a component serverside using #Html.React and tie that to the MVC
#using System.Threading.Tasks
#using React.AspNet
#model Models.DashboardViewModel
#Html.React("MessageBoard", new
{
recentPosts = Model.RecentPosts
})
messageBoard.jsx
"use strict";
var MessageBoard = React.createClass({
render: function(){
return (<table className="table forum table-striped">
<thead>
<tr>
<th className="cell-stat"></th>
<th>Topic</th>
<th className="cell-stat text-center hidden-xs hidden-sm">Replies</th>
<th className="cell-stat-2x hidden-xs hidden-sm">Last Post</th>
</tr>
</thead>
<tbody>
{this.props.recentPosts.map(function(boardPost){
return <BoardPostRow post={boardPost}/>;
}, this)}
</tbody>
</table>)
}
});
This all works great. The problem is that when I go to sources, there is no .js file so I have no way to debug. This is probably ok for some simple read-only elements. But now I want to render some interactive elements that contain state, a form for creating a new Post to the "message board". Here's the code in the same *.cshtml file.
<div id="newPost"></div>
#section scripts
{
<script src="#Url.Content("~/scripts/Components/Board/boardPostForm.jsx")"></script>
<script src="#Url.Content("~/scripts/Components/Common/textInput.jsx")"></script>
<script>React.render(BoardPostForm({}), document.getElementById("newPost"))</script>
#Html.ReactInitJavaScript()
}
The error I get in the console is:
Uncaught SyntaxError: Unexpected token <
textInput.jsx:19 Uncaught SyntaxError: Unexpected token <
(index):69 Uncaught ReferenceError: BoardPostForm is not defined(anonymous function) # (index):69
(index):70 [.NET] Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of MessageBoard. See http://fb.me/react-warning-keys for more information.
(index):71 [.NET] Warning: Unknown DOM property class. Did you mean className?
(index):71 Uncaught ReferenceError: MessageBoard is not defined
It seems an error trying to read the .jsx, because it takes me to the render function when I click on the error. What am I missing here? Maybe I need to do the jsx->js conversion as part of my build process (I am using Gulp) instead of relying on ReactJS.NET?
What happens if you hit /scripts/Components/Board/boardPostForm.jsx in your web browser? It should show the compiled JSX and have some ReactJS.NET info at the top of the file. If it doesn't, make sure the *.jsx handler is configured in your Web.config. It should look something like this:
<add name="ReactJsx" verb="GET" path="*.jsx" type="React.Web.JsxHandlerFactory, React.Web" preCondition="integratedMode" />
What am I missing here? Maybe I need to do the jsx->js conversion as part of my build process (I am using Gulp) instead of relying on ReactJS.NET?
You can use Gulp if you like, up to you. I have a sample here that uses Webpack for bundling, and ReactJS.NET for server-side rendering: https://github.com/reactjs/React.NET/tree/master/src/React.Sample.Webpack

IBM MobileFirst SQL Adapter

I want to connect my IBM MobileFirst apps to my database,
I use wampserver (localhost),
username = "root", password ="...", database name = "mydatabase".
In my MobileFirst project, I created a SQL adapter "myAdapter".
Inside the myAdapter.xml, this is the code:
<connectivity>
<connectionPolicy xsi:type="sql:SQLConnectionPolicy">
<!-- Example for using a JNDI data source, replace with actual data source name -->
<!-- <dataSourceJNDIName>java:/data-source-jndi-name</dataSourceJNDIName> -->
<!-- Example for using MySQL connector, do not forget to put the MySQL connector library in the project's lib folder -->
<dataSourceDefinition>
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/mydatabase</url>
<user>root</user>
<password></password>
</dataSourceDefinition>
</connectionPolicy>
</connectivity>
<!-- Replace this with appropriate procedures -->
<procedure name="insertMyTable1"/>
Below is myAdapter-impl.js file
var insertMyTable = WL.Server.createSQLStatement(
"IESERT INTO mytable" +
"VALUES (? , ? , ?);");
function insertMyTable1(id, name, age){
return WL.Server.invokeSQLStatement({
preparedStatement : insertMyTable,
parameters : [id, name, age]
});
}
//--------------------------------------
in one of my pages, I have a addData.html file, below is the code:
<html>
<script>
function insertData(){
var id = document.getElementById("id").value;
var name = document.getElementById("name").value;
var age = parseInt(document.getElementById("age").value);
WL.Client.invokeProcedure({
adapter : "myAdapter",
procedure : "insertMyTable1",
parameters : [ id, name, age ]
});
}
</script>
<body>
<form action="javascript:insertData();">
<table align="center">
<tr>
<td>Id : </td>
<td><input type="text" id="id"></td>
</tr>
<tr>
<td>Name : </td>
<td><input type="text" id="name"></td>
</tr>
<tr>
<td>Age : </td>
<td><input type="text" id="age"></td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" style="width:100px;">Add</button>
</td>
</tr>
</table>
</form>
</body>
</html>
But I fail to insert the data into mydatabase->mytable, anyone know why ??
error log (in my addData.html)
Uncaught ReferenceError: WL is not defined
This question is completely unrelated to your SQL adapter.
The problem here is that you have used a href to navigate to another HTML file. By doing so you have exited the scope, or context, of the MFP framework, which is why you are unable to use MFP API methods such as WL.Client.invokeProcedure.
A MFP Hybrid application is a Single Page Application. In the app's index.html there are references to the MFP JavaScript framework in order to load it... Without these, things will break.
In order to use multiple "pages" in your application, see the following tutorial:
Building a multi-page application
You must never actually navigate away from the context of the framework, so operations such as a href are not allowed.
If you want to separate your "pages" to separate HTML files, you can see this example project using jQuery Mobile. Other UI frameworks such as Dojo also provide their own implementation for multi-page support which you could use in your MFP application.
Related questions: https://stackoverflow.com/search?q=%5Bworklight%5D+multipage+is%3Aquestion

How can I react to a finished upload with <h:inputFile>?

I'm using Richfaces-4.3.5 on Wildfly-8.0.0.CR1 here, migrating from <rich:fileUpload> which doesn't work with JSF-2.2/Servlet-3.0. I'm replacing it with this snippet:
<rich:popupPanel id="testPop" autosized="true">
<h:form id="uploadF" enctype="multipart/form-data">
<h:inputFile value="#{bean.file}">
<a4j:ajax listener="#{bean.storeFile()}" render="#form,:fileListTbl"
oncomplete="#{rich:component('testPop')}.hide();" />
</h:inputFile>
</h:form>
</rich:popupPanel>
This works fine in that the storeFile method is called and I can access bean.file just fine. However, I'd like to close the rich:popupPanel when I'm done uploading, so I need to react to the success/complete events of the ajax request. But that doesn't seem possible - the popup stays visible and the response is clearly incomplete (indented for better readability):
<?xml version='1.0' encoding='UTF-8'?>
<partial-response id="j_id1">
<changes>
<update id="j_id1:javax.faces.ViewState:0">
<[CDATA[-1186354868983349335:-5499969782208038164]]>
</update>
<extension id="org.richfaces.extension"><render>#component</render></extension>
</changes>
</partial-response>
Though the richfaces debug messages indicate the handlers are being called:
RichFaces: Received 'success' event from <input id=uploadF:j_idt1136 ...>
RichFaces: Received 'complete' event from <input id=uploadF:j_idt1136 ...>
So, simple question: how can I get the popup to close and the components to be re-rendered?
i'm not sure if the problem is directly related to a4j:ajax or what's needed to be done to make it work with a4j:ajax, but the code below seems to work with f:ajax.
<h:form id="formId">
<h:commandLink value="popup"
onclick="#{rich:component('testPop')}.show(); return false;" />
</h:form>
<rich:popupPanel id="testPop" autosized="true">
<h:form id="uploadF" enctype="multipart/form-data">
<h:inputFile value="#{bean.file}">
<f:ajax listener="#{bean.storeFile()}" render="#form :fileListTbl"
onevent="eventHandler"/>
</h:inputFile>
</h:form>
</rich:popupPanel>
<script>
function eventHandler(event)
{
if (event.status == 'success')
{
#{rich:component('testPop')}.hide();
}
}
</script>

Flex mobile - tabbed application data http service

Flex Mobile Project
I have a tabbed application with a http service.
I would like to load the data, and once it is loaded pass it to the first tab, so the first tab can show a list with some data of the http service
I would like to use the firstViewData property of the tab (as probably on the future I will send different data to each tab)
I have tried the following but I get no data on the view :-(
On the main application
<?xml version="1.0" encoding="utf-8"?>
<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:wsdatos="services.wsdatos.*"
creationComplete="tabbedviewnavigatorapplication1_creationCompleteHandler(event)"
applicationDPI="160">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.rpc.events.ResultEvent;
public var WS:ArrayCollection;
protected function operation1():void
{
Operation1Result.token = wSDatos.Operation1();
}
protected function tabbedviewnavigatorapplication1_creationCompleteHandler(event:FlexEvent):void
{
operation1();
}
protected function wSDatos_resultHandler(event:ResultEvent):void
{
WS = event.result as ArrayCollection;
}
]]>
</fx:Script>
<s:ViewNavigator label="Home" width="100%" height="100%" firstView="views.HomeView" firstViewData="{WS}"/>
<s:ViewNavigator label="Publicidad" width="100%" height="100%" firstView="views.PublicidadView"/>
<s:ViewNavigator label="Eventos" width="100%" height="100%" firstView="views.EventosView"/>
<fx:Declarations>
<s:CallResponder id="Operation1Result"/>
<wsdatos:WSDatos id="wSDatos" result="wSDatos_resultHandler(event)"/>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:TabbedViewNavigatorApplication>
On the home view
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Home">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:List width="100%" height="100%" dataProvider="{data}" labelField="Nombre"/>
</s:View>
I am just new in Flex so I am probably missing basic concepts...
Any help on how to pass the data ?
The sample below works really fine on a not tabbed application, I just use navigator.pushView(views.HomeView event.result as ArrayCollection); on the function wSDatos_resultHandler (No need to use the var WS)
So I am trying to do somehting similiar on a tabbed application
Thanks!
One thing you'll need to do is mark your variable WS as [Bindable]. Without this, there is no notification sent when the data changes.
What's happening is that the view is created and the data from WS (initially unspecified) is used to display; then the HTTP request populates the WS return value, but since it's not marked Bindable the view isn't notified to update.