AlexSt
AlexSt

Reputation: 23

Microsoft Access form, "Run-time error '3164': Field cannot be updated." ERROR, Drives me crazy

Found a solution but I would still appreciate help, see the very end of my question!!

I have created a form within access that connects to an outside database, in this form I can create a case for the company I work, with all the required details. It also has some functions to automate some parts of the process, such as a button with function to open a word doc template from a certain folder and modify it with the details from the case. All good so far (I will show you code so you better understand what the form does)

Once I created the second form which looks up in the database for the case number to bring it back and let me update/modify the case, here I have the problem. Once I open a case that was already created, and try to click the button "Create Outcome of Appeal Hearing" to open a word doc from a path location on my disk and automatically update that file with the up to date details from the case, I get this error "Run-time error '3164': Field cannot be updated.".

Here is some code so you get a better idea, the below code is from when I create a case, with the button to create the outcome of appeal hearing document, everything works fine here:

Public Function matchExactCaseNumber(caseNumber As String) As Boolean
If DCount("*", "health_appeals", "exact_case_number='" & caseNumber & "'") > 0 Then
    matchExactCaseNumber = True
Else
    matchExactCaseNumber = False
End If
End Function

Function GetUserFullName() As String
    Dim WSHnet, userName, UserDomain, objUser
    Set WSHnet = CreateObject("WScript.Network")
    userName = WSHnet.userName
    UserDomain = WSHnet.UserDomain
    Set objUser = GetObject("WinNT://" & UserDomain & "/" & userName & ",user")
    GetUserName = objUser.FullName
    Splitusername = Split(GetUserName, ", ")
    SureName = Splitusername(0)
    FirstName = Splitusername(1)
    GetUserFullName = FirstName & " " & SureName
    
End Function

Private Sub Form_Load()
   DoCmd.GoToRecord , , acNewRec
   Me.pxtoc_expert = GetUserFullName()
   Me.pxtoc_expert_mail = Environ("USERNAME") & "@amazon.com"
End Sub

Private Sub Form_BeforeUpdate(Cancel As Integer)
    Dim response
    response = MsgBox("Do you want to save this as new record? Are you sure?" & vbCrLf & _
    "Yes=Save new record" & vbCrLf & "No=Close and don't save", vbQuestion + vbYesNo, "Save Changes?")

    If response = vbYes Then
        If matchExactCaseNumber(Me.exact_case_number) = True Then
            MsgBox "This Exact Case number: " & vbCrLf & vbCrLf & _
            Me.exact_case_number & vbCrLf & vbCrLf & _
            "already exists in health_appeals table, please open the update form and update the old case! ", vbInformation
            Me.Undo
            DoCmd.OpenForm "frmHealthAppeals", acNormal
        Else
            MsgBox "New record saved!", vbInformation
            DoCmd.OpenForm "frmHealthAppeals", acNormal
        End If
    ElseIf response = vbNo Then
        'Cancel = False
        Me.Undo
        DoCmd.OpenForm "frmHealthAppeals", acNormal
    Else
        Cancel = True
    End If
End Sub

Public Function workdocsPath() As String
Dim Path As String: Path = "UK Health & Attendance\Appeals\"
workdocsPath = "W:\Team Spaces\CTK Absence Management\" & Path
End Function

Public Function healthFolder() As String

Dim desktopPath As String
Dim folder As String

desktopPath = Environ("USERPROFILE") & "\Desktop\"
folder = desktopPath & "Health&Attendance"

If Dir(folder, vbDirectory) = "" Then
    MkDir folder
    healthFolder = folder
Else
    healthFolder = folder
End If
End Function

