schrijven naar tabel Logboek werkt niet (lijkt niet te werken....)

  • Onderwerp starter Onderwerp starter IsR
  • Startdatum Startdatum
Status
Niet open voor verdere reacties.

IsR

Gebruiker
Lid geworden
2 jul 2015
Berichten
94
Goedendag allen,

Ik probeer een zgn. audittrail op te zetten in access (2013).
De input van waarden gebeurt via een formulier die vervolgens in een tabel worden weggeschreven.
Wijzigingen in een tabel (via een formulier) moeten worden weggeschreven in een tabel "logboek".
Als test heb ik in 1 veld van de tabel (accountmanager) een "na-bijwerken"-macro gemaakt, maar die doet niets. (tenminste niet wat ik wil).
Als ik de inhoud van het veld accountmanager wijzig (via het formulier of rechtstreeks in de tabel) en opslaan, gebeurt er niets.
Er wordt helemaal geen record in tLogboek gemaakt.

Zie onderstaand een screenshot van de macro.
audittrail.JPG

Wat klopt er niet en wie kan me helpen bij de oplossing?
BvD,
IsR
 
Ik zie dat je bent 'overgestapt' van VBA naar macros. Wat mij betreft de omgekeerde weg, en al helemaal voor dit probleem. Zou ik echt met VBA doen. Dus mocht je je bezinnen, en een VBA oplossing prefereren, dan haak ik graag weer aan :). Gezien het aantal reacties, verwacht ik dat toch wel vrij snel :D.
 
Hallo Octafish,
Bedankt voor de reactie.
Het is niet zozeer dat ik ben "overgestapt", maar in mijn queeste naar een oplossing, kwam ik dit tegen als een "redelijk makkelijke implementeerbare oplossing", dacht ik.
Naar blijkt nu, toch niet zo makkelijk als het leek.
Ik sta overal voor open. Als de beste oplossing voor een probleem een macro is, gebruik ik die. Is het makkelijker of beter realiseerbaar/ontwikkelbaar via VBA, gebruik ik VBA.
Enige maar daar van is, dat ik daar nog niet zo in thuis ben (zoals je wellicht al gemerkt hebt) en het dus nog iets lastiger is voor mij om e.e.a. juist te implementeren.

Desalniettemin, zoals gezegd ik sta open voor alle opties en wil graag meer leren van VBA. Ik heb nl. al wel gemerkt dat de mogelijkheden daarvan vele malen groter zijn.
Wie me de weg kan wijzen, ben ik dankbaar.
Dus suggesties / hulp is altijd welkom.
 
Als de beste oplossing voor een probleem een macro is, gebruik ik die. Is het makkelijker of beter realiseerbaar/ontwikkelbaar via VBA, gebruik ik VBA.
In het kader van een consistente (ontwikkelde) database, zou ik mij bij één techniek houden. Het onderhoud van een database die op 2 poten hangt is een stuk lastiger dan een db die met één techniek is gebouwd. Kijk alleen maar naar de bron zelf: Microsoft... Dat bedrijf ontwikkelt software op (vermoed ik) afdelingen die totaal niet met elkaar communiceren. Resultaat: in het ene pakket moet je op <Ctrl>+<Enter> drukken voor een nieuwe regel, in het andere op <Shift>+<Enter> en het derde pakket gebruikt <Altl>+<Enter>. En dat allemaal voor een opdracht die in elk pakket hetzelfde oplevert. Je gaat mij toch hopelijk niet vertellen dat dat handig of logisch is? :D. Iets vergelijkbaars doe je nu dus zelf. Als straks iemand anders de db moet gaan beheren, moet hij/zij eerst gaan zoeken of je een macro of een VBA procedure gebruikt hebt. Terwijl macro's dus a) nooit meer kunnen als VBA, en b) ook nog eens niet makkelijker zijn :).

Terug naar je vraag :). Hier een voorbeeldje dat ik zelf gebruik:

Code:
Private Sub cmdOpslaan_Click()
sUser = Environ("Username")

    sInlogNaam = sUser

    For Each ctl In Controls
        With ctl
            Select Case .ControlType
                Case acTextBox
                    If Left(.Name, 5) = "Tekst" Or Left(.Name, 4) = "text" Then
                        If .Tag = "" Then MsgBox .Name
