Intermittent #error on textbox with fairly simple IIF - ms-access

I've a Customer form with a tab control that holds the details for the specific items that a customer has: Ground Rent, Electricity and Garage. They may hold all 3, just Ground Rent and Electricity, or just a garage. If they don't have an item, the tab is hidden.
The issue only appears on the Garage tab: I intermittently get #ERROR in the amountdue text box. If I close down the customer and re-open them, sometimes it clears itself (with no action performed). Sometimes it doesn't. Sometimes it needs me to reopen a few times before the value shows.
The box concerned is: txtActualAmountDue and the source is the following:
=iif([tenant],[txtNet],[txtGarageCharge])
Tenant is a form data source Boolean (that indicates whether the Ground Rent/Electricity tabs should be shown).
txtNet = [txtGarageCharge]-[txtVAT]
txtVAT = [txtGarageCharge]*([txtVatPercentage]/(1+[txtVatPercentage]))
The next two are locked textboxes to make life easier
txtGarageCharge = DLookup("[GarageCharge]","Variables", criteria that returns the current row of variables for the current date)
txtVatPercentage = DLookup("[GarageVat]","Variables", criteria that returns the current row of variables for the current date)
The only thing else I can think of to mention is that if the customer is not a tenant, then txtNet and txtVAT are hidden. I sometimes get #Type! in txtNet and txtVat too - and obviously I also get the #Error - but not always: sometimes they're valued okay and I still get the #Error. I've commented out the load/current method lines that hides those textboxes to see if it's that, but it's made no difference.
Like I say - it's not like it happens every time: Just occasionally. Could it be to do with the order in which things are being valued/populated on the form? And once it's been populated once (the values will be the same for every customer) then it's okay? And if it's this, how do I force it to value the text boxes in the right order?

It is probably a timing issue, so try avoiding the mid calculations:
txtNet = DLookup("[GarageCharge]/(1+[GarageVat])","Variables", criteria)
txtVat = DLookup("[GarageCharge]/(1+[GarageVat])*[GarageVat]","Variables", criteria)
or, ultimatively:
=IIf([tenant],DLookup("[GarageCharge]/(1+[GarageVat])","Variables", criteria),DLookup("[GarageCharge]","Variables", criteria))

Related

Is there a way to use buttons in MS Access to fill in text boxes in a report?