Private Sub cmdOutcomeLetter_Click()
    Path = workdocsPath()

    savePath = healthFolder()
    
    Dim wordApp As Object
    Dim wordDoc As Object
    
    Set wordApp = CreateObject("Word.Application")
    
    wordApp.Visible = True
    
    Set wordDoc = wordApp.Documents.Open(Path & "health_appeal_outcome.docx")
    
    With wordDoc
    
    
        .FormFields("today").Result = Format(Date, "dd mmmm yyyy")
        .FormFields("respondent_name").Result = Me.respondent_name
        
    '    ' Home Address 1
    '    If IsNull(Me.home_address_one) Then
    '        .FormFields("home_address_one").Delete
    '    Else
    '        .FormFields("home_address_one").Result = Me.home_address_one
    '    End If
    '    ' Home Address 2
    '    If IsNull(Me.home_address_two) Then
    '        .FormFields("home_address_two").Delete
    '    Else
    '        .FormFields("home_address_two").Result = Me.home_address_two
    '    End If
    '    ' Postcode
    '    If IsNull(Me.postcode) Then
    '        .FormFields("postcode").Delete
    '    Else
    '        .FormFields("postcode").Result = Me.postcode
    '    End If
    '    ' City
    '    If IsNull(Me.city) Then
    '        .FormFields("city").Delete
    '    Else
    '        .FormFields("city").Result = Me.city
    '    End If
    '    ' County
    '    If IsNull(Me.county) Then
    '        .FormFields("county").Delete
    '    Else
    '        .FormFields("county").Result = Me.county
    '    End If
        
        .FormFields("mails").Result = Me.personal_mail_address & ";" & Me.work_mail_address
        .FormFields("respondent_name_two").Result = Me.respondent_name
        .FormFields("meeting_date").Result = Format(Me.meeting_date, "dd mmmm yyyy")
        .FormFields("pxtoc_expert_two").Result = Me.pxtoc_expert
        .FormFields("notetaker_name").Result = Me.notetaker_name
        .FormFields("pxtoc_expert").Result = Me.pxtoc_expert
        .FormFields("respondent_name_thre").Result = Me.respondent_name
    
    End With
    
    
    wordDoc.SaveAs savePath & "\" & Me.respondent_name & " - Disciplinary Appeal Outcome Letter.docx"
    
    
    wordDoc.Activate
    wordDoc.Windows.Application.WindowState = wdWindowStateMinimize
    wordDoc.Windows.Application.WindowState = wdWindowStateMaximize
    
    Set wordApp = Nothing
    Set wordDoc = Nothing
End Sub

Now, all that code was for a form where I am creating a case and have the option to save it in the database. Once I decide to come back to a case and modify it, I use a second form to retrieve it from the database, the code for the form which updates a case is this:

Option Compare Database

Private Sub cmdCloseWindow_Click()
DoCmd.Close acForm, Me.Name
DoCmd.OpenForm "frmFormalHealth", acNormal
End Sub
'_____________________________________________
'_____________________________________________
'__________ Utilities Functions_______________
'_____________________________________________
'_____________________________________________
Public Function workdocsPath() As String
Dim Path As String: Path = "UK Health & Attendance\Appeals\"
workdocsPath = "W:\Team Spaces\CTK Absence Management\" & Path
End Function

Public Function healthFolder() As String

Dim desktopPath As String
Dim folder As String

desktopPath = Environ("USERPROFILE") & "\Desktop\"
folder = desktopPath & "Health&Attendance"

If Dir(folder, vbDirectory) = "" Then
    MkDir folder
    healthFolder = folder
Else
    healthFolder = folder
End If


End Function
Public Function Emailer(ValueCell As String) As String
Dim cellValue As String
Dim valuesArray() As String
Dim i As Long

valuesArray = Split(ValueCell, ",")

For i = LBound(valuesArray) To UBound(valuesArray)
    valuesArray(i) = valuesArray(i) & "@amazon.com"
Next i

Emailer = Join(valuesArray, ";")

End Function

