Is this a single user database or one hosted over a network?
If this is a single user database, replace your global variable with a global field and the value will be retained.
But if the file is hosted over a network, that won't work. You can save the value to a field in a record, but you now have additional complications as different users will have different values in the variable at the same time and thus each time a user closes the file and it saves, the previously saved value would be replaced by that of the current user--and that could raise a number of problems unless you set up one record in your table for each user. (once that's resolved, a startup script can copy the value from this table into the variable to restore it's value each time the file is opened and that avoids needing to link the same table to multiple other tables in order to make the value globally accessible.
It is indeed hosted over a network to multiple users and while only one user should be accessing this function, it still needs to be 'universal' for all users so my first thought is to create a new database with just one record. Then whenever I need to increment that number, I use a script to look up that single record in that database.
Will attempt that... can't do it through relationship cause that will just create a new record in the related database to match the record the user is on in the other database. Going to have to switch layout to this target database, get record one, grab the value, increase by one, blatz it back and return to the prior page. Here goes nothing :D
You'll need to use a non-global field if this value is to be "universal to all users". If a user modifies the value of a global variable or global field, the changes to that field or variable will be invisible to others nor will the value be retained when the user closes the file. This is actually by design as these variables and fields are intended for use in ways where it is necessary to keep the values unique to the current user rather than shared between all users.
You'll need a related table linked by the X operator so that all records in your layout's table can refer to the same single record in your table. And you'll need multiple occurrences of this added table if you need to access this same value from the context of other Tutorial: What are Table Occurrences?.
Edited for clarity:
So here's what I did that required no additional relationships and is a universal, shared variable page amongst everyone. I created a new table, one record, one field (could be many) - these are the global variables.
Then from another layout, open a new window; go to the variable layout; go to the first record; manipulate variables you need; re-commit record; store values you need in $local temp variables; CLOSE WINDOW; then place $local temp variables where you need it on your current layout.
Opening a new window just allows me to not have to deal with getting back to the correct record that needs this number in the layout the user was on when the script fired off.
But this still has a possible problem if you really want these values to be "universal to all users". If user 1 changes the value of the variable in one way and User 2 changes the value in a different way, they won't be able to see each other's changes and only one value will be saved--the value saved by whichever users was last to close the file.
Understood - however, this is more a 'variable' page. Never accessed by a human but through a script. It should be fine if two people fire it off at the same time as the table being accessed will simply be changed by the script fired off which loads the current value (number only), increments it, then stores it back. Since it's the same table accessed by 2 or every 200 users, it's still just one record, one value on that page getting hit and incremented. Should be universal for all. I hope :)
This does not appear to be the case. Whether it is a script or a direct user edit that changes the values, the changes made in one user's session will not be seen by other users.
Here's another example: Say you have a variable named $$Count and every time a particular script is run, it is incremented by 1.
If user 1 and user 2 both have the file open at the same time, they both see the most recently saved value for $$Count, 25. Now both users run the script to increment the value of $$Count, then close and save the value of $$Count.
The saved value will be 26, not 27 because the script computed the same value 26 for both users and then this same value was saved twice--once for each user.
Sorry, I may of forgot to explain I've ditched the 'global' variable approach using $$ or global fields. Hence why the new actual table, there's just one record and the fields on that one record act as the bible of 'permanent' variables for everyone. Need to update a variable? Just open a new window, go to this layout, go to record 1 and grab the 'field' which will now act as a 'global' variable for all intents and purposes across the board and will retain on closing. The script will use a temp variable to only pass this value from one table to another. Just close this new window and you'll be back on the same page to populate your new values.
But when your scripts modify a value, Do they modify the variable or the field? If they modify a variable's value and then copy that to a field to retain the value, the issue remains. If all value changes are only made directly to the fields, then my objection no longer applies.
Yes, I'm updating the changes on this master variable page with any changes, then COMMITTING it, sealing the changes globally. I'm also just taking that value back to the other window left after the close with a temp variable in the script to commit that to it's page. It's an incrementing invoice # but it's not one that I can just have increment with say a new record in the table it's in. It has to be generated as needed and you may have to blow through several 'records' before you can actually create one of these numbers.
Also Phil, Thank for taking the time to answer these questions. You've been doing it for years and that takes dedication and empathy for as sorta-newbs in the FMP world.
What's next? Duplicating a record (easy) but along with all the info from two portals on the page (not so easy). Google here I come ;)
Warning: your method can generate two invoices with the same invoice number if two users assign invoice numbers at just the wrong instance.
I would definitely not use the method from this thread to generate invoice numbers on demand. Not only does it risk getting two records with the same invoice number, there's a simpler way to do it.
Say your table is named Invoices. Add a new table InvoiceNumbers and link it to invoices like this:
Invoices-----InvoiceNumbers (this is a one to one relationship)
Invoices::__pkInvoiceID = InvoiceNumbers::_fkInvoiceID
__pkInvoiceId is an auto-entered serial number. It's the primary key for invoices, but it's NOT your invoice number as that needs to be created "on demand".
In the above relationship, enable the "allow creation of records via this relationship" option for InvoiceNumbers.
Define a field, InvoiceNumber in the InvoiceNumbers field as an auto-entered serial number field. THIS field will be your invoice number field and will be assigned to a record in the Invoices table "on demand".
Whenever you need to assign an invoice number to an invoice record, run this simple script:
Set Field [InvoiceNumbers::_fkInvoiceID ; Invoices::__pkInvoiceID ]
The first time that this script is run for an invoices record, this step creates a single related record in InvoiceNumbers, the InvoiceNumber field auto-enters a unique serial number and you have the result that you need. You can place InvoiceNumbers::InvoiceNumber on any Invoices layout where you need to show that number. With the auto-entered serial number, FileMaker will ensure that each new record gets the next number in the series with no possibility of getting a duplicate value.
Should you accidentally run this script a second time on the same invoices record, no change to your data takes place and the previously assigned invoice number remains unchanged.
Very cool - Thanks Phil - While there would never be anyone hitting this script exactly at the same time, I can see what you mean. I thought I read though that FMP's script engine was FIFO and not multi-threaded but why take the chance :) Will give it a shot! I did low-level prevent duplicating an invoice # request by checking if there was already an invoice #, etc -
The script in question runs on the client machine. So it is quite possible to have two or more scripts running at the same time--one on each client machine so all you need are two or more users running the sane script to increment your invoice number at the same time and there's a chance that two invoices will get the same number.
By contrast, the auto-entered serial number action takes place on the server and thus cannot happen simultaneously on different client machines.
Worked great Phil! Thanks for the clarity!