Function Recursion

Still trying to move heavy Classic UI code to Function Library so it will operate within the Kinetic Web Interface
Widgets operate on Tablesets and I need to process individual rows within a table. based upon conditions on the row, the row data may be passed back into the current function. So can I call the code function processing the rows from within the code?

Example:
processDT(DataTable myDT)
foreach (DataRow myDR in myDT.Rows)
{
if (condition is met)
{
processDT(DataTable returned from yet another function)
}
}

You can call a function inside of a function, is that what youā€™re asking?

Need to call within custom code block in a function

Or ā€“ can I call BO methods from custom code block

Yeah, you can do this within custom code in a function. You can either call another function or a BO within your code in the function. The preferred approach is probably using another function so you can do it as widget-y as possible, but thatā€™s your call.
The primary function library will be your function. Create another function library that acts as an ā€œinternalā€ library and add it to your primary function library as a reference. Then, inside your code block, you can invoke the internal library function method

1 Like

Iā€™m with Aaron, I needed to do a loop so I used a custom code block to start the loop, but had the custom code block call a function in the loop so I can be as widget-y as possible.

1 Like

Could you post some example code showing how?
Without giving away trade secrets of courseā€¦

Here is one I am working on this morning.

I need to run a function to add receipt lines for the amount of vendor lots that come in a shipment. We place the PO in linear feet and receive it in linear feet on the receipt entry, but what is shipped to us are 10 rolls of material at 1000 linear feet each. So we need to receive the product 10 times to generate 10 different lot numbers.

To speed this up I created a form customization for the user to put in how many lots need to be created or in other words, how many receipt lines need to be created. Instead of having them click new lot receipt or new line 10 times, I have them click a button that does that for them X amount of times- as specified.

Here is the loop that I am using to call a function over and over until it matches the amount of lots/lines they needed created.

image

for(int x = 0; x < NumberOfLots; x++)
  {

      this.InvokeFunction("POLinesPerLot", "AddPOLine",/*Company*/"GFI", /*PONum*/0, POLine, PORel, NumberOfLots, QtyPerLot, PackSlip, VendorNum,Reference,"","" );
  }

boDynamicQuery.Dispose();
1 Like

Ainā€™t no trade secrets here my friend, this is peer to peer help.

@utaylor nice answer :slight_smile:

2 Likes

IN this code line, isOdd is a boolean, num is an integer the function returns a boolean:
isOdd = this.InvokeFunction(functionLibrary,function , ( num + 1));

This is code within the code block of another function, error I get is:

Cannot implicitly convert type ā€˜object[]ā€™ to boolean

Also tried it within the code block of a standard data directive.

Am I possibly missing a using?

might need an explicit conversion of the function return. That method, ā€œInvokeFunctionā€ has no idea what if anything will be returned from your dynamic call to that function library/ function. By implicitly casting the result to a bool, the compiler is fussy. Try putting

isOdd =  (bool) this.InvokeFunction(functionLibrary,function , ( num + 1));
1 Like

I ran into this as well. If you want to do something a little closer to what you original posted you can create a stub function. That function sole job is to call the other function and return the results. I donā€™t like doubling the stack of functions called but it does appear to work in testing. It has not gone live yet, as i need to add a fail safe incase someone creates a BOM saying all you need to create a PartA is a PartA.
Example IsAssemblyMaterial:

var asBom = (from r in Db.ECOMtl where r.PartNum == AsPartNum && r.MtlPartNum == MtlPartNum select r).ToList();
if(asBom.Count()>=1){
  IsMaterial = true;
  return;
}
var asSubBom = (from r in Db.ECOMtl from x in Db.Part where r.PartNum == AsPartNum && x.PartNum == r.MtlPartNum && x.TypeCode == "M" select r).ToList();
foreach(var bomrec in asSubBom){
  IsMaterial = this.ThisLib.IsAssemblyMaterialRecur(bomrec.MtlPartNum,MtlPartNum);
  if(IsMaterial) return;
}

Example IsAssemblyMaterialRecur:
IsMaterial  = this.ThisLib.IsAssemblyMaterial(AsPartNum,MtlPartNum);

For both functions AsPartNum and MtlPartNum as string input parameters and IsMaterial is a Boolean output parameter.

They may fix not being able to call the same function you are in, in later version so it may be worth testing but version 11.1.200.0 did not allow it.

Since this came up in a search, Iā€™ll answer this old post :rofl:

Functions return an array of objects, get the object index, and cast appropriately.

isOdd = (bool)this.InvokeFunction( functionLibrary, function , ( num + 1) )[0];

1 Like