Private Sub cmdOutcomeLetter_Click()
    Path = workdocsPath()

    savePath = healthFolder()
    
   ' Dim wordApp As Object
    'Dim wordDoc As Object
    
    'Set wordApp = CreateObject("Word.Application")
    
    'wordApp.Visible = True
    
    'Set wordDoc = wordApp.Documents.Open(Path & "health_appeal_outcome.docx")
    
    'With wordDoc
    
    
     '   .FormFields("today").Result = Format(Date, "dd mmmm yyyy")
      '  .FormFields("respondent_name").Result = Me.respondent_name
        
    '    ' Home Address 1
    '    If IsNull(Me.home_address_one) Then
    '        .FormFields("home_address_one").Delete
    '    Else
    '        .FormFields("home_address_one").Result = Me.home_address_one
    '    End If
    '    ' Home Address 2
    '    If IsNull(Me.home_address_two) Then
    '        .FormFields("home_address_two").Delete
    '    Else
    '        .FormFields("home_address_two").Result = Me.home_address_two
    '    End If
    '    ' Postcode
    '    If IsNull(Me.postcode) Then
    '        .FormFields("postcode").Delete
    '    Else
    '        .FormFields("postcode").Result = Me.postcode
    '    End If
    '    ' City
    '    If IsNull(Me.city) Then
    '        .FormFields("city").Delete
    '    Else
    '        .FormFields("city").Result = Me.city
    '    End If
    '    ' County
    '    If IsNull(Me.county) Then
    '        .FormFields("county").Delete
    '    Else
    '        .FormFields("county").Result = Me.county
    '    End If
        
       ' .FormFields("mails").Result = Me.personal_mail_address & ";" & Me.work_mail_address
       ' .FormFields("respondent_name_two").Result = Me.respondent_name
       ' .FormFields("meeting_date").Result = Format(Me.meeting_date, "dd mmmm yyyy")
       ' .FormFields("pxtoc_expert_two").Result = Me.pxtoc_expert
       ' .FormFields("notetaker_name").Result = Me.notetaker_name
       ' .FormFields("pxtoc_expert").Result = Me.pxtoc_expert
       ' .FormFields("respondent_name_thre").Result = Me.respondent_name
    
    'End With
    
    
    'wordDoc.SaveAs savePath & "\" & Me.respondent_name & " - Disciplinary Appeal Outcome Letter.docx"
    
    
    'wordDoc.Activate
    'wordDoc.Windows.Application.WindowState = wdWindowStateMinimize
    'wordDoc.Windows.Application.WindowState = wdWindowStateMaximize
    
    'Set wordApp = Nothing
    'Set wordDoc = Nothing
End Sub

As you can see, the functions are identical minus some functions that are not needed inside the form I am updating the fields. Now, when I try to click on the OutcomeLetter and the function cmdOutcomeLetter_Click() runs, I am getting this error at line "Path = workdocsPath()". I have already tested it and the filepath seems to be correct. I just can't understand why is this error occurring.

I have tried to double check the filepath and it seems correct, I have also tried to comment out line "Path = workdocsPath()" where I get this error, and then feed in directly the path of the file to the wordApp.Documents.Open line like so:

Set wordDoc = wordApp.Documents.Open("W:\Team Spaces\CTK Absence Management\UK Health & Attendance\Appeals\health_appeal_outcome.docx")

And surprisingly, this works, but as soon as I use the workdocsPath() function to retrieve the path (which seems to be correct, when it assigns the value of workdocsPath() to Path in line "Path = workdocsPath()", that's when I get the error.

I FOUND out why is this not working, basically when in debugger mode, if I hover over Path variable from line Path = workdocsPath(), it does not have the value of the path retrieved by workdocsPath, I suspect that's why I was getting an error, Path was supposed to be empty, however, it is not so what I did was created another new variable to store the file path and it WORKS.

But now I am intrigued why I cannot reuse the Path variable? Why should I be forced to create a new one? Here is what I did that solved the problem but I still cannot reuse Path for this...:

Dim filePath As String: filePath = workdocsPath()

And so I used the new filePath variable instead. But I should be able to reuse Path, because when I create the case with the first form, I reuse the variable Path with no issues, not sure why with the second form I am unable to reuse it?

Upvotes: 0

Views: 152

Answers (1)

Albert D. Kallal
Albert D. Kallal

Reputation: 49069

Make sure you ALWAYS include Option explicit in all of your code modules.

When you use the variable workdocsPath, that variable will be local to the one routine, and THEN it goes out of scope when you exit that sub/function. However, other code will compile - since you not FORCING that all variables are to be declared. Had you done this, then your code would not have compiled.

So, for all code modules, always, and I repeat ALWAYS have this:

Option Compare Database
Option Explicit

You can have the VBA editor always automatic add "Option Explicit" for you with this option:

From VBA editor -> tools->options, and select this option:

enter image description here

Note that selecting the above option does not change existing modules, but for all new reports/forms, and code modules, then Option Explicit will be automatically added.

Selecting the above means bugs and issues such as your example here would not have occurred.

 Sub MyTest

    sFun = "Hello"

 End Sub


 Sub Mytest2
    
     debug.print sFun

 End Sub

So, in above, when you exit the first sub, then the variable sFun goes out of scope (does not exist). However, since you don't have Option Explicit, then the above code compiles fine. If you turn on option explicit, then the above code will not compile, thus avoiding such errors.

Upvotes: 0

Related Questions