[COLOR="#0000FF"]                        sVeld = .Tag
                        If Nz(.Value) <> Nz(Me(sVeld).Value) Then
                            sWaarde_Ori = Nz(Me(sVeld).Value)
                            sWaarde_Nieuw = Nz(.Value)
                            strSQL = "SELECT [" & sVeld & "] FROM [Brontabel] WHERE [Extern_ID] = " & Me.Extern_ID
                            With CurrentDb.OpenRecordset(strSQL)
                                If .RecordCount > 0 Then
                                    .Edit
                                    .Fields(sVeld).Value = sWaarde_Nieuw
                                    .Update
                                    .Close
                                Else
                                    .Close
                                End If
                            End With
[/COLOR]                            If Me.Dirty Then Me.Dirty = False
[COLOR="#008000"]                            With CurrentDb.OpenRecordset("SELECT * FROM tHistorie")
                                .AddNew
                                !Extern_ID = Me.Extern_ID
                                !Datum = Date
                                !Tijd.Value = TimeSerial(Hour(Now()), Minute(Now()), 0)
                                !UserID = sUser
                                !Actiesoort = 1
                                !Tabel = "[Brontabel]"
                                !Veld_Ori = sVeld
                                !Waarde_Ori = sWaarde_Ori
                                !Waarde_Nieuw = sWaarde_Nieuw
                                .Update
                                .Close
                            End With
[/COLOR]                            If Me.Dirty Then Me.Dirty = False
                        End If
                    End If
            End Select
        End With
    Next ctl
    
[COLOR="#B22222"]    'Handeling loggen
    sQuery = "INSERT INTO tLogin(UserID,Datum,Tijd,Actie)" & vbCrLf
    sQuery = sQuery & "VALUES('" & FnUser & "', CDate(" & CDbl(Date) & "), #" & Format(Now, "HH:mm") & "#, 'Record bijgewerkt" & "')"
    DoCmd.SetWarnings False
    CurrentDb.Execute sQuery, dbFailOnError
    DoCmd.SetWarnings True
[/COLOR]    
    Me.fHistorie.Requery
    Me.Repaint

End Sub

Ziet er misschien een beetje gecompliceerder uit dan je macro, maar is dat eigenlijk niet, vind ik althans :). De hele procedure is gebaseerd op het uitlezen van velden op een formulier, en op basis daarvan een historie record aanmaken. Het formulier bevat voor elk veld 2 tekstvelden: één veld met de originele waarde, en één veld met de nieuwe waarde. De velden zijn aan elkaar 'gekoppeld' doordat de mutatievelden (die allemaal 'tekst'## heten) de naam van het gekoppelde veld hebben gekregen in de eigenschap <Extra info> (<Tag) van het tekstveld. Dus een tekstveld [Achternaam] heeft een koppelveld [Tekst12] en [Tekst12] heeft dan in de Tag 'Achternaam' staan.

In mijn voorbeeldje schrijf ik elke mutatie op een willekeurig veld weg. Dat maakt het lastig, want je weet niet welk veld er is gemuteerd, dus je moet ze allemaal langslopen. Dat gebeurt met het eerste stuk:
Code:
    For Each ctl In Controls
        With ctl
            Select Case .ControlType
                Case acTextBox
                    If Left(.Name, 5) = "Tekst" Or Left(.Name, 4) = "text" Then
Daarna ga je kijken of het gevonden tekstveld gelijk is aan het originele veld. Zo nee, dan is er een mutatie en moet je de mutatie wegschrijven. Dat gebeurt in het blauwe gedeelte. In het volgende deel zie je dat vergelijken nog een keer staan:
Code:
                       sVeld = .Tag
                        If Nz(.Value) <> Nz(Me(sVeld).Value) Then
                            sWaarde_Ori = Nz(Me(sVeld).Value)
                            sWaarde_Nieuw = Nz(.Value)
In de rest van het blauwe deel wordt de record opgezocht met een recordset (met een filter op KlantID), het record wordt in de Edit modus gezet en de tabel wordt bijgewerkt. Daarna wordt in het groene deel de Historie tabel geopend, en worden de
mutaties daarin weggeschreven. Daarom zie je in het blauwe deel .Edit staan en in het groene deel .AddNew.
Als extraatje zie je nog een andere logtechniek, waarbij je met een query ongeveer hetzelfde kan bereiken. Al is de bijgeleverde query niet zo geavanceerd als de control techniek. Je logt dus op een wat lager niveau.

Ik zou zeggen: kijk eens of je er wat mee kunt :).
 
