Suitescript Matrix Item cant get record ID - suitescript

im testing out an after submit event on a matrix item.
I can see in my logs its reporting as an inventory item, however there is no internal ID unlike all the other records I have tested this against.
function afterSubmit(type)
{
var recType = nlapiGetRecordType();
var recId = nlapiGetRecordId();
dLog('matrix id',recId);
}
recId is always blank....
dLog() is a function we use to make it easier to log to the netsuite log files

I see nothing wrong. I tried that on a matrix item myself and worked fine. I suggest checking dLog or using normal debug statements.

It will not give record id on aftersubmt.. because items are created after the click of 'create matrix items'. Matrix items does not support aftersubmit event. If want to do scripting on matrix items, you have to write a scheduled script.

Related

GSuite Appmaker - how to set default value in table using button

I am trying to put together a mock up for a data collection app for a local nonprofit using GSuite's AppMaker. So far I really like the tool.
One thing I need to be able to do is streamline the data entry for the site representatives. In my app, I display a list of students in a table, where one of the columns is a boolean value which represents attendance. The desired result is for the teachers to be able to input the date field one time using the date input button at the bottom of the page. Then they can quickly point and click down the Present column to log attendance.
My question is: how would I link the date selector dropdown so that the date field pre-populates with the selected date from the input field? I don't want them to have to enter the field over an over again since its the same for each row and I don't want the user experience to feel clunky.
Screenshot of the App for reference:
Using client script, you can add the following to the onValueEdit event handler of the date widget at the bottom.
var items = widget.root.descendants.<YourTable>.datasource.items;
items.forEach(function(item){
item.<DateField> = newValue;
});
The only thing to take into account is that when using client scripting, you will only update the records loaded in the table at the moment; i.e, if your table has paging, it will only update the current page. If you are using paging, then you will need to add the following code to the onPreviousClick and the onNextClick event handlers of the pager widget:
var selectedDate = widget.root.descendants.<YourDatePicker>.value;
var items = widget.root.descendants.<YourTable>.datasource.items;
items.forEach(function(item){
item.<DateField> = selectedDate;
});

In App Maker, how do you make dynamic table cell text?

