Birt: access content of dataset from beforeFactory - javascript

Im trying (desperately) to access the content of a dataset by script in the beforeFactory.
The task at hand is to create design elements from a linked library and place them in a certain cell of a grid. Everything works fine except for the "place them in a certain cell of a grid"-part.
The information about which element is to be created and where it is to be placed is available in a dataset (dsDesignInformation), which contains three columns: targetRow, targetColumn, targetContent. targetContent contains a string, which is used to find an element in the library.
For example: There is a grid placed on the body (grdMasterGrid), with two rows and two columns. If the dsDesignInformation would contain a row like (1,1,"testObjectName"), I want to create the element "testObject" from a linked library and place it in the intersection of row 1 and column 1 of my grdMasterGrid.
The code for creating and placing the element:
importPackage(org.eclipse.birt.report.model.api);
var myLibraryHandle = reportContext.getDesignHandle().getLibrary("myLibraryName");
var myElementFactory = reportContext.getDesignHandle().getElementFactory();
// should be the objectname as defined in the dsDesignInformation
var myTargetElementHandle = myLibraryHandle.findElement("testObjectName");
var myCreatedElementHandle = myElementFactory.newElementFrom(myTargetElementHandle , "someUniqueElementName");
var myMasterGridHandle = reportContext.getDesignHandle().findElement("grdMasterGrid");
// should be target coordinates as defined in dsDesignInformation
var myTargetCellHandle= myMasterGridHandle.getCell(1,1);
myTargeCellHandle.getContent().add(myCreatedElementHandle);
This works like a charm when used with hard coded target-information and placed in the beforeFactory of the report design.
I do however need to access the contents of dsDesignInformation and pass them on to the script above. So far (4 days in) I had zero (as in null) success.
I would be glad for any help or ideas on the topic.
Regards,
maggutz

It is possible to do this, but with some severe restrictions.
The main restriction is: You cannot use your DataSource and your DataSet directly.
Instead, you'll have to copy them and work with the copy.
Don't ask my why this is, because I don't know. But I learned it the hard way during hours and days of trying...
The next restriction is: You cannot access report parameter values, unfortunately. This is not a problem if your query works without parameters.
Otherwise, you'll have to find a way to access the parameter value anyhow. Depending on how your report is integrated into the app, you could try writing the value into the appContext before calling BIRT, for example.
Here is a fragment of working code (in the beforeFactory event) to show you how to workaround this limitation:
importPackage( Packages.org.eclipse.birt.report.model.api );
importPackage(Packages.org.eclipse.birt.data.engine.api);
importPackage(Packages.org.eclipse.birt.report.model.api);
importPackage(Packages.org.eclipse.birt.data.engine.api.querydefn);
importPackage(Packages.org.eclipse.birt.data.engine.core);
importPackage( Packages.org.eclipse.birt.report.model.api );
var myconfig = reportContext.getReportRunnable().getReportEngine().getConfig();
var de = DataEngine.newDataEngine( myconfig, null );
var dsrc = reportContext.getDesignHandle().findDataSource("lisa");
// This is the existing data source.
var odaDataSource = new OdaDataSourceDesign( "Test Data Source" );
// We create a new DataSource which is only to be used in this event
// Now we copy the relevant properties from the existing DataSource to the new one.
var dbUrl = dsrc.getProperty("odaURL").toString();
var dbUsr = dsrc.getProperty("odaUser").toString();
var dbPwd = dsrc.getProperty("odaPassword").toString();
var dbDrv = dsrc.getProperty("odaDriverClass").toString();
odaDataSource.setExtensionID( "org.eclipse.birt.report.data.oda.jdbc" );
odaDataSource.addPublicProperty( "odaURL", dbUrl );
odaDataSource.addPublicProperty( "odaDriverClass", dbDrv);
odaDataSource.addPublicProperty( "odaUser", dbUsr );
odaDataSource.addPublicProperty( "odaPassword", dbPwd );
// log.info("odaURL=" + dbUrl); // Only if you have a logging framework at hand
// Now create a new DataSet and set its query etc.
// I suppose that it is possible to copy the properties from an existing DataSet instead.
// However, I didn't try that.
var odaDataSet = new OdaDataSetDesign( "Test Data Set" );
odaDataSet.setDataSource( odaDataSource.getName() );
odaDataSet.setExtensionID( "org.eclipse.birt.report.data.oda.jdbc.JdbcSelectDataSet" );
// This is the SQL query (in my application).
// You'll have to modify this as needed.
odaDataSet.setQueryText( " select STEDA.TEDA_ID, STBST.LANGTEXT" +
" from STEDA, STBST" +
" where STEDA.ZUSATZ_1 = 'MATRIX'" +
" and STBST.TBST_ID = STEDA.TEDA_ID");
// Tell the DataEngine about the new objects.
de.defineDataSource( odaDataSource );
de.defineDataSet( odaDataSet );
// Now execute the query:
// This seems overly complicated, but hey: it works.
var queryDefinition = new QueryDefinition( );
queryDefinition.setDataSetName( odaDataSet.getName() );
queryDefinition.setAutoBinding(true);
var pq = de.prepare( queryDefinition );
var qr = pq.execute( null );
rowcount=0;
var elementFactory = reportContext.getDesignHandle().getElementFactory()
var ri = qr.getResultIterator( );
// Our application is using the query to generate a layout structure
// into an (already existing) placeholder element "Layout MATRIX".
var containerGrid = reportContext.getDesignHandle().findElement("Layout MATRIX");
// Iterate through the query results
while ( ri.next( ) )
{
// get the actual values of the query output columns
var tedaId = ri.getString("TEDA_ID");
var langtext = ri.getString("LANGTEXT");
// log.info("langtext: " + langtext);
rowcount++;
// Do something with the current result row.
... myModifyLayout(containerGrid, tedaId, langtext); ...
}
// Cleanup
ri.close( );
qr.close( );
de.shutdown( );
// You may want to save the modified design file while developing.
// That way you can check the mresults in the Report Designer.
if (false) {
reportContext.getDesignHandle().saveAs("c:/temp/modified.rptdesign");
}