Wauw Octafish, dat is me nogal een duw in de juiste richting.:thumb:
Ik ga zeker kijken wat ik ermee kan / of ik er uit kom en laat de vorderingen natuurlijk weten.

Voor wat betref je opmerkingen over consistentie/onderhoud db; Ik kan me daar wel wat bij voorstellen, ik zie je punt en zal proberen in mijn database dit zoveel mogelijk te hanteren.;)
 
Even kort: wat betekent het "s"-je in de code:
sUser
sWaarde
sQuery
en het uitroepteken!; !Extern_ID, !Datum

En moet de "rode" code er ook in staan (dat was toch de aanvullende, maar niet verplichte optie?)
 
sUser etc is een manier om variabelen een herkenbare naam te geven. Had ook strUser of Appie mogen zijn. Wat jij wilt dus.
Het rode stuk hoef je inderdaad niet te gebruiken. Ik gebruik bij voorkeur de uitgebreide variant omdat je dan op veldniveau kan herstellen.
 
Ik ben erin gedoken en heb nog wat vragen.

- sUser; kan ik jouw code vervangen door het veld waarin ik de inlognaam heb vastgelegd?
(Je hebt al eerder de TempVar optie genoemd, maar daar kan ik nog even geen weg mee, weet ook niet hoe ik dat moet gebruiken bij gelijktijdig gebruik van de database door meerdere gebruikers wat wel de
bedoeling is, maar daar zal ik wel een apart topic van maken geloof ik).
- Hoe moet ik de ".name" lezen?
- Is de [Brontabel] de tabel waar het formulier op gebaseerd wordt?
- Wat is [Extern_ID] ? Is dat de PK van het gecontroleerde record?
- De tabel tHistorie is dat een tijdelijke tabel of moet ik die vervangen door de naam van de tabel die ik gebruik om wijzigingen in vast te leggen (ik denk van wel)?
- !Actiesoort is het type wijziging? (toevoegen, wijzigen, delete)? Die leg ik nl. (nog) niet vast.
- fHistorie; waar komt die vandaan?
- en waarom heb je een variabele sInlognaam in je code staan? Je hebt toch al een variabele sUser gemaakt?
Ik zie nl. sInlognaam verder nergens terug
 
Laatst bewerkt:
Ja, dat kan (eerste vraag). Maar
(Je hebt al eerder de TempVar optie genoemd, maar daar kan ik nog even geen weg mee)
Dat is echt niet zo moeilijk. Op het startformulier (waar je de db dus mee start) zet je deze code:
Code:
Private Sub Form_Load()
    TempVars.Add "sUser", Environ("Username")
    MsgBox TempVars("sUser")
End Sub
En meer is het niet! De msbox hoeft uiteraard niet, dat is nu alleen controle om te laten zien wat er in staat. Maar gebruik ik hier om te laten zien hoe je de TempVar verder kunt gebruiken. Zodra hij is gedefinieerd en gevuld, kun je hem namelijk overal gebruiken. Om de gebruiker in een tabel op te slaan mag dus wel, maar ik zie eerlijk gezegd de noodzaak niet. Het lijkt mij meer dan voldoende als je de acties van de gebruiker kunt loggen. Ongeacht wat er in een tabel staat.

- De .name komt door de With constructie. Die gebruik je als je van een object meerdere eigenschappen wilt gebruiken. Je laat dan in de regels tussen With en End With het object zelf weg. In dit geval moet je dus lezen: ctl.Name.
- Brontabel is inderdaad de tabelnaam dus die zul je moeten vervangen.
- Extern_ID is in mijn voorbeeld het sleutelveld uit de brontabel. Mag uiteraard ook weer elke andere naam zijn.
- tHistorie is mijn historie tabel, en dus zeker geen tijdelijke tabel. In de db waar dit voorbeeld uit komt, staat de historie tabel op het formulier (fHistorie op een apart tabblad) van de brontabel. Je ziet dan dus per record de mutaties terug.
- En Actiesoort is een veld dat in de db gebruikt wordt. Zou je dus weg kunnen laten. Of gebruiken voor eigen doeleinden :).

