How is this returning a blank value? - ms-access

So this code is meant to serve as a simple search system to go to certain records in a recordset. I originally had it so they had to click the btnGoToID button in order to perform the search. I decided to just make it a little more user friendly and make it so the search field listened for the Enter button and that would perform the search as well.
The issue that I am running into when the code gets to strID = Trim(Nz(Me.txtSearch.Value, "")) the value will randomly come back as an empty string even though visually I can see that there is a value in the textbox.
I haven't been able to narrow down any pattern for when this issue occurs. At this point I don't really even know how to troubleshoot this problem, nor the words to search for that could yield any results in Google. All I can say is that it SEEMS like changing between records will affect whether or not the search goes through.
This has always worked up until I put in the txtSearch_KeyPress sub procedure.
'============================================================================
' txtSearch_KeyPress
'============================================================================
Private Sub txtSearch_KeyPress(KeyAscii As Integer)
'If user pressed enter
If KeyAscii = 13 Then
Call btnGoToID_Click
End If
End Sub
'============================================================================
' btnGoToID_Click
'============================================================================
' <<Purpose>>
' Allow the user to search for a specific ID
'============================================================================
Private Sub btnGoToID_Click()
On Error GoTo Err_Handler
Dim rs As Recordset
Dim strID As String
Set rs = Me.RecordsetClone
strID = Trim(Nz(Me.txtSearch.Value, ""))
If (strID <> "") Then
'Go to the ID
rs.FindFirst "ID = '" & strID & "'"
If rs.NoMatch Then
MsgBox "ID does not exist"
Else
'If we have a match, set the record as the current record
Me.Bookmark = rs.Bookmark
End If
Else
MsgBox "Please enter a valid ID.", vbOKOnly, "Invalid ID"
End If
Exit_Handler:
On Error Resume Next
Me.txtSearch.Value = ""
rs.Close
Set rs = Nothing
Exit Sub
Err_Handler:
Call LogError(Err.Number, Err.Description, "txtSearch on " & Me.Name)
Resume Exit_Handler
End Sub
After the conversation in the comments I have narrowed down this question to be a whole lot simpler. This yields an "Invalid use of null" error message even after there are several characters in the text field. Why would that happen, and what can I do to make it pick up the values in the textbox?
'============================================================================
' txtUnitNoToSearch_KeyPress
'============================================================================
Private Sub txtUnitNoToSearch_KeyPress(KeyAscii As Integer)
MsgBox Me.txtUnitNoToSearch
End Sub

I think your problem is related to the fact that a text box has 2 properties, .Value and .Text, which appear similar but behave differently.
While you have an edit in progress in the text box, the changing content is available via the .Text property. However, the content of the .Value property has not yet been updated to match.
After the text box's After Update event, .Value will contain the new content. And if focus has moved away from the text box, its .Text property will no longer even be available.
Sorry, I couldn't think how to explain that better. But I think the situation will be clearer with this KeyPress event procedure:
Private Sub txtUnitNoToSearch_KeyPress(KeyAscii As Integer)
Debug.Print "Text: '" & Me.txtUnitNoToSearch.Text & "'"
Debug.Print "Value: '" & Me.txtUnitNoToSearch.Value & "'"
End Sub
Watch the output from Debug.Print in the Immediate window as you make changes to the context of the text box. (Ctrl+g will open the Immediate window.)
One final point is that just Me.txtUnitNoToSearch gets you its default property which is .Value. Keep that in mind as you work through the rest of your code.

Related

Setting and moving to a bookmark