Related

Can I use two parameter event for one function?

What I want to do is change the url.
Replace the Object word with an event parameter called e1.
Replace the word field with the event parameter e2.
I know this code is not working.
But I don't know how to do it.
The following is my code that I just wrote.
function getAllFieldValue(e1,e2) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var url = 'test123.my.salesforce.com/services/data/v44.0/queryAll?q=SELECT Field FROM Object';
var url = url.replace('Object',e1);
var url = url.replace('Field',e2);
var response = UrlFetchApp.fetch(url,getUrlFetchOptions());
var json = response.getContentText();
var data = JSON.parse(json);
var fieldValues = data.records;
for(var i=0;i<fieldValues.length;i++){
var fieldValue = fieldValues[i].e;
ss.getRange(i+1,1).setValue(fieldValue);
}
}
I want to take the data from another database through this code and put it in the Google spreadsheet.
For e1, it means the object value selected in the dropbox.
For e2, it means the field of the object selected in the drop box.
Is there a way to use two event parameters for one function?
I look forward to hearing from you.
====================
Please understand that I am using a translator because I am not good at English.
Checking fieldValues[i] in Logger.log returns the following values:
[{
attributes={
type=Account,
url=/services/data/v44.0/sobjects/Account/0015i00000BS03VAAT
},
Name=University of Arizona
},
{
attributes={
type=Account,
url=/services/data/v44.0/sobjects/Account/0015i00000BS03TAAT
},
Name=United Oil & Gas Corp.
},
{
attributes={
type=Account,
url=/services/data/v44.0/sobjects/Account/0015i00000BS03ZAAT
},
Name=sForce
}]
The issues I am currently experiencing are as follows.
If I select 'Name' from the drop-down list, ec2 becomes 'Name'.
As far as I'm concerned,
var fieldName = fieldValues[i].e2 is
var fieldName = fieldValues[i].Name
It means that.
I think fieldValues[i].e2 should return the values of University of Arizona, United Oil & Gas Corp, sForce.
But in reality nothing is returned.
var fieldName = fieldValues[i].Name works properly.
I think there is a problem with fieldValues[i].e2
This is the problem I'm currently experiencing.
There was no problem with the parameters e1, e2, which I thought was a problem. The reason why the code did not work is because of the for loop var fieldValue = fieldValues[i].e; Because it didn't work properly.
var fieldName = fieldValues[i].e2
to
var fieldName = fieldValues[i][e2]
After modifying it like this, the code works properly.

JavaScript - create links from user data provided in HTML textarea