De reden dat ik het zo doe (elke mutatie voor elk veld apart opslaan) en de mutaties op het formulier laten zijn bij het bijbehorende record is omdat ik op deze manier elke mutatie weer kan herstellen. In dit geval klik je dan op een specifieke mutatie op het formulier, en er wordt dan een bijwerkquery uitgevoerd die de velden weer terugzet.
Maak je een kopie van een compleet record in je historietabel, wat uiteraard ook kan, dan wordt dat een stuk lastiger. Dan is het wel simpel om een compleet record terug te zetten. 't Is maar wat je nodig hebt.
 
Kun je dan ook meerdere tempVars aanmaken? Dus TempVar1, TempVar2 etc?
Dit omdat er meerdere gebruikers gelijktijdig van de database gebruik zullen maken. Hoe werkt het dan?
De bedoeling is wel om een record te locken zodra 1 iemand er iets in wil wijzigen.
 
Dit omdat er meerdere gebruikers gelijktijdig van de database gebruik zullen maken.
Hang je dan meer muizen en toetsenborden aan één computer? :D. Ik neem aan dat elke gebruiker zijn/haar eigen FE gebruikt op de backend. Op de eigen computer. Dus het probleem speelt helemaal niet. Maar buiten dat: je kunt net zoveel Tempvars maken als je zelf wilt. Zolang ze maar een unieke naam hebben.
 
Altijd leuk dat ik nog iemand laat op de avond aan het lachen heb kunnen maken;)
Eeeuh, ik ging uit dat 1 front-end en 1 back-end genoeg was en dat iedereen op dezelfde front-end kon inloggen. (dus meerdere toetensborden en muizen aan het netwerk zeg maar.... :).
Maarrrrrr dat zouden dus beter meerdere front-ends zijn. Altijd handig om dat tussen neus en lippen door ook nog even mee te krijgen.
 
Ja, als je met een FE-BE constructie werkt, is het vele malen beter om elke gebruiker een eigen FE te geven. Kwestie van één FE maken en die bij elke gebruiker apart uitrollen. Record locks vinden dan binnen de eigen FE plaats, en de gebruikers zitten elkaar dus verder niet in de weg. Eén FE op één BE heeft dezelfde beperking als één db maken waar iedereen dan in werkt. Heeft dus eigenlijk geen toegevoegde waarde.
 
Code:
Select Case .ControlType
Case acTextBox
                    If Left(.Name, 5) = "Tekst" Or Left(.Name, 4) = "text" Then
                        If .Tag = "" Then MsgBox .Name
                        sVeld = .Tag
                        If Nz(.Value) <> Nz(Me(sVeld).Value) Then
                            sWaarde_Ori = Nz(Me(sVeld).Value)
                            sWaarde_Nieuw = Nz(.Value)
                            strSQL = "SELECT [" & sVeld & "] FROM [tContactpersonen] WHERE [contact_ID] = " & Me.contact_ID
                            With CurrentDb.OpenRecordset(strSQL)
                                If .RecordCount > 0 Then
                                    .Edit
                                    .Fields(sVeld).Value = sWaarde_Nieuw
                                    .Update
                                    .Close
                                Else
                                    .Close
                                End If
                            End With

Hoe werkt dit stukje nou precies?
De select Case Controltype, case acTextbox impliceert dat ook voor comboboxen een code moet zijn???
En wat gebeurt er met Controls die geen naam hebben die niet beginnen met "Tekst"of "Text". Als ik de code nl. goed lees, wordt de tag/Extra Info dan sowieso niet gevuld.

Verder heb ik wat veldnamen aangepast zoals je ziet en loopt de code verder niet goed:

Na het tonen van een msgbox waarin staat Tekst350 (naam van een tekstveld waarin ik een expressie heb staan die de "contactpersoon 1 van x" toont) en ik op OK klik, stopt de code met melding:
"Fout 2465 tijdens uitvoering. Kan het veld niet vinden waarnaar wordt verwezen in de expressie".
Als ik vervolgens in de foutopsporing kijk, wordt verwezen naar
Code:
If Nz(.Value) <> Nz(Me(sVeld).Value) Then
.
Het lijkt erop dat de 1) de "Tag" van dat tekstveld niet wordt gevuld en daardoor de variabele sVeld ook niet wordt gevuld en daardoor niet wordt herkend in bovenstaande coderegel.

Klopt mijn vermoeden en hoe kan ik dit oplossen?
 
Om bij het begin te beginnen: hier een uitgebreider voorbeeldje.

