Tap Forms app icon half
Tap Forms Forum text image
Blue gradient background

Exchange tips and ideas with the Tap Forms community

Search Results for 'script'

Viewing 15 results - 1,321 through 1,335 (of 2,989 total)
  • Author
    Search Results
  • Sam Moffatt
    Participant

    The error is probably because let (or var) flags a declaration of a variable and you’re getting an error that you’re redefining a variable in the same scope or something like that.

    The first way of solving this is the second time you do the addNewRecord, you just drop the let prefix. If that’s your error then we should be good with this. Personally I’d avoid this because you’re re-using a variable pointing to a record which means that you lose access to the pointer or reference to that record. If that isn’t important to you then this is probably the easiest solution.

    The second is that newRecord is just a name that has meaning to us as humans. You could use a different name like let apostilleRecord = form.addNewRecord() and then later let legalisationRecord = form.addNewRecord(). This keeps them distinct and makes it easy to realise if you’ve made a mistake that you’re assigning something to the wrong variable (why am I setting the apsotilleRecord to be “legalisation services”?). If I’m going on to use these records, perhaps to link to another record (e.g. record.addRecordToField), then this is likely the approach I’d take (though in that case I’d use let newRecord = record.addNewRecordToField(linkToFormFieldId) because it’ll automatically create the link for me).

    The third approach would be to put this in a loop if we don’t need the reference to the field. This has the downside of the first situation where you lose the reference to the record but it also has a little more flexibility if you don’t need that reference. The advantage of this would be that you can add to the array the records you want to create and create them as necessary. A refactor might look like this:

    var date_id = 'fld-55a1678dc7b847f6be303140ad4779a3';
    var type_of_disbursement_id = 'fld-1214396547f84c9b8fcccac7917e0147';
    var unit_price_id = 'fld-8af21853bb8949bbbac92a1919fb5597';
    var number_id = 'fld-0616ad94503b4bd1b87bd4a1b0ce9d44';
    
    let entries = [{
            [date_id]: new Date(),
            [type_of_disbursement_id]: "apostille",
            [unit_price_id]: "30",
            [number_id]: "1"
        },
        {
            [date_id]: new Date(),
            [type_of_disbursement_id]: "legalisation service",
            [unit_price_id]: "24",
            [number_id]: "1"
        }
    ];
    
    for (let entry of entries) {
        let newRecord = form.addNewRecord();
        newRecord.setFieldValues(entry);
    }
    
    document.saveAllChanges();
    

    We set the field ID’s at the top, same as your script but we next create an array of entries. We’re hard coding them here which makes the loop a little pointless but it shows how we add stuff to a loop to create items. The square brackets (e.g. []) when creating a variable tells Javascript this is an array of elements. The {} syntax when creating a variable tells Javascript that this is an object, we’re going to use that a little later to set the record values. The inner part should look slightly familiar as what you were doing before via setFieldValue. In our usage objects can be thought of key/value pairs of entries. In this case the “key” is the field ID and we’re using the square bracket syntax here (e.g. [date_id]) to tell Javascript to use the value of date_id which is fld-55a1678dc7b847f6be303140ad4779a3. This makes things a little neater by removing an intermediate variable because we’re directly putting in the mapping. This example creates two objects (the comma in the middle after the } tells Javascript that another object should be expected), one for the “apostille” and one for the “legalisation service”.

    The next bit of code is a for loop that runs the same code multiple times for each values in the array. The first time through the loop the value of the variable entry is the “apostille” object and then the second time through it’s the value of the “legalisation service” object. Inside the loop (the curly braces in this context is creating a block, confusing right?) we’re running the same code which is creating a new record (form.addNewRecord) and then I use setFieldValues with the object we created to set all of the field values in a single step.

    The last line remains the same, we only need to do it once to tell Tap Forms to persist everything.

    Hopefully that helps you out with some ideas and solutions for moving forward.

    #44406
    Sam Moffatt
    Participant

    The calculation documentation has an example of how you can omit certain items if they’re not set. Starting with that example there as a basis with some modifications (square brackets to denote field placeholders):

    IFNOTEMPTY([Anrede]; CONCAT([Anrede]; " "); "") + [VORNAME] + " " + [Name] + "\r" +
    [STRASSE_HAUSNUMMER] + "\r" +
    [PLZ] + " " + [STADT] + 
    IFEQUAL([LAND]; "Deutschland"; ""; CONCAT("\r"; [LAND]))
    

    Something like this should work, the IFNOTEMPTY is checking if the Anrede field is not empty and if so it adds it plus concats a space on the end of it otherwise it puts in an empty string so there isn’t the whitespace. The IFEQUAL at the end should test for if the country name matches and if it does match then we return an empty string otherwise we put in the new line and the country name. I use CONCAT but the + syntax should work as well.

    This is the edge of what I’d put in a calculation field because they’re hard to debug once they start to get a little more complicated. Script fields are a little better at giving you at least an error when you mess stuff up. In terms of being flexible in the address generation, I’ve got a video on using a script field to generate addresses that focused mostly on using a linked form field but the same approach would work for formatting an address.

    Victor Warner
    Participant

    I would like to add more than 1 record to a Form at a time.

    For one record I have the following form script:

    var date_id = 'fld-55a1678dc7b847f6be303140ad4779a3';
    var type_of_disbursement_id = 'fld-1214396547f84c9b8fcccac7917e0147';
    var unit_price_id = 'fld-8af21853bb8949bbbac92a1919fb5597';
    var number_id = 'fld-0616ad94503b4bd1b87bd4a1b0ce9d44';
    
    var date = new Date();
    var typedoc = "apostille";
    var unitprice = "30";
    var number = "1";
    
    let newRecord = form.addNewRecord();
    
    newRecord.setFieldValue(date_id,date);
    newRecord.setFieldValue(type_of_disbursement_id,typedoc);
    newRecord.setFieldValue(unit_price_id,unitprice);
    newRecord.setFieldValue(number_id,number);
    
    document.saveAllChanges(); 

    But then if I also then wished another record using the same Form script to add:

    var date = new Date();
    var typedoc = "legalisation service";
    var unitprice = "24";
    var number = "1";
    
    newRecord.setFieldValue(date_id,date);
    newRecord.setFieldValue(type_of_disbursement_id,typedoc);
    newRecord.setFieldValue(unit_price_id,unitprice);
    newRecord.setFieldValue(number_id,number);
    
    document.saveAllChanges();

    What command do I need to use to create another record (as using

    let newRecord = form.addNewRecord();

    again results in an error)?

    #44399
    Brendan
    Keymaster

    The Prompter doesn’t have direct support for date input, so you would need to parse it yourself.

    Here’s a link to various solutions for that:

    https://stackoverflow.com/questions/5619202/converting-a-string-to-a-date-in-javascript

    #44395
    Sam Moffatt
    Participant

    Creating a new record is done by form.addNewRecord(). It’ll return to you a new record object that you can use.

    The other item is that prompter runs async which means that after the show() line, the script keeps running. Conceptually, think of that as the last line of the script and when it’s finished, it will call the function you gave it, output in this case.

    Some personal preference, I try to keep the variables that are being predefined at the top. It sometimes makes a difference but I can never remember which language it’s important in.

    This should get you a little closer:

    var date_id = 'fld-55a1678dc7b847f6be303140ad4779a3';
    var type_of_disbursement_id = 'fld-1214396547f84c9b8fcccac7917e0147';
    var unit_price_id = 'fld-8af21853bb8949bbbac92a1919fb5597';
    var number_id = 'fld-0616ad94503b4bd1b87bd4a1b0ce9d44';
    var date_requested;
    var type_of_disbursement;
    var unit_price;
    // var number;
    // var other_field;
    var number;
    var numbers = ['1', '2', '3', '4', '5'];
    
    var output = function printOut(continued) {
           if (continued == true) {
    	   console.log(date_requested + ", " + type_of_disbursement + ", " + unit_price + ", " + number);
    	   let newRecord = form.addNewRecord();
    	   newRecord.setFieldValue(type_of_disbursement_id,type_of_disbursement);
    	   newRecord.setFieldValue(unit_price_id,unit_price);
    	   newRecord.setFieldValue(number_id,number);
    	   document.saveAllChanges();
           } else {
              console.log("Cancel button pressed.");
           }
    }
    
    let prompter = Prompter.new();
    prompter.cancelButtonTitle = 'Cancel';
    prompter.continueButtonTitle = 'OK';
    prompter.addParameter('Date: ','date_requested')
    .addParameter('Type of Disbursement: ', 'type_of_disbursement')
    .addParameter('Unit Price: ', 'unit_price')
    .addParameter('Number: ', 'number', 'popup', numbers)
    .show('Enter the type of disbursement, unit price and number wanted', output);
    #44390
    Victor Warner
    Participant

    I am trying to learn how to the use Prompter command/function. I have created a simple form script using the Prompter class, and added what I believe are the correct commands to save the output. But on running the script it is not saving the output to the fields of a blank record.

    The form script:

    var date_id = 'fld-55a1678dc7b847f6be303140ad4779a3';
    var type_of_disbursement_id = 'fld-1214396547f84c9b8fcccac7917e0147';
    var unit_price_id = 'fld-8af21853bb8949bbbac92a1919fb5597';
    var number_id = 'fld-0616ad94503b4bd1b87bd4a1b0ce9d44';
    
    var output = function printOut(continued) {
           if (continued == true) {
    	   console.log(date_requested + ", " + type_of_disbursement + ", " + unit_price + ", " + number);
           } else {
              console.log("Cancel button pressed.");
           }
    }
    var date_requested;
    var type_of_disbursement;
    var unit_price;
    // var number;
    // var other_field;
    var number;
    var numbers = ['1', '2', '3', '4', '5'];
    
    let prompter = Prompter.new();
    prompter.cancelButtonTitle = 'Cancel';
    prompter.continueButtonTitle = 'OK';
    prompter.addParameter('Date: ','date_requested')
    .addParameter('Type of Disbursement: ', 'type_of_disbursement')
    .addParameter('Unit Price: ', 'unit_price')
    .addParameter('Number: ', 'number', 'popup', numbers)
    .show('Enter the type of disbursement, unit price and number wanted', output);
    
    record.setFieldValue(type_of_disbursement_id,type_of_disbursement);
    record.setFieldValue(unit_price_id,unit_price);
    record.setFieldValue(number_id,number);
    
    document.saveAllChanges();

    The Form is attached, with the form script (‘Prompt’)

    Also what commands would I need to add to create a new record before populating the fields with the output of the running the prompter?

    Any help would be gratefully received.

    Attachments:
    You must be logged in to view attached files.
    #44385
    Sam Moffatt
    Participant

    Ok, so you’re starting with a form and you’re looking to denormalise some data out into a new structure. I’d probably personally use a form script to do the heavy lifting during a data migration but I think what will work best for you is using the export functionality to export the set of records you want to put in the other forms and then reimport it.

    One thing is I suspect you’ll want to link these records once you split them apart. If you don’t have some sort of unique key for the records (student ID, client ID, etc), then I’d add one. A really quick way of doing it is to use a calculation field with the function UUID() in it and make sure the type is “Text”. That’ll give you a unique ID so that we can join it later. This might be unnecessary but I change the type to text once it’s generated since I don’t intend to keep using this field.

    Next step is to export the records and fields, including our unique field. If you want to export a subset, you’ll need to do a saved search to filter out the ones you’re interested in (should be a funnel icon on the top right next to the search box). If you do File > Export > Records then you’ll get a dialog where you can select the fields you want to bring to your new form. Don’t tick “Export record ID” and “Export linked records” but you will want to tick “Field type tags” and “Export media”. Hit Export and select a folder to send the export the files. You’ll get a CSV file created with a folder full of images to use.

    Next step is to import them into your new form. File > Import > Records will let you import to an existing form or even create a new form for you. Choose the CSV file that we just created and then choose the photo folder it would have exported (if you exported a photo field). I always tick the “add missing fields to form” option even though TF should match the field names automatically, it’s useful to have the extra field to understand what went wrong.

    That should populate your other form with a bunch of records (yay) though they’re obviously not inherently connected to your old records (boo!). Make sure everything is where you expect it to be though nothing should change (famous last words). This is where the “Link to Form” field type in “JOIN” mode helps us out. Add it to your main form, where it has “Link to Form”, select your target form, click on “JOIN” and then pick the unique ID field (either one you had already or the one just created) and Tap Forms will link those records together for you.

    I’d also created a second link to form field with the link type that makes sense for you (either one to many or many to many) so that moving forward you use this field to link the data together. The JOIN field requires both records share a common value and in the long run when you’re not importing data that’s a bit of work. Creating a TF managed link to form field will handle creating the linking metadata between the records for you with some extra UI functionality for picking records, creating them and a bunch more. You can use a script to automate migrating the JOIN’d records, do it manually, or just leave the JOIN field in place and update as you go.

    That should enable you to export your data and import it to new forms relatively easily, perhaps not quite as easy as drag and drop but I don’t think it’s an insurmountable problem.

    I have a video on leveraging link to form fields that might help you out as well as it covers a couple of different use cases. My channel has a few different videos that might give you some ideas on how you can model your data and make good use of Tap Forms.

    #44383
    Sam Moffatt
    Participant

    There are some scripting solutions to copy a record to another form but in general the suggestion is to use saved searches to filter and limit records that are retrieved.

    Perhaps you can share a little more about your workflow, what you’re trying to achieve and how moving records between forms solves this for you?

    #44377
    Sam Moffatt
    Participant

    That’s an interesting approach, I didn’t think of a full export cycle, I was trying to get at it via scripting. That gets me thinking about leveraging something outside the ecosystem.

    I’d probably lean on CouchDB and use that to watch it’s change log and then each time a record with an image is added, process it in something I’m comfortable in (generally PHP) and then just have that rewrite the entry in CouchDB. If I needed it to be responsive, I’d probably set a smaller timeout and try to wait for a quiet period on the record (older than five minutes?) before triggering the update so as to not be too disruptive and create conflicts. It could be an overnight thing so that it minimises the risk of conflicts as well but that experience wise isn’t great. Now I’m riffing maybe even have a script trigger to extract the record, process the data and hand it back to Tap Forms then have TF handle updating the record so at least the users TF document is consistent and the writes are generally going in one direction.

    Fun problem to solve :)

    #44373
    Sam Moffatt
    Participant

    I don’t think there is a ready filter for the next X days, you can emulate it by doing two clauses in the search. That’s a little janky but for one off it’ll work.

    The other trick is to use a calculation or script field to calculate a value and then search based on that value but you need to refresh all of your records because calc/script fields are only evaluated when they’re modified.

    In your calculation editor, something like this:

    days(<double click on your date field to insert it here>, TODAY())
    

    Should do the trick. Again, caveat is you need to refresh all of your records to use the search (that’s the refresh button beneath the record list not to be confused with the refresh button beneath the record).

    #44358
    Brendan
    Keymaster

    It would be good to have some cover methods to let you write directly to the file system from JavaScript.

    #44356
    DrJJWMac
    Participant

    Thank you again.

    I am beginning to think that an easier alternative will be to export as CSV and then run a converter (AppleScript or other) to massage the CSV to raw.

    FWIW, my objective is to use TapForms as a front end GUI to a database of LaTeX-encoded problems. An example record output would appear as below.

    \begin{defproblem}{enthalpy-phasetransitionenthalpy-default}
    From the attached plot, what is the molar enthalpy $\Delta_{vap}\bar{H}$ to heat the room?

    \smallskip

    \putfig[0.1\textwidth]{fig-enthalpyplot}
    \end{defproblem}

    I can set fields for the topic (enthalpy), problem (phase transition enthalpy), set (button choices from A … example, default), LaTeX problem (From the attached plot …), has figure (yes/no), figure name (enthalpyplot), and relative figure size (0.1). A JavaScript field builds the final output from the data form. I intend to use this to administer sets of problems in a topic to track across exams, homework, and examples. I can build the exam or homework questions and then add examples (eventually with answers) to assure that students have seen what I will test against. The raw outputs for any cases are compiled into a final document using a LaTeX package called probsoln.

    In closing, I will use this thread once more to request a RAW/ASCII export option either directly or through JavaScript.


    JJW

    #44350
    Sam Moffatt
    Participant

    There isn’t a way to write a file directly, if I was to put it straight to a file I would send it to a web service and use that to dump it to disk for me. You can use Utils.postContentToUrlWithContentType() or Utils.postJsonToUrl() to call out to a web service. Probably for your use case postContentToUrlWithContentType with a simple text content would suffice. They’re pretty simple API’s with details on the Javascript page.

    Something like this should work:

    let entries = [];
    for (let record of form.getRecords()) {
      entries.append(record.getFieldValue('fld-yourfieldid'));
    }
    Utils.postContentToUrlWithContentType(entries.join("\n"), "http://localhost/tapforms-bridge.php", "text/plain");
    

    Then tapforms-bridge.php could look like this:

    <?php
    file_put_contents("/tmp/file.txt", file_get_contents("php://input"));
    

    As a simple example of getting data out, it’s not the greatest solution but it should do the trick. You’d need to get the built in Apache and PHP set up on your Mac but there are plenty of guides out there for that.

    #44340
    Sam Moffatt
    Participant

    Would you be able to share a screen shot of what you’re seeing because I think I’m a little lost.

    One thing to note is that the view settings for link to form fields can be different to the normal view settings for that form though I’m not 100% sure that’s what you’re seeing so if you haven’t already, hit view settings on the link to form list and make sure that field list has what you expect in it. It should be hidden on the record detail view when you get there, regardless of how you get to that view but the multicolumn list view screens can have different fields than the default form would have. The only other thing I can think of is that the hidden field is at the top of your list and is some how being rendered by the single column list view settings but I couldn’t replicate that on my own iPad for testing.

    Some folk have used text fields and scripts to build some pretty interesting report style interfaces, the Markdown stuff allows for some of that but it’s a limited form of Markdown to work with the printing system. It’s not the greatest system but it does provide a mechanism for building some sort of a structured report at least.

    #44338
    Sam Moffatt
    Participant

    The CSV export will likely wrap things in quotes for compatibility reasons, I don’t believe there is a way I’ve seen to turn it off.

    You could easily create a form script that generates the output via console.log that you could easily grab out of the display, something like:

    for (let record of form.getRecords()) {
      console.log(record.getFieldValue('fld-yourfieldid'));
    }
    

    Would do the trick to dump out all of the records to the console for you. Replace the fld-yourfieldid with the field ID you care about, you can get the field ID by double clicking on the field you want in the script editor or from underneath the field description in the field editor.

Viewing 15 results - 1,321 through 1,335 (of 2,989 total)