I have an error message on a form that checks for an existing SSN on the BeforeUpdate event of a text box. If it already exists in the database, the user is given a message box to this effect, and has the option to go to the existing record. I'm using this example code here. My code is below.
Private Sub txtSocialSecurityNumber_BeforeUpdate(Cancel As Integer)
'check for existing SSN
Dim SSN As String
Dim strLinkCriteria As String
Dim rsc As Recordset
Set rsc = Me.RecordsetClone
SSN = Me.txtSocialSecurityNumber.Value
strLinkCriteria = "[SocialSecurityNumber] = " & "'" & SSN & "'"
'look for duplicates
If DCount("SocialSecurityNumber", "Person", LinkCriteria) > 0 Then
'Undo duplicate entry
Me.Undo
'error message
intResponse = MsgBox("Social Security Number " & SSN & " already exists in database." & _
vbCrLf & vbCrLf & "Would you like to view the record?", vbYesNo, "Duplicate SSN")
If intResponse = vbYes Then
'go to record
rsc.FindFirst strLinkCriteria
Me.Bookmark = rsc.Bookmark
ElseIf intResponse = vbNo Then
Exit Sub
End If
End If
Set rsc = Nothing
End Sub
According to this code, and several other examples I have looked up, it seems like I'm doing everything right, but I must not be because when I try to run the code and go to the existing record, I get the error "Run-time error '424': Object Required". When I debug, the row rst.FindFirst strLinkCriteria is highlighted, and hovering over it gives me the text strLinkCriteria = "[SocialSecurityNumber] = '123456789'" (123456789 is a known sample SSN in my database). Thank you to Sergey S. for pointing out the spelling error that fixed this section.
When I tell the message box to go to the record with the existing SSN, it gives me Run-time error '3021': No current record. Debug highlights the line Me.Bookmark = rsc.Bookmark with the message rsc.Bookmark = <No current record.>. So it sounds like I'm not assigning the bookmark correctly.
I've never used bookmarks before, so I'm not really sure what I'm doing wrong here. Any help would be appreciated.
You declared rsc, but used rst.
Change your code to
rsc.FindFirst strLinkCriteria
And I'd recommend always use Option Explicit in every module (default can be changed on options), otherwise you'll face with such kind strange errors. With this option the typo would be found by compiller, not at runtime.

VBA Access Textbox returning Null Value

I have a VBA Access userform. In this useform there is a textbox with the name txtSearch_POBOX. I'm trying to get its value using the code below:
Private Sub txtSearch_FirstName_Change()
MsgBox ([Form_Client List].txtSearch_POBOX.Value)
End Sub
But this is constantly returning NULL. When even when there is a value inside the text box. Any ideas?
Your reference is wrong. It should read:
MsgBox Forms![Client List]!txtSearch_POBOX.Value
As it could be empty, you should use:
MsgBox Nz(Forms![Client List]!txtSearch_POBOX.Value)
remember that if you want to intercept the text box value while digiting, until you "validate" the content change (e.g. losing focus) the .Value property is not updated.
For instance I used a text box to make a running filter of a submask: I wanted to filter the submask while digiting.
To do this you need to use the .Text property.
In the following example I make a running filter of a list of Publishers:
Private Sub txtNameFilter_Change()
On Error Resume Next
Dim strFilter As String
If Not IsNull(Me.txtNameFilter.Text) Then
strFilter = "Publisher LIKE '*" + Me.txtNameFilter.Text + "*'"
Me.Filter = strFilter
Me.FilterOn = True
Me.txtNameFilter.SelStart = Len(Me.txtNameFilter.Text)
End If
End Sub
Bye
Wiz

Create an immediate window style log on a form

Is it possible to create something like the immediate window on a form?
I've tried sending various updates to a text box, but the update rate on text box seems to be much slower than what you get with Debug.Print to the immediate window.
Would be good to tell the user what operations are currently being carried out whilst they wait for something to be processed (and without skipping some operations because they are processed quicker than the update rate would seemingly allow).
You can set the textbox (or label) text and then call the DoEvents method.
This last call is important because is supossed you are executing a long process and screen will redraw only on idle time.
Alternatively, you can use the status bar to notify your progress:
SysCmd acSysCmdSetStatus, "Doing some long task, please wait..."
'Do your work
SysCmd acSysCmdSetStatus, ""
If you can measure your progress, it's possible to include a progress bar. I.e. processing a recordset:
bk = rs.Bookmark
rs.MoveLast
r = SysCmd(acSysCmdInitMeter, caption, rs.RecordCount)
rs.Bookmark = bk
Do Until rs.EOF
'Do something
i = i + 1
If i Mod 10 = 0 Then 'Do not update the meter for every processed record
SysCmd acSysCmdUpdateMeter, i
End If
rs.MoveNext
Next
SysCmd acSysCmdRemoveMeter
In the past I had tried using a single multi-line Text Box as a scrolling status window but it seemed to be inordinately fussy when it came to the text selection status (.SelText, .SelLength, .SelLength). In the end I just went with five (5) single-line Text Box controls and "scrolled" them myself.
In the following screenshot the Text Box controls are named txtStatus4, txtStatus3, ... txtStatus0 (from top to bottom)
and the code to update that status "window" (actually a Frame control) is
Private Sub UpdateStatus(StatusText As String)
Dim i As Long
For i = 4 To 1 Step -1
Me.Controls("txtStatus" & i).Value = Me.Controls("txtStatus" & i - 1).Value
Next
Me.txtStatus0.Value = StatusText
Me.Repaint
End Sub
Just in case anyone ever looks for this again, there IS a way to do what the OP asked, without multiple textboxes.
Screenshot of solution
On your form, add a textbox. A regular textbox will do. Give it a name, like txtLog. Size it to be big enough to display a bunch of text.
Here's a sub to handle the updating:
Private Sub WriteToLogText(strText As String, Optional blnClear As Boolean = False)
txtLog.SetFocus
If blnClear = True Then
txtLog = strText
Else
txtLog = txtLog.Text & Chr(13) & Chr(10) & strText
End If
End Sub
Then call the sub to write your text:
strMsg = "Warning: Commodity '" & Trim(drs("RawCommodity")) & "' is not mapped."
WriteToLogText strMsg