Here's the crux of the question, I have 26 compliance queries to run, in a previous question it was suggested that I should filter a single query, or two, on a single report. I like this idea, and have rewritten the query to pull all available data from all the fields, this query works fine. The report will work fine as well, as it does with a model query that I had coded up beforehand. What I would like to do is this:
The end user is being given an interface in access that is locked down, I want them to click a button, and that button will run the query and send to the text box just the field that is called for.
I have tried doing this through VB using the where clause and aliasing the column being called, this did not work at all. I have the report currently pulling the correct data, but not displaying the dates along side it. But it is filtering correctly aside from that.
So what needs to happen is this : Button click : Query runs, and is filtered for "Compliance Issue 1" and puts the dates in "Compliance Issue 1" in the text box on the report.
Right now... I get a list of names, the correct list of names, but an empty column.
I have tried using OpenArgs, but all it did was fill in the date column with "Compliance Issue 1" not the actual data in that column.
Is what I am trying to do even possible in access, and if so does someone have a reference or suggested starting point.
My background : 6 Months of python coding, 3 months of SQL , and some limited access from 20 years ago.
As noted, using the filter of the openreport is without question the way to go (one would not write a whole bunch of different queries - you can send/have any filter for that report - you can EVEN use a sub query in the filter that you send to the report.
As for displaying values in the report that are not from "rows" of data?
There are two approaches that work quite well.
First up, is you have that launcher form. This of course allows the user to select critrea - maybe even some nice combob boxes. These selections take care and you build up the filter in code that you pass to the report.
As for text boxes to be filled out from that form and inclluded in the report?
If they are static values from the report (say filter options, or even just a notes box that you could type in some text? To display such values in textboxes on the report?
You can directly set the text box data source (in the designer) to the report propter form like this:
=(forms!MyPromptForm!notes)
So, any value you shove into text boxes on the report prompt form can thus be displayed in any text box on the report with the above type of expression. And it does not even take code to achieve this goal. So, you could say with above enter some notes into that text box, and thus on the report, whatever you typed into that text box will now show up in the report. You just drop in a text box onto the report, and set the data source of the text box to the above expression that references the form with the values we want from that form.
The next approach, and I often use this in the case that some value/expression/calculation has to occur for each row. In this case, you can use the reports on-detail format event. This allows you to run code for EACH row of data.
You are free to run ANY code in that event - and that includes after running such code to set a text box in the reports detail section.
So, say the query only had the Hotel ID (PK). This is a lame example, but you could then write this code in the on-format event of the reports detail section.
dim strSQL as string
dim rst as DAO.RecordSet
strSQL = "SELECT HotelName from tblHotels where ID = " & me.HotelID
set rst = CurrentDb.OpenRecordSet(strSQL)
me.HotelName = rst!HotelName
rst.Close
So in above, we assume that a row text box is called HotelID, and then in code we build a whole sql query from scratch, pulled the row data from a table, and then SHOVE/SET the value of the un-bound text box called hotelName.
As noted, the above is a simple example, but we are free to run any code we want, pull any data we want, and set the value of ANY text box for the given detail section ONE row of values.
So, above shows two approaches. The first approach is code free - and you can put forms! expression directly into the report, and the values from that report prompt form will thus show up directly in the report. However, if you need VBA code to run for each row, pull values, walk the dog, and THEN set a text box on that one details row of data, then you are as above shows free to write procedural code in the report that fires + runs for each row of data - and that means you can quite much do anything you want in terms of running code. I mean, even that on detail format event COULD pull values from your report prompt form, but as the 1st example shows, you can shove in forms! expression directly into a text box - and those forms! expressions can be values from a existing form that is open before the report is launched.

What ID does a ComboBox reference?

I am attempting to maintain and fix a horribly out-of-date CRM designed by an ex-employee ~4-5 years ago in Access 2007. I have brought it into Access 2013 and fixed a ton of stuff up, but I am still running into many problems.
I spent a good 4 hours today attempting to figure out why certain values didn't line up. These values were being pulled from a SELECT statement on a Combo Box over a stored Query which simply returns a table with a few extra rows. Great.
However this value (a number) doesn't appear to correlate with what we expect. I enter in one value, save the ticket, and a completely different value gets stored into the table. Opening up the ticket, I see the value that I expect. Digging deeper, I found the following difference:
Set value_1 = Me.RegistrationID // What's being stored in the table
Set value_2 = Me.RegistrationID.Column(0) // What we expect
Surprise surprise! This is a Combo Box and some value is being stored in the table. The Control Source is "RegistrationID" and the Row Source is the query in question.
However I do not know what it is! This specific value correlating to the Combo Box appears to pull the correct data when we later open the tickets. However I have a strong feeling that this could be why many tickets from before one of the rows was deleted all appear to have invalid RegistrationID's.
How badly can this break?
How easily can we correct tens of thousands of tickets?
How can I fix this to store the correct value?
This is what I expect is happening.
Your combo box row source is based on a Select query which returns and displays multiple rows. For example:
Select RegistrationID, CustomerID, CustomerName From MyTable;
The Control Source for the combo box is bound to RegistrationID which is part of the Forms Record Source.
The issue is the bound column. If we set the bound column in our example to 1, then we get the behavior your are describing with:
Set value_1 = Me.RegistrationID - Set's value to CustomerID (may appear correct)
Set value_2 = Me.RegistrationID.Column(0) - position 0 from our query (RegistrationID)
Further building on our query example, you can say:
Me.TextBox1 = Me.RegistrationID.Column(0) - RegistrationID
Me.TextBox2 = Me.RegistrationID.Column(1) - CustomerID
Me.TextBox3 = Me.RegistrationID.Column(2) - CustomerName
The RegistrationID is what normally should be stored in the table.
As long as your form shows any values that directly relate to this RegistrationID you're fine.
I would start by checking to see under the format setting to see if column widths are set properly and I would also check under the data section to see if the bound column is correct. I might also throw in an after update macro/vba sub routine that saves the record. Hope this helps.

"Run time error 3167: Record is deleted" when unchecking a selection in multi select listbox

I have a form that contains a multi-select list box, a user can check off as many selections as required, then hit the "save" button, which saves the form fields, and the checked off selections in their respective tables.
Everything works perfectly fine, until a user unchecks a selection that had previously been saved.
I have tried several things, including refreshing the form, and the recordset, to no avail.
While testing to find a solution, I commented out every single line of VBA code tied to the form's save button. When clicking this button, obviously nothing happens with the code commented out, but if I try and close the form with the window's "x" button, I then get a message box stating "Record has been deleted"
I have no idea where to look at this point, I've tried to compact and repair database, also with negative results.
I have no code to post, as it doesn't matter what code I try to run, I get the error, a completely empty sub still gives me the error.
Again, this only happens when a user unchecks a selection that previously had been checked off.
Here is a screen shot of the form:
The list box in red is the culprit.
A user can edit every single field on the form and it all works fine, a user can even "add" selections from the listbox by checking items off, and it will save them, and show them the next time the record is viewed.
The problem occurs when a user unchecks one of the selections that were previously checked off.
Details of the listbox:
It is a multi select list box populated by a "lookup" that was created with the listbox wizard
The values selected are saved in a field as a comma separated list
The field itself is a lookup of another table, that allows multiple values
At this point I'm not even sure I'm explaining myself properly, I've gone so far down the "rabbit hole"!
If any clarifying statements are needed please ask away.
The following describes my implementation of what I think you were trying to do, but there may be some variations. The key point is I was able to reproduce your 'Deleted record' error on a regular basis, but somehow finally got it to stop.
I created a table named 'res_area' with an ID field and an 'area'. I populated with rows for '1E, 1F, 1I, 1J, 3C, 3D, 3E, 3F, 3I, 3J, 3K, etc.'
I created table 'res_tow' with all the fields you show on your form. I included a field named 'area' that is a LOOKUP field with the following source: "SELECT [res_Area].[TTID], [res_Area].[Area] FROM [res_Area] ORDER BY [Area];". Allow Multiple Values = yes.
I created form 'frmEditTow' with the Record Source:
SELECT res_Tow.TowID, res_Tow.TCompany, res_Tow.TPhone1, res_Tow.TPhone2,
res_Tow.TPhone3, res_Tow.TType, res_Tow.TTown, res_Tow.TAddress,
res_Tow.TFileName, res_Tow.TComments, res_Tow.TChecks, res_Tow.area
FROM res_Tow;
I added the 'Save Record' button with code to: 'DoCmd.RunCommand acCmdSaveRecord' and 'Me.Requery'
I am able to add or delete any combination of list items and save the changes.
For what its worth, I think my earlier version of the rowsource for the form included field 'area' and 'area.value'. With that, the form recordcount reflected the total number of listbox items selected - not the number of rows in table 'res_Tow'.
Good luck!

SSRS- Implementing an either or paramater

So I have a requirement for a report where the user can select the exact batch number or if they are too lazy to remember the number they can pick the owner, the year, the month then the actual creation date of the batch.
If batch number is selected no need to select all the other stuff.
When the report starts up it starts in the opposite start state than expected. The query for Owner is
IF (ISNULL(#BatchNumer, '') = '')
begin
select distinct CashReceiptOwner as Label,CashReceiptOwner as Value
from CashReceiptBatchPosted
end
I was expecting the Owner box to be active, than if batch number is not empty for it to be disabled. That is not a huge issue as the combo box is blank, the bigger issue is that the report says it is required even though it is suppose to all blanks. Now I don't want to check the allow null option because all that does is create a checkbox which the user has to select.
Hopefully I made that clear enough, does anyone what I am doing incorrectly?

Custom row source for combo box in continuous form in Access

I have searched around, and it seems that this is a limitation in MS Access, so I'm wondering what creative solutions other have found to this puzzle.
If you have a continuous form and you want a field to be a combo box of options that are specific to that row, Access fails to deliver; the combo box row source is only queried once at the beginning of the form, and thus show the wrong options for the rest of the form.
The next step we all try, of course, is to use the onCurrent event to requery the combo box, which does in fact limit the options to the given row. However, at this point, Access goes nuts, and requeries all of the combo boxes, for every row, and the result is often that of disappearing and reappearing options in other rows, depending on whether they have chosen an option that is valid for the current record's row source.
The only solution I have found is to just list all options available, all the time. Any creative answers out there?
Edit Also, I should note that the reason for the combo box is to have a query as a lookup table, the real value needs to be hidden and stored, while the human readable version is displayed... multiple columns in the combo box row source. Thus, changing limit to list doesn't help, because id's that are not in the current row source query won't have a matching human readable part.
In this particular case, continuous forms make a lot of sense, so please don't tell me it's the wrong solution. I'm asking for any creative answers.
I also hate Access, but you must play with the cards you are dealt.
Continuous forms are a wonderful thing in Access, until you run into any sort of complexity as is commonly the case, like in this instance.
Here is what I would do when faced with this situation (and I have implemented similar workarounds before):
Place an UNBOUND combobox on the form. Then place a BOUND textBox for the field you want to edit.
Make sure the combobox is hidden behind (NOT invisible, just hidden) behind the textBox.
In the OnCurrent event fill the listBox with the necessary data. Go ahead and "Limit to list" it too.
In the OnEnter or OnClick event of the textBox give the combobox focus. This will bring the combobox to the forefront. When focus leaves the combobox it will hide itself once more.
In the AfterUpdate event of the combobox set the value of the textbox equal to the value of the combobox.
Depending on your situation there may be some other details to work out, but that should more or less accomplish your goal without adding too much complexity.
use continuous forms .. definitely. In fact you can build entire applications with great and intuitive user interface built on continuous forms. Don't listen to Toast!
Your solution of listing all options available is the correct one. In fact there is no other clean solution. But you are wrong when you say that Acccess goes nuts. On a continuous form, you could see each line as an instance of the detail section, where the combobox is a property common to all instances of the detail section. You can update this property for all instances, but cannot set it for one specific instance. This is why Access MUST display the same data in the combobox for all records!
If you need to accept only record-specific values in this combobox, please use the beforeUpdate event to add a control procedure. In case a new value cannot be accepted, you can cancel data update, bringing back the previous value in the field.
You cannot set the limitToList property to 'No' where the linked data (the one that is stored in the control) is hidden. This is logical: how can the machine accept the input of a new line of data when the linked field (not visible) stays empty?
You could also make the value of the combo box into an uneditable text field and then launch a pop-up/modal window to edit that value. However, if I was doing that, I might be inclined to edit the whole record in one of those windows.
I don't think that Access continuous forms should be condemned at all, but I definitely believe that they should be avoided for EDITING DATA. They work great for lists, and give you substantially more formatting capabilities than a mere listbox (and are much easier to work with, too, though they don't allow multi-select, of course).
If you want to use a continuous form for navigation to records for editing, use a subform displaying the detailed data for editing, and use the PK value from the subform for the link field. This can be done with a continuous form where you place a detail subform in the header or footer, linked on the PK of the table behind the continuous form.
Or, if you are using a continuous form to display child data in a parent form, you can link the detail subform with a reference to the PK in the continuous subform, something like:
[MySubForm].[Form]!MyID
That would be the link master property, and MyID would be the link child property.
We also encounter this a lot in our applicatins. What we have found to be a good solution:
Just show all rows in the comboboxes.
Then, as soon as the user enters the compobox in a specific row, adjust the rowsource (with the filter for that row). When the combobox loses the focus, you can re-set the rowsource to display everything.
I have a simpler way to go than Gilligan. It seems like a lot of work but it really isn't. My solution requires having my continuous form as a subform datasheet. On my subform I have two lookup comboboxes, among other fields, called Equipment and Manufacturer. Both simply hold a Long Integer key in the data source. Manufacturer needs to be filtered by what is selected in Equipment. The only time I filter Manufacturer.RowSource is in the Manufacturer_GotFocus event.
Private Sub Manufacturer_GotFocus()
If Nz(Me.Equipment, 0) > 0 Then
Me.Manufacturer.RowSource = GetMfrSQL() '- gets filtered query based on Equipment
Else
Me.Manufacturer.RowSource = "SELECT MfgrID, MfgrName FROM tblManufacturers ORDER BY MfgrName"
End If
End Sub
In Manufacturer_LostFocus I reset Manufacturer.RowSource to all Manufacturers as well. You need to do this because when you first click in the subform, GotFocus events fire for all controls, including Manufacturer, even though you are not actually updating any fields.
Private Sub Manufacturer_LostFocus()
Me.Manufacturer.RowSource = "SELECT MfgrID, MfgrName FROM tblManufacturers ORDER BY MfgrName"
End Sub
In the Enter event of Manufacturer you have to check if Equipment has been selected, if not set focus to Equipment.
Private Sub Manufacturer_Enter()
If Nz(Me.EquipmentID, 0) = 0 Then
'-- Must select Equipment first, before selecting Manufacturer
Me.Equipment.SetFocus
End If
End Sub
You also need to requery the Manufacturer combobox in Form_Current event (i.e. Me.Manufacturer.Requery), and you should set the Cycle property of this subform to "Current Record".
Seems simple enough, but you're not done yet. You also have to reset Manufacturer.RowSource to all Manufacturers in the SubForm_Exit event in the parent form in case the user goes to the Manufacturer combobox but does not make a selection and clicks somewhere on the parent form. Code sample (in parent form):
Private Sub sFrmEquip_Exit(Cancel As Integer)
Me.sFrmEquip.Controls("Manufacturer").RowSource = "SELECT MfgrID, MfgrName FROM tblManufacturers ORDER BY MfgrName"
End Sub
There is still one piece of this that is not clean. When you click on Manufacturer and have multiple rows in the datasheet grid, Manufacturer field will go blank in other rows (the data underneath the comboboxes is still intact) while you're changing the Manufacturer in the current row. Once you move off this field the text in the other Manufacturer fields will reappear.
This seems to work well.
CBOsfrmTouchpoint8 is a combobox shortened to just the dropdown square.
CBOsfrmTouchpoint14 is a textbox that makes up the rest of the space.
Never say never:
Private Sub CBOsfrmTouchpoint8_Enter()
If Me.CBOsfrmTouchpoint8.Tag = "Yes" Then
CBOsfrmTouchpoint14.SetFocus
Me.CBOsfrmTouchpoint8.Tag = "No"
Exit Sub
End If
Me.CBOsfrmTouchpoint8.Tag = "No"
Me.CBOsfrmTouchpoint8.RowSource = "XXX"
Me.CBOsfrmTouchpoint8.Requery
Me.CBOsfrmTouchpoint8.SetFocus
End Sub
Private Sub CBOsfrmTouchpoint8_GotFocus()
Me.CBOsfrmTouchpoint14.Width = 0
Me.CBOsfrmTouchpoint8.Width = 3420
Me.CBOsfrmTouchpoint8.Left = 8580
Me.CBOsfrmTouchpoint8.Dropdown
End Sub
Private Sub CBOsfrmTouchpoint8_LostFocus()
Me.CBOsfrmTouchpoint8.RowSource = "XXX"
Me.CBOsfrmTouchpoint8.Requery
End Sub
Private Sub CBOsfrmTouchpoint8_Exit(Cancel As Integer)
Me.CBOsfrmTouchpoint14.Width = 3180
Me.CBOsfrmTouchpoint8.Width = 240
Me.CBOsfrmTouchpoint8.Left = 11760
Me.CBOsfrmTouchpoint8.Tag = "Yes"
End Sub
What if you turn off the "Limit To List" option, and do some validation before update to confirm that what the user might have typed in matches something in the list that you presented them?
Better...
Set you combo box Control Source to a column on the query where the values from your combo box will be stored.
For Me I think the best way and easiest way is to create a temporary table that has all your bound fields plus an extra field that is a yeas/no field.
then you will use this table as the data source for the continuous for. You can use onLoad to fill the temporary table with the data you want.
I think it is easy after that to loop for the choices, just a small loop to read the yeas/no field form the temporary table.
I hope this will help
Use OnEnter event to populate the combo box, don't use a fixed rowsource.
I've just done similar. My solution was to use a fixed row source bound to a query. The query's WHERE clauses reference the form's control i.e. Client=Forms!frmMain!ClientTextBox. This alone will fill the combo boxes with the first row's data. The trick then is to set an 'On Enter' event which simply does a re-query on the combo box e.g. ComboBox1.Requery, this will re-query that combo box alone and will only drag in the data related to that record row.
Hope that works for you too!
Disclaimer: I hate Access with a passion.
Don't use continuous forms. They're a red herring for what you want to accomplish. Continuous forms is the same form repeated over and over with different data. It is already a kludge of Access's normal mode of operation as you can't have the same form opened multiple times. The behavior you are seeing is "as designed" in Access. Each of those ComboBox controls is actually the same control. You cannot affect one without affecting the others.
Basically, what you have done here is run into the area where Access is no longer suitable for your project (but cannot ditch because it represents a large amount of work already).
What seems to be the most likely course of action here is to fake it really well. Run a query against the data and then create the form elements programmatically based on the results. This is a fair amount of work as you will be duplicating a good bit of Access's data handling functionality yourself.
Reply to Edit:
But as they are, continuous forms cannot accomplish what you want. That's why I suggested faking out your own continuous forms, because continuous forms have real limitations in what they can do. Don't get so stuck on a particular implementation that you can't let go of it when it ceases to work.