https://wiki.mementodatabase.com/index.php?title=How:Trigger_Examples&feed=atom&action=historyHow:Trigger Examples - Revision history2024-03-29T04:47:42ZRevision history for this page on the wikiMediaWiki 1.39.2https://wiki.mementodatabase.com/index.php?title=How:Trigger_Examples&diff=4076&oldid=prevUnConnoisseur: Created page with "{{Stamp|2022-01-12|4.10.3|1.10.1}} {{BannerMenu}} == Libraries Examples == ----- === Data Validation === Using scripts, you can check the correctness of input data and deny s..."2022-01-12T17:11:39Z<p>Created page with "{{Stamp|2022-01-12|4.10.3|1.10.1}} {{BannerMenu}} == Libraries Examples == ----- === Data Validation === Using scripts, you can check the correctness of input data and deny s..."</p>
<p><b>New page</b></p><div>{{Stamp|2022-01-12|4.10.3|1.10.1}}<br />
{{BannerMenu}}<br />
<br />
== Libraries Examples ==<br />
-----<br />
=== Data Validation ===<br />
Using scripts, you can check the correctness of input data and deny saving of data that fail the test. For example, perhaps a field integer values are allowed only from 0 to 200.<br />
<br />
:; Add a Create trigger: Set Event to '''Creating a new entry''', Phase to '''Before saving the entry'''. It will run synchronously.<br />
:; Add an Update trigger: Set Event to '''Updating an entry''', Phase to '''Before saving the entry'''. It will run synchronously.<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
var num = entry().field("Number"); // Get value of field Number<br />
if (num < 0 || num > 200) { // Test for value matching allowable range<br />
message("Wrong range"); // If value is outside range, display message<br />
cancel(); // Cancel the operation<br />
}<br />
</source><br />
<br />
:; Set default values: If default values cannot be set using the user interface, they can be set using a script.<br />
<br/><br />
-----<br />
=== Previous value of another field ===<br />
Suppose there is a library containing daily mileage of daily walks or use of a car or bicycle. Suppose the library has a StartingMileage field and a Mileage field. When an entry is created, the field StartMileage must get data from the field Mileage in the previous entry.<br />
<br />
:; Add a new trigger: Set Event to '''Creating an entry''' and Phase to '''Open the Entry Edit card'''. It will run synchronously.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
var entries = lib().entries(); // Get current library & array of its entries<br />
if (entries.length > 0) { // Check that array is not empty;<br />
// otherwise exit,<br />
// since there is no previous entry.<br />
prevMileage = entries[0].field("Mileage"); // The array is sorted newest to oldest,<br />
// so newest entry in the array<br />
// on top with index of 0.<br />
entryDefault().set("StartMileage", prevMileage); // Set value of field Mileage<br />
// from the previous entry<br />
// as default value for field StartMileage.<br />
} <br />
</source><br />
<br/><br />
-----<br />
<br />
=== Beginning of the next day ===<br />
Suppose you need to identify the beginning of a new day in the DateTime field. (The script requires connection of the JavaScript library '''moment.js''' [http://momentjs.com/ moment.js].)<br />
<br />
:; Add new trigger: Set Event to '''Creating an entry''' and Phase to '''Opening an Entry Edit card'''. It will run synchronously.<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
var m = moment().add(1,'d'); // Using the moment.js library function moment(),<br />
// get the current time, and add 1 day<br />
m.hour(8).minute(0); // Set the time to hour 8 and minute 0<br />
entryDefault().set("Date",<br />
m.toDate().getTime()); // Use that as the default value for the field Date<br />
</source><br />
<br/><br />
-----<br />
<br />
=== New entry in one library triggers new entry in another ===<br />
Suppose that after a new application for membership is validated, a new member should be created. We have libraries Applications & Members. After a new Applications entry is entered and before it is saved, we want to validate the application, and if it passes, we want to create a new entry in Members.<br />
<br />
:; Fields: Library Applications has fields '''Date''', '''Name''', City, Years in city, Type.<br/> Library Members has fields '''Name''' & Type.<br />
:; Set library permission: The Applications library must be permitted to access other libraries via ''libByName()''.<br/>Within Triggers, press the shield icon to view Permission settings.<br />
:; Add new trigger: Add a new trigger to the Applications library.<br/>Set Event '''Creating a new entry''', Phase '''Before saving the entry'''.<br/>(A similar trigger could be set for Event '''Updating an entry''' Phase '''Before saving the entry''', but only if a change in a field value is to trigger the add of the new member.)<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
// Get the application entry that's being saved and call it e<br />
// (because you may use it a lot)<br />
// With that, you can readily reference fields<br />
// in the new application entry about to be saved<br />
<br />
var e = entry();<br />
<br />
// If you have any checks on the values of fields the user entered,<br />
// you could do them here<br />
// If any validations fail, call cancel() to forestall the save<br />
// The user remains in the Entry Edit card<br />
// and will be advised the application does not pass criteria<br />
<br />
if (e.field("Years in city") <= 2) { // Sample field validation<br />
message("Application inadequate"); // You'll want more<br />
cancel(); // This will abort the save, but continue the script<br />
}<br />
<br />
else { // Add a new member only if application is adequate<br />
<br />
// From here on, the new application will be saved,<br />
// so we must also create the new member entry<br />
<br />
// To create the new member, we need to reference Members<br />
<br />
var members = libByName("Members"); // This requires permission (see above)<br />
<br />
// Start a new entry for Members<br />
<br />
var newMember = new Object();<br />
<br />
// Set member fields from application data and add the new Members entry<br />
<br />
newMember["Name"] = e.field("Name");<br />
newMember["Type"] = e.field("Type");<br />
members.create(newMember);<br />
}<br />
</source><br />
<br/><br />
-----<br />
<br/><br />
<br />
=== Ensuring unique non-Name field value ===<br />
The goal is to ensure that a particular field value is unique within the library.<br />
<br />
The ideal way to do this is to make the field the one and only Entry Name field and then set the Entry Name to be unique. Then, Memento will take care of ensuring this for you.<br />
<br />
To do this, go in the Library Edit screen to the MAIN tab of the library and turn on the switch "The Entry Name is unique". Then go to the FIELDS tab and ensure that your field and only that field has the role Entry Name. Do that by editing the field, and under Display Options, you'll see "Display in the list as"; the choices will include Entry Name.<br />
<br />
Now, if your library needs some other Entry Name, and you nevertheless want to ensure that a different field is unique within the library, then, yes, you'll need some code.<br />
<br />
The best way, if you're just starting to enter entries into your library, is to make sure they're unique from the outset, so from the Entries List screen, pick Triggers from the menu. Press the + (plus) button to add a trigger, set the Event to "Creating a new entry" and the Phase to "Before saving the entry".<br />
<br />
:; Fields: The field in the current library &mdash; that is to be unique among the entries of the library &mdash; is ''myField''.<br />
:; Add new trigger: Add a new trigger to the library.<br/>Set Event '''Creating a new entry''', Phase '''Before saving the entry'''.<br/>(A similar trigger could be set for Event '''Updating an entry''' Phase '''Before saving the entry''' &mdash; for instance, if the library already has entries in which ''myField'' may not be unique.)<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
var myField = entry().field("myField"); // Value of myField<br />
var entries = lib().entries(); // Array containing all entries<br />
<br />
var unique = true; // Presuming, initially<br />
for (var ent = 0; ent < entries.length; ent++) { // Loop through all entries<br />
if (entries[ent].field("myField") === myField) // If there is ever a match,<br />
unique = false; // Remember it<br />
}<br />
<br />
if (!unique) { // If not unique,<br />
cancel(); // Disallow the save<br />
message("myField is not unique. Try again."); // Tell the user<br />
}<br />
</source><br />
<br/><br />
-----<br />
<br/><br />
<br />
=== TEMPORARY SECTION. PLEASE DISREGARD ===<br />
Suppose you use a Checkboxes field or a Multiple-choice field in a My Today's Activities library to represent a plan of club activities to do today &mdash; a set of activities one can select or not. Which of the items one will do on a given day will be based on standard plans one can select from an Activity Plans library via a Link to Entry field to that library.<br />
<br />
:; Libraries: My Today's Activities &mdash; Contains a member's plan for the day.<br/>Activity Plans &mdash; Essentially a menu of available plans for activities.<br />
:; Fields: My Today's Activities &mdash; Date and Member, a few other fields, and a Checkboxes field called '''Today's Plan'''.<br/>Activity Plans &mdash; A plan name, description, and a Checkboxes field '''Plan''' (identical items to Today's Plan) with the checked activities associated with the plan.<br />
:; Add new trigger: Add two new triggers to the library.<br/>Set Event '''Creating a new entry''', Phase '''Before saving the entry'''.<br/><br />
<br />
<source lang="JavaScript"><br />
var e = entry();<br />
var links = e.field("Std Plans").length;<br />
if (links > 0) { // If the member has selected a standard plan<br />
var linkedEntry = e.field("Std Plans")[0]; // The first & only entry<br />
var todaysPlan = e.field("Today's Plan");<br />
var stdPlan = linkedEntry.field("Plan");<br />
var forSet = "";<br />
for (var act in stdPlan) {<br />
if (forSet != "")<br />
forSet += ", "; // Comma except 1st time thru<br />
forSet += stdPlan[act]; // Only items that are checked<br />
}<br />
e.set("Plan", forSet); // Set Today's Plan to the values in the selected standard Plan<br />
}<br />
</source><br />
:; After the Creating/Before trigger is running correctly<br />
:: Add another trigger, this time for event '''Updating an existing entry''' and phase '''Before saving the entry'''. Then copy the previous script to the clipboard and paste it into this new trigger, so that they are identical, except for the trigger name and the event name.<br />
<br/><br />
-----<br />
<br/><br />
<br />
=== Copying the value of a Checkboxes or Multiple-choice field to another library ===<br />
Suppose you have and library with the same structure as the 1st library, and you'd like to send a clone of an entry to the web library in the trigger for saving the wet library's entry. Thisuse a Checkboxes field or a Multiple-choice field in a My Today's Activities library to represent a plan of club activities to do today &mdash; a set of activities one can select or not. Which of the items one will do on a given day will be based on standard plans one can select from an Activity Plans library via a Link to Entry field to that library.<br />
<br />
:; Libraries: My Today's Activities &mdash; Contains a member's plan for the day.<br/>Activity Plans &mdash; Essentially a menu of available plans for activities.<br />
:; Fields: My Today's Activities &mdash; Date and Member, a few other fields, and a Checkboxes field called '''Today's Plan'''.<br/>Activity Plans &mdash; A plan name, description, and a Checkboxes field '''Plan''' (identical items to Today's Plan) with the checked activities associated with the plan.<br />
:; Add new trigger: Add two new triggers to the library.<br/>Set Event '''Creating a new entry''', Phase '''Before saving the entry'''.<br/><br />
<br />
<source lang="JavaScript"><br />
var e = entry();<br />
var links = e.field("Std Plans").length;<br />
if (links > 0) { // If the member has selected a standard plan<br />
var linkedEntry = e.field("Std Plans")[0]; // The first & only entry<br />
var todaysPlan = e.field("Today's Plan");<br />
var stdPlan = linkedEntry.field("Plan");<br />
var forSet = "";<br />
for (var act in stdPlan) {<br />
if (forSet != "")<br />
forSet += ", "; // Comma except 1st time thru<br />
forSet += stdPlan[act]; // Only items that are checked<br />
}<br />
e.set("Plan", forSet); // Set Today's Plan to the values in the selected standard Plan<br />
}<br />
</source><br />
:; After the Creating/Before trigger is running correctly<br />
:: Add another trigger, this time for event '''Updating an existing entry''' and phase '''Before saving the entry'''. Then copy the previous script to the clipboard and paste it into this new trigger, so that they are identical, except for the trigger name and the event name.<br />
<br/><br />
-----<br />
<br/><br />
<br />
=== Copying an entry's field values to another library ===<br />
Suppose you use a library to hold purchase orders, and you want a subset of these to be sent to a history library for later transmission to a server database.<br />
:; Libraries: The current library is used as the source library. The target library is to be called PO History. This is set as a default at the top of the script below to copy the current entry to the history library, so the default may be changed readily.<br />
<hr><br />
:; Fields: My Today's Activities &mdash; Date and Member, a few other fields, and a Checkboxes field called '''Today's Plan'''.<br/>Activity Plans &mdash; A plan name, description, and a Checkboxes field '''Plan''' (identical items to Today's Plan) with the checked activities associated with the plan.<br />
:; Add new trigger: Add two new triggers to the library.<br/>Set Event '''Creating a new entry''', Phase '''Before saving the entry'''.<br/><br />
<hr><br />
<br />
<source lang="JavaScript"><br />
<br />
//Field names to copy to another lib<br />
const fields=["Field1","Filed2"];<br />
<br />
// Get current entry<br />
let ent = entry();<br />
<br />
//Create empty object<br />
let newLogEntry = new Object();<br />
<br />
//Get another library name and create new entry<br />
let logs = libByName("anotherLib");<br />
let newEntry = logs.create(newLogEntry);<br />
<br />
<br />
//Fill new log entry with values from state<br />
for (let i of fields) {<br />
newEntry.set(i,ent.field(i));<br />
}<br />
</source><br />
<br />
== Files Examples ==<br />
-----<br />
=== Writing & reading from a file ===<br />
<br />
:; Add trigger(s): This script could be a part of any phase of any event.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
f = file("/sdcard/myfile.txt"); // Open myfile.txt on the SD card<br />
// If no file, it will be created<br />
f.writeLine("one"); // Write "one" as a line to the file<br />
f.writeLine("two");<br />
f.writeLine("three");<br />
f.close(); // Close & save. Until closed,<br />
// the file is still empty<br />
var a = f.readLines(); // Read all lines into array a<br />
</source><br />
<br/><br />
-----<br />
=== Save an entry to a file in XML format ===<br />
The entry includes fields: id , title , date.<br />
<br />
:; Add trigger(s): This script could be a part of any phase of any event.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
var xml = '<record id="' + entry().field("id") + '">' + // Format XML record<br />
'<title>' + entry().field("title") + '</title>' + // from entry field values<br />
'<date>' + entry().field("date") + '</date>' +<br />
'</record>';<br />
f = file("/sdcard/" + entry().field("title") + ".xml"); // File name is Entry Name<br />
f.write(xml); // Save XML data to the file<br />
f.close(); // Close the file<br />
</source><br />
<br/><br />
-----<br />
<br/><br />
<br />
== Http Examples ==<br />
-----<br />
=== Currency Conversion ===<br />
Suppose the library contains two fields: PriceUSD and PriceEUR.<br />
The user will enter the value in PriceUSD and the value in Euros will appear in PriceEUR according to the current exchange rate.<br />
<br />
:; Add new trigger: Set Event '''Create a new entry''' and Phase '''After saving the entry'''. It will run asynchronously.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
result = http().get("http://api.fixer.io/latest?base=USD"); // Use http://fixer.io/ for<br />
// conversion rate in JSON<br />
usdToEur = JSON.parse(result.body)["rates"]["Eur"]; // Use JavaScript object JSON<br />
// to parse the result<br />
entry().set("PriceEUR",<br />
entry().field( "PriceUSD") * usdToEur ); // PriceUSD * conversion rate<br />
// for value for PriceEUR<br />
</source><br />
<br/><br />
-----<br />
<br />
=== Creating a Task in the Todoist App ===<br />
[https://todoist.com Todoist] — A Web service and mobile app for task management. Todoist allows task creation via API [https://developer.todoist.com/].<br />
In the following example of task creation, text will be taken from the Memento library entry.<br />
<br />
:; Add a new trigger: Set Event to '''Creating a new entry''' or perhaps '''Update an entry'''. Set Phase as appropriate.<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
// Create a JSON command for Todoist task creation<br />
// using the format described in [https://develop.todoist.com/#add-an-item].<br />
// This command should include a unique identifier<br />
// created using the guid() global function.<br />
var commands =<br />
'[{"uuid":"' + guid() + '","temp_id":"' + guid() +<br />
'","type":"item_add","args":{"content":"' + entry().field("Task") + '"}}]';<br />
<br />
// Execute the HTTP request. An attribute called '''token''' is used<br />
// for authorization in Todoist.<br />
// It is available in the Todoist Account setting.<br />
// Since the text of the task can include symbols<br />
// not allowed in a URL request,<br />
// use the standard function encodeURIComponent() to filter them out.<br />
result = http().get("https://todoist.com/API/v7/sync?token=15281e8e4d499dаff817af0b14112eac3176f9dc&commands=" +<br />
encodeURIComponent(commands));<br />
<br />
// Show the user a message indicating successful creation of the task.<br />
if (result.code == 200)<br />
message('Task has been successfully created");<br />
</source><br />
<br/><br />
-----<br />
<br/><br />
<br />
== System Examples ==<br />
-----<br />
=== Script to open a screen for dialing a number ===<br />
Suppose a library contains a field called Phone containing a phone number.<br />
<br />
:; Add a new trigger: Set Event to '''Opening an Entry View card''', Phase to '''After display of the entry'''.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
i = intent("android.intent.action.DIAL"); // Create information exchange object Intent<br />
// with the action of DIAL<br />
i.data("tel:"+entry().field("Phone")); // The data will be the phone number obtained<br />
// from the field Phone<br />
i.send(); // Send the message<br />
</source><br />
<br/><br />
-----<br />
=== Script to open app to send SMS message ===<br />
The phone number will be obtained from the field Phone and the text of the message will be obtained from the fields ContactName and Notes.<br />
<br />
:; Add a new trigger: Set Event to '''Opening an Entry View card''', Phase '''After display of the entry'''. It will run synchronously.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
msg = "Dear, " +<br />
entry().field("ContactName") +<br />
"\n" + entry().field("Notes"); // Form the message from ContactName & Notes<br />
i = intent("android.intent.action.SENDTO"); // Create intent object to open the app for sending<br />
i.data("smsto:"+entry().field("Phone")); // Provide the phone number in format smsto:number<br />
i.extra("sms_body" , msg); // Insert the text of the message to sms_body<br />
i.send(); // Send the message<br />
</source><br />
<br/><br />
-----<br />
=== Script to insert an appointment into Google Calendar ===<br />
Suppose a library contains the time and name of an appointment.<br />
<br />
:; Add a new trigger: Set Event to '''Creating a new entry''', Phase to '''Before saving the entry'''. It will run synchronously.<br />
<br />
:'''Trigger script:'''<br />
<source lang="javascript"><br />
i = intent("android.intent.action.INSERT"); // Create Intent object<br />
i.data("content://com.android.calendar/events"); // Data contains Google Calendar URI<br />
i.extra("title", entry().field("Title")); // Get event name from field Title<br />
i.extra("description",<br />
entry().field("Description")); // Get description from field Description<br />
i.extraLong("beginTime",<br />
entry().field("Begin").getTime()); // Get start time from field Begin<br />
// Begin is of type DateTime<br />
// Additional parameter is of type Long,<br />
// so extraLong() is used for conversion.<br />
i.extraLong("endTime",<br />
entry().field("End").getTime()); // Get end time from the field End<br />
// Requires same conversion as above<br />
i.send(); // Send the message<br />
</source><br />
<br/><br />
-----<br />
<br/><br />
<br />
== Built-in Objects Examples ==<br />
-----<br />
=== Example: Extracting components from a Contact field into separate fields ===<br />
Suppose you have a Contact field called myContact. If you would like the name, primary phone, and primary email as separate fields, create the fields, maybe ContactFullname, ContactPrimaryPhone, and ContactPrimaryEmail. The create two triggers, as follows:<br />
<br />
:; CreateBefore<br />
:: Event: Creating a new entry<br />
:: Phase: Before saving the entry<br />
:: Script: As follows<br />
<source lang="JavaScript"><br />
var e = entry();<br />
var contact = e.field("myContact");<br />
<br />
e.set("ContactFullname", contact.fullName);<br />
e.set("ContactPrimaryPhone", contact.phone);<br />
e.set("ContactPrimaryEmail", contact.email);<br />
</source><br />
<br/><br />
:; UpdateBefore<br />
:: Event: Updating an existing entry<br />
:: The rest the same as above.<br />
<br />
Now, every time you create a new entry or update an existing one, the contact information will be extracted to separate fields.<br />
<br />
=== Example: Extracting coordinates from a Location field into Real fields ===<br />
Suppose you have a Location field called myLocation. If you would like the coordinates as Real fields, create the Real fields, maybe LocationLatitude and LocationLongitude. The create two triggers, as follows:<br />
<br />
:; CreateBefore<br />
:: Event: Creating a new entry<br />
:: Phase: Before saving the entry<br />
:: Script: As follows<br />
<source lang="JavaScript"><br />
var e = entry();<br />
var loc = e.field("myLocation");<br />
<br />
e.set("LocationLatitude", loc.lat);<br />
e.set("LocationLongitude", loc.lng);<br />
</source><br />
:; UpdateBefore<br />
:: Event: Updating an existing entry<br />
:: The rest the same as above.<br />
<br />
Now, every time you create a new entry or update an existing one, the coordinates for myLocation will be extracted to the Real fields.<br />
<br />
<br/><br />
-----<br />
<br/><br />
<br />
== See Also ==<br />
; [[Triggers]]: Fundamental information about Memento triggers<br />
; [[Memento JavaScript Library]]: Memento JavaScript functions & objects<br />
; [[Tips:Using JavaScript in Memento]]: Tips for using JavaScript in Memento<br />
<br />
[[Category:How]] [[Category:Scripting]]</div>UnConnoisseur