Auto Populate Access Form using simple VBA code by setting a variable

I was recently given the task of creating a form that will autofill with the information from a table. The information the form autofills is selected using a primary key called ModID. I have a combo box that has a List of the ModIDs that are listed as Active.
SELECT ModID
FROM P_Review
WHERE Status = "Active"
Simple enough. I then have VBA code running on the event After Update. So after the value for the combo box is select or changed it will run this VBA code.
Option Compare Database
Option Explicit
Private Sub selectModID_AfterUpdate()
'Find the record that matches the control.
On Error GoTo ProcError
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
.FindFirst "ModID=" & Me.selectModID
If Not .NoMatch Then
Me.Bookmark = .Bookmark
Else
DoCmd.RunCommand acCmdRecordsGoToNew
Me!localModID = Me.selectModID.Column(0)
End If
End With
ExitProc:
Exit Sub
ProcError:
MsgBox "Error: " & Err.Number & ". " & Err.Description
Resume ExitProc
End Sub
The code runs fine (I get no errors when I debug or run).
Now for the access text box. I would like to populate certain fields based off the variable localModID. I have a dlookup in a text box to find the information in the table P_Review.
=DLookUp("Threshold","P_Review","ModID =" & [localModID])
So the DlookUp should find the value for the column threshold, in the table P_Review, where the ModID in P_Review equals the localModID set in the VBA code. But when I go to form view and select a ModID I get the Error 3070: The Microsoft Access database engine does not recognize as a valid field name or expression. I did copy this code from another database we are already using but it fails in this new instance.
Private Sub ModID_AfterUpdate()
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
.FindFirst "ModID='" & Me.ModID & "'"
If Not .NoMatch Then
Me.Bookmark = .Bookmark
Else
DoCmd.GoToRecord , , acNewRec
Me!ModID = Me.ModID
End If
End With
End Sub
This is the answer to question. I used this code to auto update.
Try
Forms!<whatever_this_form_name_is>![localModID]
in your DLOOKUP

Possible to set filter on subform from parent form before subform data loads

I have frmParentForm with multiple controls used to build a filter for frmSubForm.
On frmParentForm_Load, I am doing (simplified example):
Me.sbfInvoice_List.Form.filter = "[created_on] >= #" & Me.RecentOrderDateCutoff & "#"
Me.sbfInvoice_List.Form.FilterOn = True
The problem is, on initial load, it seems the subform load is occurring first, so the entire table is loaded.
Is there a way (in a different event perhaps) to properly set the subform filter from the parent form so it is applied before the subform does its initial data load? (The subform can exist on its own, or as a child of many different parent forms (sometimes filtered, sometimes not), so I'd rather not put some complicated hack in the subform itself to accomplish this.)
Because the subform loads before the parent form, the parent form can not set a subform filter before the subform initially loads.
If you want to use the subform flexibly (all records when stand alone, but different subsets of records when included on different parent forms), I think you have to modify the subform to do it.
Private Sub Form_Open(Cancel As Integer)
Dim strParent As String
Dim strMsg As String
On Error GoTo ErrorHandler
strParent = Me.Parent.Name
Select Case strParent
Case "frmYourParentForm"
'set filter to only records from today '
Me.Filter = "[created_on] >= #" & Date() & "#"
Me.FilterOn = True
Case "frmSomeOtherParent"
'do something else '
End Select
ExitHere:
On Error GoTo 0
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 2452
'The expression you entered has an invalid reference to '
'the Parent property. '
Resume Next
Case Else
strMsg = "Error " & Err.Number & " (" & Err.Description _
& ") in procedure Form_Open"
MsgBox strMsg
End Select
GoTo ExitHere
End Sub
Edit: If you want to track the sequence of events in the parent form and subform, you can add procedures like this one to the forms' modules.
Private Sub Form_Load()
Debug.Print Me.Name & ": Form_Load"
End Sub
Here is what I get when tracking the Open and Load events for my parent form and subform.
fsubChild: Form_Open
fsubChild: Form_Load
frmParent: Form_Open
frmParent: Form_Load