What I'm trying to do is, dynamically create clickable links from user provided textarea data, first being saved to the local machine using localStorage. User data is provided in the following format:
a|aa,
c|cc,
e|ee,
a,c,e are the labels for the links
aa,cc,ee are the links themselves
example of final output:
<a href="aa" />a</a>
<a href="cc" />c</a>
<a href="ee" />e</a>
Step 1: Save data to localStorage in a format that will later be used to create 2 separate arrays.
This is what I've done so far for step 1 (not sure it's correct)
// remove white space and carriage returns
textToSave = textToSave.replace(/(\r\n|\n|\r)/g,"").trim();
// replace | from user data with =>
var textToSaveArrayFormat = textToSave.replace(/(\|)/g, "=>");
// store data to localSorage
localStorage.setItem("appLinkConfig" ,JSON.stringify(textToSaveArrayFormat));
Step 2: Retrieve data from localStorage and create 2 arrays from that data
URLLabels = ["a", "b", "c"];
URLOptions = ["aa", "bb", "cc"];
For step 2 I start with
// get local storage app link config data
var appLinksObj = JSON.parse(localStorage.getItem("appLinkConfig"));
console.log(appLinksObj);
which returns
a=>aa,c=>cc,e=>ee,
From this I need to create my 2 arrays and this is where I'm stuck.
Step 3: I'm currently doing this with hardcoded arrays in my script, but would like to do it with the array data created in step 1 and 2.
// Object created
var obj = {};
// Using loop to insert key
// URLOptions in Object
for(var i = 0; i < URLLabels.length; i++){
obj[URLLabels[i]] = URLOptions[i];
}
// Printing object
for (var URLLabels of Object.keys(obj)) {
lnk.innerHTML += "<a href=\'" + URLLabels + "' target\='" + hotDeck + "'\>" + obj[URLLabels] + "</a>";
}
hotDeck is a flag I'm using to target one of two frames (returns the ID of those frames) contained in the page.
Thanks in advance for your help - please be gentle, I've been away from coding for a long time due to illness and coding again now to help my recovery. I'd be very grateful to solve this problem.
I assume this is what you are expecting. try the snippet on the console as i am not able to aceess localStorage property in the code snippet
var input = 'a|aa, c|cc, e|ee';
var output = input.split(',').map(str => str.split('|'));
window.localStorage.setItem('appLinkConfig', JSON.stringify(output));
var config = JSON.parse(window.localStorage.getItem('appLinkConfig'));
var result = config.map(([text, href]) => `${text.trim()}`).join(' ')
console.log(result);

Autodesk Forge How to get dbid from name

I have an extension which loads a docking panel with a text field and a button. The functionality of this button would be to display the DB-ID of the item name given in the text field.
Something like:
Rubber = 2130
where Rubber is the input and 2130(db-id) will be the output
How can I achieve this?
Thanks in advance.
Would suggest using .search() method, which is a supported way:
viewer.search('Rubber', function(dbIds){
// here the dbIds is a list of dbIds, you can handle it
callback(dbIds); // handle the results async
}, function(error){
// handle errors here...
}, ['name'] /* this array indicates the filter: search only on 'Name'*/
)
And look here on how to improve performance on search.
There is no such API available currently, but a workaround can be used in this case. It's shown as the following:
//-- For the element type or element category like "Floor [" or "Floor"
var it = viewer.model.getData().instanceTree;
var strIdx = it.nodeAccess.strings.indexOf( "Floor [" );
// var strIdx = it.nodeAccess.strings.indexOf( "Floor" );
var nameIdx = it.nodeAccess.names.indexOf( strIdx );
for( var key in it.nodeAccess.dbIdToIndex ) {
if( it.nodeAccess.dbIdToIndex[key] === nameIdx ) console.log( key )
}
//-- For element name like "Floor[766598]":
var it = viewer.model.getData().instanceTree;
var eidIndex = it.nodeAccess.nameSuffixes.indexOf( 766598 );
for( let key in it.nodeAccess.dbIdToIndex ) {
if( it.nodeAccess.dbIdToIndex[key] === eidIndex ) console.log( key )
}
P.S. Since this is just a workaround, not the formal solution. You would have to use it at your own risk.
If you want to avoid using the search() method, you could also create your own Object that maps the name to ID's. This is a temporary workaround until Autodesk implements its own method.
var instanceTree = viewer.model.getData().instanceTree; // Get model tree
var allDbIds = Object.keys(instanceTree.nodeAccess.names); //get array of all ID's
var forgeNameMap = {} //Empty array for mapping names
allDbIds.map(function(id) {
forgeNameMap[instanceTree.getNodeName(id)] = id
})
let rubberID = forgeNameMap["Rubber"]

Parse.com issues while querying array of pointers, .include not getting nested pointer data in cloud code