Code:
    For Each ctl In Controls
        With ctl
            Select Case .ControlType
                Case acTextBox
                    If Left(.Name, 5) = "Tekst" Then
                        sVeld = .Tag
                        .Value = Nz(Me(sVeld).Value, "")
                    End If
                On Error GoTo 0
                Case acComboBox
                    If Left(.Name, 10) = "Keuzelijst" Then
                        sVeld = .Tag
                        .Value = Me(sVeld).Value
                    End If
                Case acCheckBox
                    If Left(.Name, 3) = "chk" Then
                        sVeld = .Tag
                        .Value = Me(sVeld).Value
                        Exit For
                    End If
            End Select
        End With
    Next ctl

Eigenlijk is de procedure voor elk object hetzelfde: je leest de tag uit, en stelt een waarde in. Waarom dan toch verschillende? Dat komt doordat de naamgeving van de objecten bij elk objecttype anders is. Dat hoeft overigens niet; als je een naamgeving hanteert die voor elk object dezelfde naamstructuur heeft, dan ben je er ook. Krijg je iets als:

Code:
    For Each ctl In Controls
        With ctl
            Select Case .ControlType
                Case acTextBox, acComboBox, acCheckBox
                    If LCase(Left(.Name, 5)) = "nieuw" Then
                        sVeld = .Tag
                        .Value = Nz(Me(sVeld).Value, "")
                    End If
            End Select
        End With
    Next ctl

Het hele principe is gebaseerd op het idee dat je speciale objecten (tekstvakken, keuzelijsten, selectieveldjes) hebt die alleen uitgelezen moeten worden. De For Each ctl In Controls regel zorgt ervoor dat alle objecten op een formulier worden geëvalueerd. Dus ook labels, lijnen, knoppen etc. Die kun je uiteraard niet allemaal gebruiken; een knop heeft nu eenmaal geen waarde. Je moet dus, als je alle objecten doorloopt, onderscheid maken in welke objecten wél, en welke níet. Dat doe je dus met ControlType.

Daarnaast is niet elk tekstvak of selectievakje geschikt; je wilt alleen die objecten gebruiken die daarvoor bedoeld zijn. Daarom moet je onderscheid maken in die objecten. Vroeger, toen ik deze techniek nog niet gebruikte, was ik van mening dat een object een logische, verklarende naam moet hebben. In beginsel vind ik dat nog steeds. Om nu onderscheid te maken tussen het oude veld txtAchternaam en het nieuwe tekstveld, geef ik dat laatste dus bijvoorbeeld de naam nieuwAchternaam. En het veld txtAdres kent een broertje met de naam nieuwAdres. De code moet dus, om te weten welk tekstveld wel en welke nieuw, kijken naar de naam van het object, meer specifiek naar de beginletters ervan. Doe je dat consequent, dan pak je nooit verkeerde velden op en schrijf je dus ook nooit verkeerde velden weg.
Dat lost hopelijk dit probleem op:

Na het tonen van een msgbox waarin staat Tekst350 (naam van een tekstveld waarin ik een expressie heb staan die de "contactpersoon 1 van x" toont) en ik op OK klik, stopt de code met melding:
"Fout 2465 tijdens uitvoering. Kan het veld niet vinden waarnaar wordt verwezen in de expressie".

Standaard krijgen objecten een naam volgens een vast patroon: tekstvakken de naam Teksvak12, Teksvak14, keuzelijsten de naam Keuzelijst89 etc. Als ik een 'normaal' tekstvak, zoals in jouw voorbeeldje, zou dat bij mij zonder meer, en vrijwel gelijk, een naam krijgen als: txtContactPersoon. Een normale keuzelijst geef ik gelijk een naam als cboLand, en ga zo maar door. De belangrijkste reden? Als ik formules ga maken met de functie Opbouwen, dan wil ik niet objecten zien met de namen Teksvak12, Teksvak14 en Tekstvak350, want die zeggen mij helemaal niks. Ik wil snel en foutloos kunnen zien waar dat object voor staat. Dus: altijd een logische naam!

