In Notes I have a form (Order) in which I have button "Create new OrderLine" which creates a new form(Orderline). The Order document has an embedded view on the design which gets orderlines documents. Each orderline document contains a hidden field with the ID of the order document, so that you know which orderline is connected with which order. Same goes for Orderline this has an embeddedview with Prices.
In the Order form I have 2 editable text fields: AdministrationNumber and DebtorNumber.
In the OrderlineForm I only got the debtorNumber
In Prices I have a editable number field called Fee.
So I did this on various ways:
In the postOpen of the form prices I have put this LotusScript code:
If( (Source.FieldGetText( "AdministrationNumber" ) = "1" ) And (Source.FieldGetText( "DebtorNumber" ) = "2") ) Then
Call Source.FieldSetText("FeePercentage", "4.235")
Call Source.Refresh()
End If
But did not work.
In Default Value of Fee I also tried this formula code:
#If((AdministrationNumber="1") & (DebtorNumber= "2");
"4,235";
"0"
)
But also of no use..
Is it possible for an editable field to be set when opening the subform based on conditional statement with data which is in the parent form?
Edit
2 ways to solve:
1.
When clicking "Add new Orderline" Button whic is on the Order form, I will call a function in the scriptlibrary, in this function I get values of debnr and admnr and then do the conditional statement.. If true then set FeePercentage
2.
Added new hidden field on the orderlline called admnr which gets the administratorNr field data when the New Orderline Button is clicked.. The field is set through a function in the scriptlibrary.
Eventually in the postOpen of the prices subform this works:
Dim doc As NotesDocument
Set doc = Source.Document
If doc.admnra(0) = "1" And doc.debnr(0) = "2" Then
doc.FeePercentage = 4.235
End If
Work with back-end classes instead:
Dim doc as NotesDocument
Set doc = Source.Document
If doc.AdministrationNumber(0) = "1" And doc.DebtorNumber(0) = "2" Then
doc.FeePercentage = 4.235
End If
It gives you easy access to all fields in document.
You say "subform" which has a special meaning in Notes design but it sounds like what you have is a form called "Order", a form called "OrderLine" and a subform called "Prices" that the OrderLine form uses?
In which case, make sure the OrderLine's the "Formulas inherit values from selected document" form property is checked.
That and your default formula should do it if the button is on the parent form (as opposed to view the Order form embeds).
P.S. You might want to change your default formula to
#If(
(AdministrationNumber="1") & (DebtorNumber= "2"); 4235;
0
)
so that it returns a number instead of text that looks like a number.
Related
Hypothetical:
Say i'm having someone order a cake and they choose vanilla or chocolate, and then they have to choose a frosting
if vanilla: strawberry or buttercream
if chocolate: mocha, dark chocolate or buttercream.
Right now the frosting value in the data model can accept all four options, so all four show up in the dropdown.
a) is there a way to change the binding for the second dropdown after the first is chosen?
This can be done without having the data saved in any datasource. Simply do the following...
Suppose the first dropdown is named primaryDropdown and the second dropdown is called secondaryDropdown. In the primaryDropdown options set the following:
["Vanilla", "Chocolate"]
Also, make sure to uncheck the option allowNull and on the onAttach event handler, place the following:
widget.value = "Vanilla";
Now we move on to the secondaryDropdown. Here, we will do a binding so place the following in the options value:
getAvailableOpts(#widget.root.descendants.primaryDropdown.value)
In the client script, we need to make sure that function exists so please paste the following in any client script:
function getAvailableOpts(primaryValue){
var options;
switch(primaryValue){
case "Vanilla":
options =["Strawberry","Buttercream"];
break;
case "Chocolate":
options = ["Mocha","Dark Chocolate","Buttercream"];
break;
default:
options = [];
}
return options;
}
From here, you are good; However we can still make it better. For that, make sure to also uncheck the allowNull option for the secondaryDropdown and then we need to add some logic in the onValueChange event handler of the primaryDropdown.
widget.root.descendants.secondaryDropdown.value = widget.root.descendants.secondaryDropdown.options[0];
References:
https://developers.google.com/appmaker/ui/input-widgets#dropdown
https://developers.google.com/appmaker/ui/binding#bindings
https://developers.google.com/appmaker/scripting/client#use_scripts_in_binding_expressions
Im guessing you set the dropdown "possible value" options in the data source and you have those fields as just string fields in your table.
the quick and dirty way to do this is go to the Cake drop down and on the Property Editor>Events>OnValueChange select Custom Action and use this Code
if(widget.value==="Vanilla"){
widget.root.descendants.Field.options = ['Strawberry','Buttercream'];
}else if (widget.value === "Chocolate"){
widget.root.descendants.Field.options = ['Mocha','Dark Chocolate','Buttercream'];
}
"Field" here is replaced with the name of the dropdown box for your frostings
also go to the property editor of the frostings dropdown and delete everything in the options field there.
I was trying to solve for a similar situation and created an additional table to serve as a lookup.
I have a drop down for CATEGORY with possible options set on the field in the main data source.
Then I have a second table with 2 Columns: CATEGORY, and SUB_CATEGORY.
On the entry form I have options for the SUB_CATEGORY drop down set to SUB_CATEGORY on the CATEGORY_MATRIX lookup table.
Then for an onValueEdit event on the CATEOGRY drop down I have a script to reload the CATEGORY_MATRIX table source based on the value of the CATEGORY drop down in the query so when the CATEGORY is selected only valid SUB_CATEGORY options are shown in the second drop down.
var datasource = app.datasources.CATEGORY_MATRIX
datasource.query.filters.CATEGORY._equals = newValue;
datasource.load();
There may be more efficient ways to do this but the benefit is I could create another form page and dynamically add new combos so there isn't any required code change as new combos are needed.
See Datasource Paging Issue (Revised)
for the original question.
Markus, you were kind enough to help with out with the issue of incorporating a record count into a query using a calculated datasource. I have a search form with 15 widgets - a mix of date ranges, dropdowns, text values and ._contains, ._equals, ._greaterThanOrEquals, ._lessThanOrEquals, etc.
I have tested this extensively against mySQL SQL code and it works fine.
I have now added a 16th parameter PropertyNames, which is a list with binding #datasource.query.filters.Property.PropertyName._in and Options blank. The widget on the form is hidden because it is only used for additional filtering.
Logic such as the following is used, such that a particular logged-in user can only view their own properties. So if they perform a search and the Property is not specified we do:-
if (params.param_Property === null && canViewAllRecords === false) {
console.log(params.param_PropertyNames); // correct output
ds.filters.Property.PropertyName._in = params.param_PropertyNames;
}
The record count (records.length) is correct, and if I for loop through the array of records the record set is correct.
However, on the results page the table displays a larger resultset which omits the PropertyNames filter. So if I was to search on Status 'Open' (mySQL results 50) and then I add a single value ['Property Name London SW45'] for params.param_PropertyNames the record count is 6, the records array is 6 but the datasource display is 50. So the datasource is not filtering on the property array.
Initially I tried without adding the additional parameter and form widget and just using code such as
if (params.param_Property === null && canViewAllRecords === false) {
console.log(params.param_PropertyNames); // correct output
ds.filters.Property.PropertyName._in = properties; // an array of
properties to filter out
}
But this didn't work, hence the idea of adding a form widget and an additional parameter to the calculated recordcount datasource.
If I inspect at query.parameters then I see:-
"param_Status": "Open",
"param_PropertyNames": ["Property Name London SW45"],
If I inspect query.filters:-
name=param_Status, value=Open
name=param_PropertyNames, value=[]}]}
It looks as though the filter isn't set. Even hard coding
ds.filters.Property.PropertyName._in = ['Property Name London SW45'],
I get the same reuslt.
Have you got any idea what would be causing this issue and what I can do for a workaround ?
Using a server side solution I would suggest editing both your SQL datasource query script (server side) that is supposed to filter by this property list and including the same code in your server side script for your calculated Count datasource. The code would look something like this, not knowing your exact details:
var subquery = app.models.Directory.newQuery();
subquery.filters.PrimaryEmail._equals = Session.getActiveUser().getEmail();
subquery.prefetch.Property._add();
var results = subquery.run();
if(!results[0].CanViewAllRecords) {
query.filters.Property.PropertyName._in = results[0].Property.map(function(i) {return i.PropertyName;});
}
By adding this code you are filtering your directory by your current user and prefetching the Property relation table, then you set the filter only if your user canviewallRecords is false and use JS map function to create an array of the PropertyName field in the Property table. As I stated, your code may not be exactly the same depending on how you have to retrieve your user canviewallrecords property and then of course I don't know your relation between user and Property table either, is it one-to-many or other. But this should give you an idea how to implement this on server side.
Pretty simple question, I'm creating a dropdown field and trying to set the selected value like so:
$tourField = DropdownField::create('Tour', 'Tour', Tour::get()->sort('TourName ASC')->map('ID', 'TourName')->toArray(), $currentTourID);
I have confirmed that $currentTourID contains the correct value (a numeric ID) and that value exists in the resulting dropdown. When rendered, no item in the dropdown is selected by default. So I assume I have something else wrong here.
Edit: Note that this field is a has_one relationship field with the object, and in the case of this object, the value of it is null. I am trying to override that and set it using something a bit smarter.
My edit made me realise that all I had to do was set the object representation of these fields rather than try to manually override the default value. The key here is that the dropdowns in question reference a relationship in the object.
So instead of:
$currentTourID = $mySmartFunction();
$tourField = DropdownField::create('TourID', 'Tour', Tour::get()->sort('TourName ASC')->map('ID', 'TourName')->toArray(), $currentTourID);
I did this:
$this->TourID = $mySmartFunction();
$tourField = DropdownField::create('TourID', 'Tour', Tour::get()->sort('TourName ASC')->map('ID', 'TourName')->toArray());
In the form cutslistepage , i want to get the value of accountNum of the selected row in grid and passe it to another form
i have try that :
int64 recordsCount;
recordsCount = CustTable_ds.recordsMarked().lastIndex();
// CustTable = CustTable_ds.getFirst(1);
If you want to retrieve the CustTable record, check the CustTableListPageInteraction class.
In the selectionChanged method, it has the following code:
custTable = CustTable::findRecId(this.listPage().activeRecord(queryDataSourceStr(CustTableListPage, CustTable)).RecId);
This is how you can retrieve the record. But since it is already done, you can simply use the custTable variable that is already declared in the class declaration.
Side note: if you have an other form that is opened from the list page, it should automatically be filtered based on the relations between the data sources of the form. So you might be searching for a solution for a problem you shouldn't have. For example create a form that has a data source with a relation to the CustTable table on it and it should create a dynaink between the list page and your form, filtering the records for that customer.
If only one record is selected you can do:
info(CustTable_ds.accountNum);
Otherwise, if more than one record is selected you need to do something like:
custTable = CustTable_ds.getFirst(true);
while (custTable)
{
info(custTable.accountNum);
custTable = CustTable_ds.getNext();
}
I'm working on web pages that have an ASP DropDownList defined, and on page load the data source is bound to it through DataSource.DataBind(). When I step through the code, the drop down list does not show anything in it, but when the page actually displays, it does have items in the list. When exactly does DataBind() get applied to the control?
The problem is that some of the values returned by the SQL back end have a null Text, so nothing is displayed in the drop down list for that row. I want to just use the Value as the Text, but only if the Text is null. And when I put the code to loop through and do that right after the DataBind(), there is nothing in the drop down list at that point in the code.
Thanks!
The best option for your specific example is to do what kd7 said, and modify your query. However, if you ever need to do other modifications to the items, you can access them in the DataBound event of the DropDownList. MSDN. This event fires after the binding occurs.
You could
a) Modify your database query to exclude null values
or
b) Before you databind, iterate through the data returned and remove the undesired values.
You can just use LINQ on the data before you assign it to create a new type on the fly with the data arranged how you want. Here is a quick example:
// This simulates the data you get from the DB
List<SomeObject> lstData = new List<SomeObject>();
lstData.Add(new SomeObject() { ID = "1", Text = "One" });
lstData.Add(new SomeObject() { ID = "2", Text = "" });
lstData.Add(new SomeObject() { ID = "3", Text = "Three" });
// This will take your data and create a new version of it substituting the
// ID field into the Text field when the Text is null or empty.
yourDropDownList.DataSource = lstData.Select(i => new {
ID = i.ID,
Text = string.IsNullOrEmpty(i.Text) ? i.ID : i.Text }).ToList();
// Then just databind
yourDropDownList.DataBind();
The DropDownList would have the following items:
One
2
Three