I am having trouble getting data from the nested pointers in my array of pointers from a query. I have an array of pointers like so: [{"__type":"Pointer","className":"QuizData","objectId":"rmwJrV55c7"},{"__type":"Pointer","className":"QuizData","objectId":"2132q8i9np”}, etc…]
That QuizData class also has a column named “ad” which is a Pointer to the “Ads” class. I can get the QuizData in a query using the following include statements on my query like so:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include("quizAdArr”);
__quizAdQueueQuery.include(["quizAdArr.QuizData"]);
BUT Neither of these or both combined don’t work as when I try to get column data from the ad it’s always undefined:
__quizAdQueueQuery.include(["quizAdArr.QuizData.ad"]);
__quizAdQueueQuery.include(["quizAdArr.QuizData.Ads"]);
This is my return from that query, where the column data "mediaType" that I am trying to access is always undefined:
return __quizAdQueueQuery.first().then(function(__resultsObj)
{
__quizQueueObj = __resultsObj;
__userQuizQueueArr = __quizQueueObj.get("quizAdArr");
var __quiz;
var __ad;
var __seenAd;
var __lengthInt = __userQuizQueueArr.length;
var __mediaTypeStr = __request.params.mediaType;
var __matchedQuizzesArr = [];
for (var __i = 1; __i < __lengthInt; __i++)
{
__quiz = __userQuizQueueArr[__i];
// console.log('__quiz.get("name") = '+__quiz.get("name"));
__ad = __quiz.get("ad");
// console.log("__ad.id = "+__ad.id);
//THE MEDIA TYPE IS ALWAYS RETURNING UNDEFINED HERE!!!
console.log('__ad.get("mediaType") = '+__ad.get("mediaType")+', __mediaTypeStr = '+__mediaTypeStr);
if (__ad.get("mediaType") == __mediaTypeStr)
{
//put all matches in array to be sorted
__matchedQuizzesArr.push(__userQuizQueueArr[__i]);
console.log("__matchedQuizzesArr.length = "+__matchedQuizzesArr.length);
}
}
return __matchedQuizzesArr;
});
Thanks for any help you can give! I also posted this as a bug in the Parse/Facebook issue reporter but was redirected here, so if this is a bug I can reopen it: https://developers.facebook.com/bugs/923988310993165/
EDIT Here is the updated, working query with nested includes for clarity:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include('quizAdArr');
__quizAdQueueQuery.include('quizAdArr.ad');
This should work (you only need to list the column names):
query.include('quizAdArr.ad');
Here's why:
You're querying QuizAdQueue so you don't need to list that
The QuizAdQueue class has an array in quizAdArr so you include it: query.include('quizAdArr');
Each quizAdArr element is a QuizData with an ad so you include it: query.include('quizAdArr.ad');
The issue was that you were including QuizData which is the name of a class and not a column name

Alfresco: update data list line

I have data being sent to a custom data list from the following code:
// Get the site name and dataLists
var site = siteService.getSite("Testing");
var dataLists = site.getContainer("dataLists");
// Check for data list existence
if (!dataLists) {
var dataLists = site.createNode("dataLists", "cm:folder");
var dataListProps = new Array(1);
dataListProps["st:componentId"] = "dataLists";
dataLists.addAspect("st:siteContainer", dataListProps);
dataLists.save();
}
// Create new data list variable
var orpList = dataLists.childByNamePath("orplist1");
// If the data list hasn't been created yet, create it
if (!orpList) {
var orpList = dataLists.createNode("orplist1","dl:dataList");
// Tells Alfresco share which type of items to create
orpList.properties["dl:dataListItemType"] = "orpdl:orpList";
orpList.save();
var orpListProps = [];
orpListProps["cm:title"] = "Opportunity Registrations: In Progress";
orpListProps["cm:description"] = "Opportunity registrations that are out for review.";
orpList.addAspect("cm:titled", orpListProps);
}
// Create new item in the data list and populate it
var opportunity = orpList.createNode(execution.getVariable("orpWorkflow_nodeName"), "orpdl:orpList");
opportunity.properties["orpdl:nodeName"] = orpWorkflow_nodeName;
opportunity.properties["orpdl:dateSubmitted"] = Date().toString();
opportunity.properties["orpdl:submissionStatus"] = "Requires Revisions";
opportunity.save();
This correctly creates data list items, however, at other steps of the workflow require these items to be updated. I have thought of the following options:
Remove the data list item and add another with the updated information
Simply update the data list item
Unfortunately I have not found adequate solutions elsewhere to either of these options. I attempted to use orpWorkflow_nodeName, which is a unique identifier generated at another step, to identify a node to find it. This does not seem to work. I am also aware that nodes have unique identifiers generated by Alfresco itself, but documentation doesn't give adequate information on how to obtain and use this.
My question:
Instead of var opportunity = orpList.createNode(), what must I use in
place of createNode() to identify an existing node so I can update its
properties?
You can use this to check existing datalist item.
var opportunity = orpList .childByNamePath(execution.getVariable("orpWorkflow_nodeName"));
// If the data list Item is not been created yet, create it
if (!opportunity ) {
var orpList = orpList .createNode(execution.getVariable("orpWorkflow_nodeName"),"dl:dataList");}

Categories