Met dus de uitzondering voor objecten die ik juist wél op basis van standaardnamen wil verwerken, zoals in deze routine. Dat brengt mij bij het laatste stukje van de puzzel: hoe weet ik nu welk veld met welke waarde waar moet worden weggeschreven? Op het formulier is het duidelijk: de velden met de oude en nieuwe waarde staan waarschijnlijk naast of onder elkaar. Makkelijk zat. Maar waar het veld [Achternaam] niet alleen een herkenbare naam heeft, maar ook is gekoppeld aan het veld [Achternaam], is [Tekstveld16] dat niet. Maar dat bevat dus wél de nieuwe waarde.... En hier komt dus de eigenschap <Extra Info> (of Tag) om de hoek kijken.
Bij het maken van het formulier zet ik dus de origine velden op hun plek, de nieuwe niet-gebonden tekstvelden er naast, en kopieer ik de Besturingselementbron uit het oorspronkelijke object en plak ik dat in de eigenschap <Extra Info> van het nieuwe tekstveld. En dat herhaal je voor alle velden. Is meestal niet meer dan een half uurtje werk.

Goed, ik heb dus (voorbeeldje) 20 originele velden, en 20 velden voor de nieuwe waarden. Die 20 hebben allemaal een veldnaam in de <Extra Info> staan, en een naam als Tekstvak23. (Of Nieuw01, Nieuw02 etc als je niet lui bent :) ). Ik heb er voor gezorgd dat er geen enkel ander tekstveld is waarvan de naam met 'Tekst' begint, want zoals je al gemerkt hebt: die mogen dus niet meedoen in de procedure. Niet alleen bevatten ze niet de juiste informatie (nieuwe waarden voor je tabel), je hebt er vast ook geen <Extra Info> ingevuld. En dat is verplicht, want anders kan de procedure daar op vastlopen.

Ik hoop dat de procedure zo wat duidelijker is :).

Eén opmerking nog: het uitlezen is voor de meeste objecten identiek, behalve bij keuzelijsten waar je meerdere waarden kunt selecteren. Die moet je anders uitlezen. Je moet dan namelijk door alle geselecteerde waarden heenlopen en die ofwel samenvoegen in één string, ofwel apart opslaan. Maar dat speelt geloof ik niet nu.
 
Hoi Octafish,
Bedankt voor de uitgebreide toelichting.
Ik ga ermee aan de slag. Sorry mijn reactie duurde even omdat ik 1)parttime werk en 2)ondertussen ook weer met een ander onderdeel bezig was.
Ik ga het op mijn gemak doorlezen en proberen toe te passen.

Kan/wil jij een plaatje van zo'n formulier als voorbeeld posten?
Ik lees je uitleg nl. als volgt: dat dus voor elk veld op een formulier waarvan ik de wijziging wil tracen, het originele veld staat en een extra (verborgen??) veld waar de nieuwe waarde in komt te staan???
Klopt mijn aanname of geldt dat alleen in het geval je de naam van alle controls met dezelfde tekst laat beginnen?

En hoe vul ik nu de Tag (in het uitgebreidere voorbeeldje), want volgens mij zie ik alleen dat de variabele sVeld wordt gevuld met Tag.
Maar hoe de Tag gevuld wordt, zie ik hier niet.
Uit je eerdere post kan ik alleen herleiden dat als de Tag leeg is, er een Msgbox wordt getoond met de naam van het veld (niet de inhoud van het veld??)

(p.s. overigens heb ik ook te maken met het uitlezen van keuzelijsten die veranderd zijn/worden qua inhoud. Denk bijv. aan de cboMailing toegestaan die kan wijzigen van Ja naar Nee en andersom, maar misschien moet ik niet alles tegelijk willen???? :o)
 
Laatst bewerkt:
Een plaatje is uiteraard geen probleem. Zie bijlage :).

Nog een extra functie die je kunt gebruiken om waarden over te zetten....
Code:
Function CopyVeld()
Dim ctl As Control
    Set ctl = Screen.ActiveControl
    Me(ctl.Tag).Value = Me(ctl.Name).Value
End Function
Deze functie werkt ook weer met de Tag, zoals je ziet. In dit geval bevat het tekstvak dat de oorspronkelijke waarde bevat (in het plaatje de groene velden) in de eigenschap <Extra info> de naam van het teksveld waar de waarde naar toe gekopieerd moet worden. Deze keer gebruik je hem om één veld over te zetten naar een ander veld.
In mijn voorbeeld wordt zo het veld [Straat] gekopieerd naar het tekstveld [Tekst3]. In de eigenschap <Bij klikken> van het oorspronkelijke veld (Straat) zet je dus de actie =CopyVeld(). De gebeurtenis kopieert de waarde van het actieve control (toegewezen aan de variabele ctl) naar het tekstveld dat is benoemd in de eigenschap <Extra Info> (Tekst3).