In App Maker, I am displaying a table and want to replace table cell data with different text using a data lookup from another table. Assume two tables, Departments and Employees.
Departments is two fields, DeptID and DeptDescription.
Employees is multiple fields including DeptID.
In the table listing for Employees, I would like to replace the DeptID with the DeptDescription. (The page datasource is Employees. I do not want to set up a relationship between the data models.)
I am guessing I want to do some scripting in the onDataLoad event for the table cell label for DeptID. I have this much so far:
app.datasources.Departments.query.filters.DeptID._equals = widget.datasource.item.DeptID;
app.datasources.Departments.newQuery().run();
widget.text = app.datasources.Departments.item.DeptDescription;
I know this is not correct, but am I close?
This answer is untested, but I wanted to present a possible solution that would not require a lot of DB calls, especially ones that make repeated calls to a server script which might consume a lot of processing time when you do line item calls.
Set up a separate datasource under the Department model. Change the default 'Query Builder' to 'Query Script' and add a parameter of type 'list(number)' or 'list(string)', this should match your Primary Key field type. Uncheck the 'auto load' option.
In your 'Query Script' portion enter the following code:
query.filters.Id._in = query.parameters.YourParameter;
return query.run();
Go to your Employees datasource that is supposed to generate your table and find your 'On Load' client script section. In this section enter the following code:
var departmentsDs = app.datasources.YourDepartmentsDs;
departmentsDs.properties.YourParameter = datasource.items.map(function(deptIds) {return deptIds.DeptID;});
departmentDs.load();
Now go the page that contains your table. If you have not already create a label widget do so now. In this label widget for the text binding enter the following:
#datasources.YourDepartmentsDs.loaded && (#datasources.YourDepartmentsDs.items).map(function(Id){return Id.Id}).indexOf(#widget.datasource.item.DeptID) !== -1 ? #datasources.YourDepartmentDs.items[(#datasources.YourDepartmentsDs.items).map(function(Id){return Id.Id}).indexOf(#widget.datasource.item.DeptID)].DeptDescription : 'Unable to retrieve Dept Description'
As stated this is untested and I wrote the code from memory without App Maker in front of me so it may require some additional tweaking. Going with the first option presented by J.G. would also be a very viable solution though. And I apologize but the code formatter does not seem to be working for me.
1 way) Create an aggregate table that joins your tables if you need to bypass using the relations feature. This way you can use sql to join the two tables in the datasource definition
2) if you don't want to make a new table. Change the text from a value binding to "more options"
=getDescription(#datasource.item.DeptId)
and then the code you wrote in a client side script
function getDescription(id){
google.script.run
.withSuccessHandler(function successHandler(result){ return result;})
.withFailureHandler( function failureHandler(e){ console.log(" Failed" +e);})
.queryValue(id);
}
server side script:
function queryValue(id){
var query = app.models.Departments.newQuery();
query.filters.DeptID._equals = id;
var results = query.run();
return results[0]["DeptDescription"];
}
that last line might be results[0].DeptDescription

Dynamics AX 2012 - Grid Control linkPhysicalTableInstance to TempTable, first record inserted doesn't appear in Grid, fine afterwards

The problem related to using table buffers in AX 2012 with Grid Controls, where first time additions to the form's tempDB were not displayed in real time (but were persistent and subsequent additions worked fine thereafter).
I resolved the problem with help from DAX legend Martin Dráb and Brandon Weise on the Dynamics Community MSDN but I'm posting on SO in case it helps others (as I couldn't find anything close), and I don’t think it hurts the community to add more Dynamics AX content on SO. There are also some learnings to be had about how physical tables link to tempDBs and their relationship to the form's datasource.
Original thread: https://community.dynamics.com/ax/f/33/t/225120
Problem:
I have a Wizard that generates a new form at runtime, containing a Grid Control.
The Wizard passes a reference to one of its temp Tables to the form, in which I use linkPhysicalTableInstance in the runtime form's datasource init() method.
The GridControl has an add new record button, which inserts records in to the tmp table reference.
The new record is saved to the reference temp table correctly, and displays in the grid when the runtime form is closed and reopened but does not display in the grid immediately after the insert.
To add to the weirdness, after a runtime form has been created, a record inserted and then closed, subsequent run time forms do display new record insertions immediately, without needing to be re-opened. Some code snippets below.
Why does this behavior only happen for the first time that data is inserted in to the temp table, but displays fine for subsequent runs of the runtime form?
Creating the runtime form:
args = new Args(formstr(RunTimeFormName));
formRun = classFactory.formRunClass(args);
formRun .parmRuntimeFormsGridTmpDS(sysWizard.ReferenceToWizardsTableTmp()); // Passing a reference for Wizards tmpTable to form
formRun .init();
formRun .run();
formRun .wait();
formRun .detach();
RunTime Form's parmDataSourceMethod:
public void parmRuntimeFormsGridTmpDS(CommentsGridTmp _ReferenceToWizardsTableTmp)
{
ReferenceToWizardsTableTmp = _ReferenceToWizardsTableTmp;
}
DataSource init() method:
public void init()
{
super();
RuntimeFormsGridTmpDS.linkPhysicalTableInstance(ReferenceToWizardsTableTmp);
}
RunTime Form's New button clicked method:
void clicked()
{
int64 numRows;
;
// Refresh records loaded in grid DS to ensure correct number of records for setting initial index number
// Note: SomeId is passed in Args() record, its passing fine as is the number of rows count - and replacing with a static value has no effect.
select count(RecId) from ReferenceToWizardsTableTmp
where ReferenceToWizardsTableTmp.SomeId == someId;
numRows = ReferenceToWizardsTableTmp.RecId;
ReferenceToWizardsTableTmp.Comment = "Comment " + int642str(numRows + 1);
ReferenceToWizardsTableTmp.Filename = "";
ReferenceToWizardsTableTmp.someId = someId;
ReferenceToWizardsTableTmp.insert();
element .Task(#TaskF5);
// super();
}
So as described above, the first time that the runtime form is created and a record is inserted, it doesn't display. Reopening the form will display the inserted data fine. Also, after reopening the form any new records inserted appear in the grid in real time.
I originally supposed it had to be something to do with the linkToPhysicalTable and where the grid fields look for records to display…
By the way, if you have a better answer or explanation then please feel free to contribute.
Solution
I have a working solution whereby I run a select statement on the buffer reference prior to the linkPhysicalTableInstance operation (a delete_from tmptable statement has the same effect and is cheaper), which acts to initialize the buffer reference despite it being empty.
The linkPhysicalTableInstance operation then succeeds at the first run because the buffer properly exists - and changes written to the form DS are now persistent and reflected in the calling Wizard's buffer reference.
In Addition (from Brandon Weise):
In case you happen to be jumping tiers in your code, here's a small gotcha to watch out for.
https://community.dynamics.com/ax/b/dynamicsaxexperience/archive/2016/01/24/2012-unexpected-degeneration-of-insert-recordset-into-tempdb-buffer
Techniques That I Found Useful for Investigation
(Credit to Brandon Weise and Martin Dráb for these)
It does seem that using .linkPhysicalTableInstance(..) to change the underlying temp table associated with a form datasource after it
has already initialized produces some weird behavior. This seems to
be true even when you can demonstrate with .getPhysicalTableName()
that they are linked properly.
One technique to help is to create your form, and
call .init(), but not yet .run(). Then use
.linkPhysicalTableInstance() to link the freshly created temp table
underlying the data source to your external temp table buffer. In
other words, instead of trying to transplant your already created
temp table into the form's data source, let the form create the temp
table, then let the caller transplant that temp table into its own
buffer using .linkPhysicalTableInstance(). Then insert records,
then call .run(). If necessary, call .executeQuery() on the form
data source after .run().
I took a scattergun approach to printing
the table names throughout initialization and operation, and while
the two tables do eventually link correctly with the same table
name, they take a roundabout way of getting there.
Inspect the contents of a temp table while debugging, from SQL Server Management Studio using:
set transaction isolation level read uncommitted;
select * from tempdb..t107946_BE044A13A9C24283897CA1B59607CBD2;
Which is easy if you have the table name from
.getPhysicalTableName(), but even if you don't know it precisely,
it's often easy to locate with a little trial and error. select *
from tempdb.sys.tables; The table will of course start with "t" and
the table number. Often it's the most recently created one, so
sorting by create_date desc floats it to the top, but of course
there can be a pool of them.
Review Methods on a Form Data Source which methods you can use when working with records through a datasource.

reload table in WatchKit

We have a hierarchical watch app.
The root controller is a table of menu items. That list of items is controlled by a server. The data is retrieved and stored in core data. The menu is populated the first time going into the app.
But I want this table to stay current. My thought was to add code to willActivate to check if there was changes, and reload the table. In my reload logic I call the same function I called the first time, which sets the menuTable.setNumberOfRows and creates each row. Looking at what I'm putting in the logs, it is going through this logic with a different count of rows and new labels. But the app on the watch shows the table with the old data.
How can I get this table to reload with the new information?
I've had this problem too and as rmp says, it still seems to be a bug in watchOS 1.0.1. The problem appears when you try to reload your tableView after run willActivate() and nothing will happen.
In my case, I reload the tableView after receive a reply from a delegate and then I reload all the content just if it's necessary. To achieve this, I remove all rows from a NSIndexSet and load again.
if isNecessary {
self.table.removeRowsAtIndexes(NSIndexSet(indexesInRange: NSMakeRange(0, maxItems)))
isNecessary = false
}
I've tried a lot of tricks but none has worked for me:
Force to reload rows by table.setNumberOfRows(0, withRowType: "data")
Setting parameters to empty text before assign new values
One thing you could do is to hide tableView before removing rows, and avoid the remove animation.
It is a bug in WatchKit. Seems like Apple doesn't handle the repetitive interface object correctly.
The general principle here is: Only insert or remove necessary rows after a table is created. Do not reload the whole table like what we usually do in iOS. It just doesn't work (or trigger the bug).
So specifically, you have to:
Do this in willActivated method. This is correct.
If this is the first load, before the table is even created, do what you are now doing – load all table rows.
For all following times, don't reload the table, fetch the new data and check the desired number of rows.
Compare with the current number of rows in the table, insert to or remove from the bottom of the existing table.
Now simply re-assign the new data to all existing rows. Again, do not reload.
It should work if you follow the above steps.
I have found what works best given the current state of watchkit is to remove all rows then re-populate the table.
Try something like this:
- (void)loadTableData{
//clear the table
[mainTableView setNumberOfRows:0 withRowType:#"myTableRow"];
//set the row count again
[mainTableView setNumberOfRows:numberOfRows withRowType:#"myTableRow"];
//populate table
}
Its pretty simple. As Apple hasn't provided any method to reload the data.
You can still achieve that by simply populating the rows for the tableview.
Below is the sample code:
for index in 0..<tracksTableView.numberOfRows {
if let controller = tracksTableView.rowController(at: index) as? EditPlaylistRowController {
controller.playingTrackId = self.playingTrackID
controller.sharedTrack = trackItems[index]
}
}
Use it whenever you want to refresh the data.
NOTE:
You can still make some conditional statements inside the row controller class.
Happy to help :)

Collect all parameters from all reports in reportserver folder and populate a sql table

[Thanks to Filburt and Devjosh. I have restructured the post and included my attempt approach. ]
I have a table on my SQL DB call ReportList which is a list of report. I need to go through that list and interrogate the reportserver, eport by report, to populate a table called ReportParameters. The ReportParameters table has a column for ReportOwnerID which needs to contains the ReportID value of the corresponding (owner) report as listed in the ReportList table.
This is in VB.NET 2005 ASP2.0 and I have ended up with a mess. Please help me with the cleanest approach to doing this.
It needs to work so:- I have a listbox of the reports as per REportList and a GridView that list all the parameters (uniquely - most of the parameters are common to many reports) the idea being that the parameters get set once and the report can be kicked off by selecting them in the ReportList CheckListBox and clicking on Execute.
I would like it that as I click on a particular report in the ListView, the relevant parameters in the Gridview get a green background and those that do not apply are red. The leftmost column in the gridview contains tha Parameter NAME (not editable) and the next column must be editable to populate the value.
DONE SO FAR:
I have tried on clicking the EXECUTE button , to build a parameters string in a testbox and call that with the Javascript OpenReportWin() function when I open the report in a new window. This works fine, but my biggest issue it interrogating the reportserver reports to get back a list of parameters and dooping them into a table. I have triend to use a hidden DataGrid bound to a ds onto the reportParamaters table; I have tried to poulate it using a datalist but I cannot get the hang of these thionsg and its looking messy. Ther must be a simple clean way of gettting the .GetParameters resultset back from the report server and populating the table without having to create a reportviewer object and cycling through the list of reports - it then has to render each report before you can get that list out.
Thanks
I will withdraw this for now. I will submit a solution when I am comfortable that I have reahced a clean solution.
Mac
PLEASE CLOSE!!!

Resources