I am currently working with the Apex Office Print it would be nice if you could help me with two points.
I am creating a template with a lot of fields, and around 50% of
these fields are optional, so they are often only (null) in my
database. Can I do something so that the fields with no value are not
shown?
My second question would be the work with the print function and
checkboxes. How do I integrate the item APEX_APPLICATION.G_F01 so
that I only print the content of a selected checkbox ? It is not
really working in the PL/SQL section.
I am creating a template with a lot of fields, and around 50% of these fields are optional, so they are often only (null) in my database. Can I do something so that the fields with no value are not shown?
The {tag} will just be removed when it's empty. In case you want to make some blocks disappear you can wrap that in a condition,
for example:
{#tags=null} {product_name}: {product_description} {/tags=null} {#tags!=null} {product_name}: {tags} {/tags!=null}
or if you have a value:
{#checked=="Yes"}☒Yes ☐No{/checked=="Yes"}{#checked!="Yes"} ☐Yes ☒No {/checked!="Yes"}
My second question would be the work with the print function and checkboxes. How do I integrate the item APEX_APPLICATION.G_F01 so that I only print the content of a selected checkbox ? It is not really working in the PL/SQL section.
Are you running the AOP Process type plugin or the Dynamic Action plugin?
For example we use it for ourself when selecting invoices and printing them.
We have a checkbox in an IR:
apex_item.checkbox2(
p_idx => 1,
p_value => id,
p_attributes => 'class="invoice_id"',
p_checked_values => :P39_INVOICE_ID_LIST,
p_checked_values_delimiter => ',') as chk,
And then we have a Dynamic Action on change that sets an hidden item (P39_INVOICE_ID_LIST) on the page:
var
//Checkbox that was changed
$checkBox = $(this.triggeringElement),
//DOM object for APEX Item that holds list.
apexItemIDList = apex.item(this.affectedElements.get(0)),
//Convert comma list into an array or blank array
//Note: Not sure about the "?" syntax see: http://www.talkapex.com/2009/07/javascript-if-else.html
ids = apexItemIDList.getValue().length === 0 ? [] : apexItemIDList.getValue().split(','),
//Index of current ID. If it's not in array, value will be -1
idIndex = ids.indexOf($checkBox.val())
;
//If box is checked and it doesn't already exist in list
if ($checkBox.is(':checked') && idIndex < 0) {
ids.push($checkBox.val());
}
//If box is unchecked and it exists in list
else if (!$checkBox.is(':checked') && idIndex >= 0){
ids.splice(idIndex, 1);
}
//Convert array back to comma delimited list
apexItemIDList.setValue(ids.join(','));
In our query in the AOP DA we have:
where i.id in (select regexp_substr(:P39_INVOICE_ID_LIST,'[^,]+', 1, level) invoice_id
from dual
connect by regexp_substr(:P39_INVOICE_ID_LIST, '[^,]+', 1, level) is not null)
and we make sure the P39_INVOICE_ID_LIST is set in session state by specifying the Affected Elements of the AOP plugin call.
If you setup an example of what you want to do on apex.oracle.com I'm happy to build you the example there. In AOP 4.0 we will also include an example with checkboxes.
Hope that helps,
Dimitri
Related
I have an Apex Tabular form:
ID Name Title Class ROW_EDIT <br>
1 Smith Mgr AP (checkbox)<br>
etc...
I am trying to activate the 'checkbox' ROW_EDIT column - which has a default value of Y - when the user changes the value for the tabular form column Class (Select list) in the same row. I can change the ROW_EDIT attribute to text (ie, Y) if easier...
I have no apex_items for the page to reference - all columns are tabular form.
I have researched some dynamic change events - but I can't seem to get the row-reference to set correctly.
Any help would be greatly appreciated.
Thanks
Unfortunately, last time I saw APEX 4.2 was 2 years ago and I don't have it now.
The idea is in the following:
Add onchange event to select list. I don't remember is there an easy way to do this. If not, you can create a select list manually using APEX_ITEM package. To do this, write in the source query:
select apex_item.select_list_from_lov (
p_idx => 10,
p_value => class, -- it is a name of a table column
p_lov => 'my_lov_name',
p_attributes => 'onchange="my_func.call(this);"')
from ...
In page properites (JavaScript section), create a javascript function:
function my_func () {
this.parentElement.parentElement.getElementsByTagName("input")[0].checked = true;
}
Parameter this in the function is a reference to select list. Hence, this.parentElement.parentElement - reference to row with the triggering select list, getElementsByTagName("input")[0] is a checkbox. If you have several input elements in the row, use proper index instead of 0.
How this JavaScript code works you can check here: https://codepen.io/anon/pen/NvPmPp
I have a set of unique items (Index) to each of which are associated various elements of another set of items (in this case, dates).
In real life, if a date is associated with an index, an item associated with that index appeared in a file generated on that date. For combination of dates that actually occurs, I want to know which accounts were present.
let
Source = Table.FromRecords({
[Idx = 0, Dates = {#date(2016,1,1), #date(2016,1,2), #date(2016,1,3)}],
[Idx = 1, Dates = {#date(2016,2,1), #date(2016,2,2), #date(2016,2,3)}],
[Idx = 2, Dates = {#date(2016,1,1), #date(2016,1,2), #date(2016,1,3)}]},
type table [Idx = number, Dates = {date}]),
// Group by
Grouped = Table.Group(Source, {"Dates"}, {{"Idx", each List.Combine({[Idx]}), type {number}}}),
// Clicking on the item in the top left corner generates this code:
Navigation = Grouped{[Dates={...}]}[Dates],
// Which returns this error: "Expression.Error: Value was not specified"
// My own code to reference the same value returns {0,2} as expected.
CorrectValue = Grouped{0}[Idx],
// If I re-make the table as below the above error does not occur.
ReMakeTable = Table.FromColumns(Table.ToColumns(Grouped), Table.ColumnNames(Grouped))
in ReMakeTable
It seems that I can use the results of this in my later work even without the Re-make (I just can't preview cells correctly), but I'd like to know if what's going on that causes the error and the odd code at the Navigation step, and why it disappears after the ReMakeTable step.
This happens because when you double click an item, the auto-generated code uses value filter instead of row index that you are using to get the single row from the table. And since you have a list as a value, it should be used instead of {...}. Probably UI isn't capable to work with lists in such a situation, and it inserts {...}, and this is indeed an incorrect value.
Thus, this line of code should look like:
Navigate = Grouped{[Dates = {#date(2016,1,1), #date(2016,1,2), #date(2016,1,3)}]}[Idx],
Then it will use value filter.
This is a bug in the UI. The index the UI calculates is incorrect: it should be 0 instead of [Dates={...}]. ... is a placeholder value, and it generates the "Value was not specified" exception if it is not replaced.
I have two columns called Quantity and Issued Quantity. I want that when I put value in Quantity column, for instance 3, the Issued Quantity will automatically generate 3. Also I want it to happen the other way around.
The example is on Purchase Order window, PO Line tab. in Quantity section. When I put 4 in Quantity field, the PO Quantity field automatically generate 4.
I try to imitate the column and field but it doesn't work.
This is accomplished in Adempiere by a Callout which is configured in what Adempiere calls the Application Dictionary
From the example you gave; updating the qty on the Purchase Order.
If you login to Adempiere using the System user, you can view and modify the Application Dictionary.
From the main menu select Application Dictionary->Table & Column.
In the Search box that opens enter C_OrderLine as the DB Table name.
Now Column tab and scroll down the list to locate the QtyEntered column. Switch to the Form view and near the end you will see were you can enter the field Callout.
You should see that the C_OrderLine.QtyEntered field already has a value "org.compiere.model.CalloutOrder.qty; org.compiere.model.CalloutOrder.amt" which indicates it should run the method qty in the class org.compiere.model.CalloutOrder followed by the method amt in the org.compiere.model.CalloutOrder class.
If you open those classes you can see how easily you can evaluate and modify values. Breaking some of of it down for you... if you open the CalloutOrder.java class you cab scroll down until you find the qty method.
public String qty (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
{
You need use the signature as above for any new callout method you create. Follow that approach and Adempiere will look after passing the correct values for you
if (isCalloutActive() || value == null)
return "";
It's good practice to start the method with the above ensure you do not open a Callout from within a Callout - which would break the Adempiere rules.
int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
Is an example of how you could extract values from the existing window... the syntax would remain the same regardless of Column/Field the you just need to enter the "M_Product_ID" which is the Field name you wish to extract to use.
Now this Callout is called by more than one Column/Field so it is littered with a big if...then...else to executed the logic needed for the relevant field. It's not pretty, but this is aimed at business developers who will concentrate more on business logic than coding principals.
The code you are interested in is
else if (mField.getColumnName().equals("QtyEntered"))
{
int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
QtyEntered = (BigDecimal)value;
BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
if (QtyEntered.compareTo(QtyEntered1) != 0)
{
log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
QtyEntered = QtyEntered1;
mTab.setValue("QtyEntered", QtyEntered);
}
QtyOrdered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
C_UOM_To_ID, QtyEntered);
if (QtyOrdered == null)
QtyOrdered = QtyEntered;
boolean conversion = QtyEntered.compareTo(QtyOrdered) != 0;
log.fine("UOM=" + C_UOM_To_ID
+ ", QtyEntered=" + QtyEntered
+ " -> " + conversion
+ " QtyOrdered=" + QtyOrdered);
Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
mTab.setValue("QtyOrdered", QtyOrdered);
}
The code
mTab.setValue("QtyOrdered", QtyOrdered);
Is where it sets the value of the other quantity field Qty Ordered.
Also, the call must not be Java. It is possible to link any [JSR223 script][3]. I never actually tried this approach myself, but it is even possible to implement Callouts using the Drools Rules Engine!
I am working on some legacy code, and I have the following wonderful issue. I am hoping some FoxPro experts can help!
The infrastructure of this legacy system is setup so that I have to use the built-in expression engine to return a result set, so no go on the SQL (i know that would be so much easier!)
Here is the issue.
I need to be able to do something like
PUBLIC ARRAY(20) ArrayOfValuesToFilterBy
SELECT dataTable
SET FILTER TO logicalField = .T. and otherField NOT INLIST(ArrayOfValuesToFilterBy)
However, I know this wont work, I just need the equivalency...not using SQL.
I can generate the list of values to filter by via SQL, just not the final record select due to the legacy infrastructure constraint.
Thanks!
First, a logical field you do not have to do explicit
set filter to Logicalfield = .t.
you can just do
set filter to LogicalField
or
set filter to NOT LogicalField
Next, on the array. VFP has a function ASCAN() which will scan an array for a value, if found, will return the row number within the array that matches what you are looking for.
As for arrays... ex:
DIMENSION MyArray[3]
MyArray[1] = "test1"
MyArray[2] = "something"
MyArray[3] = "anything else"
? ASCAN( MyArray, "else" ) && this will return 0
? ASCAN( MyArray, "anything else" ) && this will return 3
If you are doing a "set filter", the array needs to be "in scope" for the duration of the filter. If you set filter in a procedure the array exists, leave the procedure and the array is gone, you're done.
So, you could do
set filter to LogicalField and ASCAN( YourArray, StringColumnFromTable ) > 0
Now, if you want a subset to WORK WITH, you can do a SQL-Select and pull the data into a CURSOR (temporary read-write table) that has the same capabilities of the original table (except auto-increment when adding)...
I typically name my temporary cursors prefixed with "C_" for "CURSOR OF" so when I'm working with tables, I know if its production data, or just available for temp purposes for quicker display, presentation, extractions from other origins as needed.
use in select( "C_FinalRecords" )
select * from YourTable ;
where LogicalField ;
and ASCAN( YourArray, StringColumnFromTable ) > 0;
into cursor C_FinalRecords READWRITE
Then, you can just use that...
select C_FinalRecords
scan
do something with the record, or values of it...
endscan
or.. bind to a grid in a form, etc...
The INLIST() function takes an expression to search for and up to 24 expressions of the same data type to search.
SELECT dataTable
SET FILTER TO logicalField = .T. AND NOT INLIST(otherField, 'Value1', 'Value2', 'Value3', 'Value4')
I am making some assumptions here, that what you want to do is create a filter with a dynamic in list statement ? If this is correct have a play with this example :-
lcList1="ABCD"
lcList2="EFGH"
lcList3="IJKL"
lcList4="MNOP"
lcList5="QRST"
lcFullList=""
lcFullList=lcFullList+"'"+lcList1+"',"
lcFullList=lcFullList+"'"+lcList2+"',"
lcFullList=lcFullList+"'"+lcList3+"',"
lcFullList=lcFullList+"'"+lcList4+"',"
lcFullList=lcFullList+"'"+lcList5+"'"
lcField="PCode"
lcFilter="SET FILTER TO INLIST ("+lcField+","+lcFullList+")"
The results of the above would create the following filter statement and store it in lcFilter
SET FILTER TO INLIST (PCode,'ABCD','EFGH','IJKL','MNOP','QRST')
you can then use macro substitution
Select dataTable
&lcFilter
Bear in mind that there is likely to be some limitations on how many items you can define in a INLIST() statement
I have a database table that holds parent and child records much like a Categories table. The ParentID field of this table holds the ID of that record's parent record...
My table columns are: SectionID, Title, Number, ParentID, Active
I only plan to allow my parent to child relationship go two levels deep. So I have a section and a sub section and that it.
I need to output this data into my MVC view page in an outline fashion like so...
Section 1
Sub-Section 1 of 1
Sub-Section 2 of 1
Sub-Section 3 of 1
Section 2
Sub-Section 1 of 2
Sub-Section 2 of 2
Sub-Section 3 of 2
Section 3
I am using Entity Framework 4.0 and MVC 2.0 and have never tried something like this with LINQ. I have a FK set up on the section table mapping the ParentID back to the SectionID hoping EF would create a complex "Section" type with the Sub-Sections as a property of type list of Sections but maybe I did not set things up correctly.
So I am guessing I can still get the end result using a LINQ query. Can someone point me to some sample code that could provide a solution or possibly a hint in the right direction?
Update:
I was able to straighten out my EDMX so that I can get the sub-sections for each section as a property of type list, but now I realize I need to sort the related entities.
var sections = from section in dataContext.Sections
where section.Active == true && section.ParentID == 0
orderby section.Number
select new Section
{
SectionID = section.SectionID,
Title = section.Title,
Number = section.Number,
ParentID = section.ParentID,
Timestamp = section.Timestamp,
Active = section.Active,
Children = section.Children.OrderBy(c => c.Number)
};
produces the following error.
Cannot implicitly convert type 'System.Linq.IOrderedEnumerable' to 'System.Data.Objects.DataClasses.EntityCollection'
Your model has two navigation properties Sections1 and Section1. Rename the first one to Children and the second one to Parent.
Depending on whether you have a root Section or perhaps have each top-level section parented to itself (or instead make parent nullable?), your query might look something like:-
// assume top sections are ones where parent == self
var topSections = context.Sections.Where(section => section.ParentId == SectionId);
// now put them in order (might have multiple orderings depending on input, pick one)
topSections = topSections.OrderBy(section => section.Title);
// now get the children in order using an anonymous type for the projection
var result = topSections.Select(section => new {top = section, children = section.Children.OrderBy(child => child.Title)});
For some linq examples:
http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx
This covers pretty much all of the linq operations, have a look in particular at GroupBy. The key is to understand the input and output of each piece in order to orchestrate several in series and there is no shortcut but to learn what they do so you know what's at hand. Linq expressions are just combinations of these operations with some syntactic sugar.