Overigens werken keuzelijsten met invoervak exact hetzelfde als een tekstvak, dus dat maakt niet zoveel uit. Hooguit is de naamgeving anders (txt voor tekstvak, cbo voor keuzelijsten) en daarom scheid ik ze in de procedure.
 

Bijlagen

  • Historieformulier.png
    Historieformulier.png
    12,2 KB · Weergaven: 70
Goedemorgen Octafish,
Even een snel berichtje dat ik probeer deze week met je oplossing verder te gaan.
Ben er vorige week niet meer mee verder kunnen gaan.
Nu nieuwe poging.
Overigens bedankt nog voor je update.
 
Ik wacht je bevindingen af :).
 
nieuwe foutmelding

Octafish,

Ik heb een kleine testversie-database gemaakt (met 1 tabel contactpersonen, 1 logtabel en 1 formulier om elk andere variabele uit te sluiten) en heb jouw eerste code daarin geplakt.
Kom nu iets verder. Het lijkt erop dat ik de verkeerde verwijziging in de code had gebruikt (die van de originele velden i.p.v. de "mutatievelden"). Dit nu aangepast, maar nu krijg ik de volgende melding:"
Fout 3061 Tijdens uitvoering: Er zijn te weinig parameters. Het verwachte aantal is: 1.

Als ik op foutopsporing klik, kom ik uit bij:
Code:
With CurrentDb.OpenRecordset(strSQL)


De totale code die ik nu heb staan is:
Code:
Private Sub Opslaan_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
sUser = Environ("Username")

    sInlogNaam = sUser

    For Each ctl In Controls
        With ctl
            Select Case .ControlType
                Case acTextBox
                    If Left(.Name, 5) = "Tekst" Or Left(.Name, 2) = "NW" Then
                        If .Tag = "" Then MsgBox .Name
                        sVeld = .Tag
                        If Nz(.Value) <> Nz(Me(sVeld).Value) Then
                            sWaarde_Ori = Nz(Me(sVeld).Value)
                            sWaarde_Nieuw = Nz(.Value)
                            strSQL = "SELECT [" & sVeld & "] FROM [tContactpersonen] WHERE [contact_ID] = " & Me.contact_ID
                            With CurrentDb.OpenRecordset(strSQL)
                                If .RecordCount > 0 Then
                                    .Edit
                                    .Fields(sVeld).Value = sWaarde_Nieuw
                                    .Update
                                    .Close
                                Else
                                    .Close
                                End If
                            End With
                            If Me.Dirty Then Me.Dirty = False
                            With CurrentDb.OpenRecordset("SELECT * FROM tLogboek")
                                .AddNew
                                !Tabelnaam = "[tContactpersonen]"
                                !Veldnaam = sVeld
                                !Record_ID = Me.contact_ID
                                !OudeWaarde = sWaarde_Ori
                                !NieuweWaarde = sWaarde_Nieuw
                                !WijzigingDatum = Date & "" & TimeSerial(Hour(Now()), Minute(Now()), 0)
                                '!Tijd.Value = TimeSerial(Hour(Now()), Minute(Now()), 0)
                                !WijzigingDoor = sUser
                                '!Actiesoort = 1
                                .Update
                                .Close
                            End With
                            If Me.Dirty Then Me.Dirty = False
                        End If
                    End If
            End Select
        End With
    Next ctl
    
    'Handeling loggen
    'sQuery = "INSERT INTO tLogin(UserID,Datum,Tijd,Actie)" & vbCrLf
    'sQuery = sQuery & "VALUES('" & FnUser & "', CDate(" & CDbl(Date) & "), #" & Format(Now, "HH:mm") & "#, 'Record bijgewerkt" & "')"
    'DoCmd.SetWarnings False
    'CurrentDb.Execute sQuery, dbFailOnError
    'DoCmd.SetWarnings True
    
    'Me.tLogboek.Requery
    Me.Repaint

End Sub

Waarbij geldt dat elk "mutatieveld" begint met de naam "NW*" en ik in elk mutatieveld in de tag de veldnaam van het originele veld heb gezet.
Waar gaat het nu nog fout?
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan