I have form that loads as Data Entry = Yes and the navigation buttons are disabled. I'm trying to figure out how to make it to where a user cannot press SHIFT+TAB and go back through previously entered records. You have to press tab at the very last field to move to a new record just like you would the table.
Should I just close and reopen the form after update? Or is there a different way?
Thanks in advance
Before I answer the question, are you sure preventing the user from going backwards is a good idea? Perhaps they tabbed forward to make a new record and then realized they made a mistake so they want to go back and correct it? Of course, this depends on the specific needs of your db and how it will be used.
The Cycle property in the Other tab defines how tabbing works. If you change this to Current Record, then the user cannot tab backwards or forwards to other records.
If the user needs to add multiple records at once, you can add a command button.
Edit
Regarding your idea on the submit button, here's how you can make that work. Leave the form's record source blank (so it isn't tied to the table). When the users click Submit, a msgbox will first pop up asking them to save and warning them they can't go back. If they choose Yes, a SQL query stored in the VBA will then append the form's values to the target table, then clear the form.
The only potential problem with this is if the user enters single or double quotes to any string fields as those can mess up your SQL query. A simple Replace() can fix that though.
Related
I am developing a MS Access 2016 application with bound controls on Forms. Late in the process I decided I want a multi-select listbox.
From what I can see, you can't bind a multi-select listbox to a table. I'm okay with parsing the listbox when about to leave that record, and putting a comma separated list of values in a bound, non-visible text box. And then on arriving at the new record, setting the values in the listbox based on the values in that record's textbox.
The Current event lets me know when I arrive at a new record, but is there an event that lets me know I'm leaving a record? Before Update only works if the current record is changed, not just navigating to a new record. I suspect I'm missing something real basic.
If you want to parse a field and manually update it to a table, use the Before Insert and Before Update events. Don't do anything with navigation, because then you're likely too late.
Also, make sure to dirty the form when the value of the list box changes (Me.Dirty = True in the On Change event), so the update fires when navigating.
Or, like krish KM says, just make sure your text box changes every time your listbox changes.
That's more reliable than accounting for navigation, filtering, closing the form, manually saving, etc.
I have frmMain that has a number of subforms that are contained in several tabs on tab control on frmMain. I have subForm3 on one of the tabs of frmMain. subForm3 has a textbox control called tbxNote. tbxNote requires one user to make changes to the note based on feedback from a supervisor that is shown in a separate, non-modal popup form called frmFloater that appears above frmMain so that the supervisor's note shown in the non-modal form can be seen while tbxNote in frmMain.subForm3 is being editted.
Now, both frmMain and frmFloater can change the data in the same table. I understand that this is what is causing the write conflict error I am receiving.
So, I want to be able to trigger a save of the data in subForm3 when the user exits tbxNote, for example, the user exits by clicking frmFloater or a control in frmFloater. And, I want to trigger a save of the data in frmFloater when I exit frmFloater or click a control in frmMain.
The problem I am running into is that I cannot find an event that triggers when I leave frmMain or when I enter frmFloater; nor can I find an event when I leave frmFloater or when I enter frmMain.
I have tried the following events for frmMain (and also in frmFloater), none of which trigger when the user leaves frmMain (e.g., by clicking into frmFloater) nor do they trigger when the user leaves frmFloater (e.g., by clicking into frmMain):
On Deactivate
On Activate
On Current
On Click
On Got Focus
On Lost Focus
How can I detect switching to a different form so that I can save out the data in the first form before handing control over to the 2nd form?
If there are 2 forms showing 1 record, you will always run into problems. I would look at separating the record into 2 tables and creating a relationship between the tables to prevent corruptions of records. For example:
Table 1 will hold the main information of the record being viewed
Table 2 will hold the supervisor notes
The relationship between the tables will be either a 1 to 1 (if you want a note to be a single record and all updates the current note) or a 1 to many (if you want multiple records with multiple notes
be sure to check "enforce referential integrity", "Cascade Updating", and "Cascade Deleting". Otherwise you will have orphan records.
To answer your question, it cannot be done with the current setup. If employee A is editing the record on frmMain and a supervisor opens frmFloater and begins adding notes. You just corrupted the record... Reason being is, you cannot have the front end the employee has save the record the front end the supervisor has. only their machine can save the record the specific person has accessed. make sense?
There is another solution, and that would be making frmFloater an unbound form. There is quite a bit of programming involved to accomplish this, but once I made all my forms in my Access Databases unbound and all the controls unbound, I never had a corrupted record incident again. But this requires a button building the query before opening the form, open the form, then take the values from the query and place the values in the corresponding textbox on your form, then close the query. This will give you a snapshot view of the record on the table without being bound to it. Your button/afterupdate event can then run an update query on the record without locking it.
Let me know if this helped or if this did not make sense. If it didn't make sense, I'll try to explain a little better.
So I have two issues with my database, which I think are linked together.
Firstly if tblDeliveries is empty and frmMainView is opened it comes up with "You must enter a value in the 'tblDeliveries.deliverySlot' field" but the form shouldn't be trying to create a record and I can't see any reason why it would. Opening frmDailyView (which is a subform of frmMainView) doesn't show this behaviour but it is the one with the continuous form on...
Secondly if tblDeliveries has one (or more) rows the first row of the table will jump about... For example in frmMainView if the date of the first record is set to 23/01/2015 and you navigate to the 24/01/2015 and click anywhere on the subform and then press F5 to refresh the record will have jumped to that date, the date even changes in tblDeliveries.
I have no idea why it's doing it, I even removed all of the VBA code for the form to stop it, but it happens anyway.
If anyone has come across anything like this before, please let me know how you fixed it, or any suggestions would be very welcome. Thanks!
EDIT: If you download the database, add your computer login name to tblUsers. Also the date is UK formatted, so might need tweaking to work with US dates.
The offending database (1.5MB)
Taking a look at your database, several issues are occurring.
You first issue can be resolved by going into the Design View of the table tblDeliveries, select the deliverySlot field and change Required (in bottom panel) from Yes to No.
Your second issue is multi-faceted with many issues but a critical problem is that the parent-child link field, deliveryDate, between the main form and subform is missing in the recordsource of the sub form and the field's table origin is not in the query's join statements. For me, I can't even update anything in subform (all boxes are grayed out).
Essentially, you are trying to normalize Delivery Dates and Delivery Times (one-to-many) but the left join query (qryDeliveryIncBlanks) setup is not aligned to this effect. You user login also does not integrate smoothly into frmMainView. My ultimate advice is revamp your database design relational model then use forms as the visual representation of those related tables.
I am not re-iterating the points of #Parfait.
Access Forms have a property DataEntry. If it is set to Yes (or True in VBA), then the form will open itself pointing to a new empty data record. Set this property to No (False in VBA).
If you want to give the user the possibility to manually enter a new record, set the property AllowAdditions to Yes and to No otherwise. Yes displays an empty record marked with a star * and the end of the data sheet or continuous form.
I've resolved the issue, thanks to some of the comments I realised I could just give the deliverySlot field a default value with a number outside of the range it would look for, I set it to 99, but it only looks for 1-20. The date still jumps around but since it's not in the range of the query it's hidden. It's resolved both issues.
There may be a better way to do this, but currently, if the user enters i value that is not allowed (in this case, a project that has been closed), then it notifies them. However, because it's on a sub-form linked to the table, it automatically created a record anyway. This is how it's currently handled (if a bad input was entered):
Clear the fields of that record
Delete the record from the table
Requery / Refresh
Currently it works fine, except it leaves #DELETED in all the controls associated with the records. However, if I hit F5, it disappears. Is there a way to make it so the deleted record disappears (like how it does when F5 is hit) programmatically?
I think you have a couple options to handle this. The main thing is that you want to avoid deleting the record and try to handle it before it ever becomes a saved record. You should be able to do this using one of several different form events (not control events): Dirty, BeforeUpdate or BeforeInsert.
If you use the Dirty event, check to see if the project is closed and check to see if the record they are working on is a NewRecord. If both are true then try using Cancel = True and/or Me.Undo.
If you use the BeforeUpdate event instead, it works much the same way. You'll probably need to cancel the edits and undo the edits as I mentiond directly above, in which order I'm not sure.
I don't have a good way to test the BeforeInsert event at the moment but I think you can prevent new records from coming into existence inside this event by using Cancel = True.
If you cannot handle the record before it gets saved, and you must truly clear #DELETED from your form, you'll probably need to use a Me.Requery statement. Exactly how this will work depends on whether or not the form is bound and what it is bound to but it sounds like you are using a fairly standard Access form that is bound to a table or SQL statement so I believe the Requery statement should work.
I'm new to Access VBA, and have created a form using the Form Wizard that displays records in a table. That's a piece of cake.
The behavior that I get with the form, though, is that updates to the records occur automatically when I move around records.
What I'd like is to have the updates occur only when I click an "Update" button that I put in the form.
It seems like I can construct the form from scratch, update all of the (unbounded) controls programmatically, and then update the record from the controls programmatically, but this seems like too much work.
Is there a way to "turn off" the automatic updating behavior from within Access, or using VBA code?
Thanks!
As Robert suggested, you can avoid saving a changed record by canceling the before update event. The code would look something like this:
Private Sub Form_BeforeUpdate(Cancel As Integer)
Me.Undo
Cancel = True
End Sub
However, that approach requires you discard any changes you've made to the record before you can move off it. Without Me.Undo, you can cancel the update, but Access won't allow you to move to a different record. You must either save or discard the changes to the current record before moving to another.
If you want to move to another record but not discard changes first, I think you need to try a disconnected recordset. It's an ADO recordset you create in memory, not bound to any data source. You can add a command button to save your changes on command. If it sounds useful, see this article by Danny Lesandrini at Database Journal: Create In-Memory ADO Recordsets
If users are accidentally changing data and moving record to record causing updates, maybe you should have an Edit button to only start editing when needed. You can use other suggested code to either undo the changes if they move to another record or prevent them from moving at all unless they save or cancel.
Is there a way to "turn off" the
automatic updating behavior from
within Access, or using VBA code?
You can try cancelling the Form.BeforeUpdate event, unless a flag is set. When the button is clicked, set the flag, set Form.Dirty to false (to save the data), and then clear the flag in the Form.BeforeUpdate event handler.
Why would you want to? Access works on a record by record basis. Not like Excel which only saves the spreadsheet when you choose to save or exit.
It sounds like you have a continuous form with multiple records on the screen. The only way to do this would be to use a "temporary" table and the save the contents of the "temporary" table to the permanent table once you're ready. However then you will lose the ability to determine if someone else has changed the records unless you do a lot more work.