You are right that Ignition doesn’t handle this by default, and doesn’t make it easy to handle this. But a lot depends on how your setup is done.
Ignition is most often meant to alter single data points (a bit to start something, a numeric parameter, …). Those can be written directly to the PLC, and if two people set something different, they need to communicate better on what they want.
Recipies on the other hand are complex data, and you can indeed argue that they should be locked.
If you use datasets, it can be very annoying. Dataset updates are not atomic. That means if user A wants to change row 3, and user B wants to change row 5, each of them downloads the dataset from the server, updates the row they want, and uploads the entire dataset back to the server. The one who updates it as last will win, the other change will be lost.
In that case, you may try to add locking f.e. by having a “locked-by” tag where you put the hostname of the client who currently has that recipe open. Then you can disable the interface if the “locked-by” tag doesn’t match the client’s own hostname.
But, as with many naive locking implementations, if something goes wrong, and the “locked-by” tag doesn’t get reset, nobody will be able to edit that recipe again.
I wouldn’t implement locking on datasets, but would only use datasets if it’s very unlikely that two people will edit the same recipe at the same time.
The recipe editor I once made, stored the data in a database. So every line in a recipe was a database row. If the user updated a step of the recipe, the DB update made it atomic (only that step, and even only that parameter of the step was altered). And thanks to Ignition’s native polling, it appeared a few seconds later on the other clients too (if they happened to have that screen open).
Phil had also given me some good advice on how to make sure you write to the database at the right moments. Especially if you switch recipes, and all values of your templates change, you have to make sure to not update the wrong recipe. His tip was to have a custom property named
raw that always gets the data from the DB, but never writes. Then the actual component value is linked to the
raw property. If the value changes, and the value is different from the raw value, it means the user has edited that field, and you should write it to the database.