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,531 through 1,545 (of 2,952 total)
  • Author
    Search Results
  • #42883

    In reply to: rounding decimals

    Eric de Mildt
    Participant

    Hi Sam,

    Thanks for your reply and pointing this out!
    Field script does the trick, rounds up from 0,5.
    So it works!
    I’m anything but a programmer, didn’t know about these rounding rules (Rounding is no a straightforward subject though once you start reading on the subject ;-) But interesting ).

    Cheers
    Eric

    #42881

    Topic: Inventory number

    in forum Script Talk
    Nils B
    Participant

    First of all, I know about the auto-increment function of a number field. But it’s not what I am looking for. Why? Because the field continues to count from the last position even if old records are deleted.

    This means:

    I need a script to fill in the gaps (freed up inventory slots) in the database when records are deleted and after that, created.
    I want to use the inventory number as just it, a fixed number for a record (readable) and I don’t want gaps.

    Can somebody help me with it? I think it’s understandable that you need something like this for managing collections of items (i am a collector).

    Thanks!

    #42878
    Sam Moffatt
    Participant

    Nice start to a generic entry point! I have some suggestions for improvements :)

    Instead of this long line:

    if (param == 'JLRouteScheme' || param == 'JLRouteURL' || param == 'formID' || param == 'JLRoutePattern' || param == 'docID' || param == 'scriptName')
    

    You could use an array and simplify the if statement and skip to your else directly by using Array.includes:

    var ignoredParams = ['JLRouteScheme', 'JLRouteURL', 'formID', 'JLRoutePattern', 'docID', 'scriptName'];
    if (!ignoredParams.includes(param)) {
    

    The other thing would be to use a switch statement instead of the if/else:

    			var theField = form.getFieldNamed(param);
    			if (theField == undefined) {
    				console.log(`No field called ${param}`);
    				continue;
    			}
    			switch(theField.fieldType) {
    				case 'text':
    				case 'web_site':
    					record.setFieldValue(theField.getId(), parameters[param]);
    					break;
    				case 'photo':
    					record.addPhotoFromUrlToField(parameters[param], theField.getId());
    					break;
    				case 'script':
    					console.log('Cannot set value for a "script" field type');
    					break;
    				default:
    					console.log(`Unsupported field type ${theField.fieldType}`);
    			}
    
    #42877

    In reply to: rounding decimals

    Sam Moffatt
    Participant

    I’ve not personally noticed the rounding behaviour but it sounds to me like an implementation of IEEE 754’s rounding rules for round half to even which is a strategy for mitigating rounding bias.

    You might be able to use a script field to have Javascript do the rounding for you, I believe it uses the round up strategy.

    #42874
    Eric de Mildt
    Participant

    Am I right in finding that 0.5 is occasionally rounded down instead of up? Is it that rounding decimal places in Javascript can go “quirky”? And can it be solved in TF calculation fields?
    What would be the best approach?
    Thanks for any advise.

    Eric

    #42869
    Martin Kendall
    Participant

    Hi,

    I just made a quick utility to simplify adding records to Tap Forms from other apps.

    It actually allows adding of records from any app (e.g. Shortcuts, Drafts) that can call a URL.

    To use:
    1) Install: Add the attached script as a form script to the form you want to be able to add records to.
    2) Run the script in Tap Forms and it will display the URL you need to use in Shortcuts to add a record
    3) Create a Shortcut calling that URL with the parameters matching the field names in the form (for the fields you want to set)

    I’ve only added support for adding text values, URLs and photos, but there is nothing to stop other field types, such as rating, being added.

    Hope someone finds this useful,

    Martin

    Attachments:
    You must be logged in to view attached files.
    #42842
    Brendan
    Keymaster

    Hi Chris,

    You’re right. It’s not working right for checkmark field types. I’m working on fixing that. In fact, I just fixed it (for the next update).

    In the meantime, you can write a Form Script to accomplish the same thing that loops through the records, looking for the checkmark field value and turning it off if it’s on.

    Are you familiar with scripts in Tap Forms yet? Here’s a sample bit of code that will do that for you, but you’d have to put your own Checkmark field’s ID in it:

    function Toggle_Checkmark() {
       var records = form.getRecords();
       var check_mark_id = 'fld-f14ccd51913b4348b2c32d9ac4eaf7f2';
    
       for (var index = 0, count = records.length; index < count; index++){
    	// do something;
    	var record = records[index];
    	var value = record.getFieldValue(check_mark_id);
    	if (value == true) {
    		record.setFieldValue(check_mark_id, 0);
    	}
       }
       form.saveAllChanges();
    }
    
    Toggle_Checkmark();

    Thanks,

    Brendan

    Sam Moffatt
    Participant

    If you were to aim to optimise the script, I’d probably want to have a map of PDF name to Tap Forms record ID. You can do a retrieve of a record by key/record ID via the script so if you precomputed a map of these keys or used the record ID import mode for Tap Forms to import the records then it’ll be a single retrieve for retrieving the record (form_record_id is the field in the CSV file which if present will be prepended with a rec- prefix and allow you to use form.getRecordWithId). The horse has likely already bolted for this one but something to consider for future projects, so let’s go ahead with the other suggestion: PDF attachment name in a script field.

    If you have the PDF attachment name in a script field, you could use the getRecordFromFormWithKey function in my script manager. The method signature looks like this:

    getRecordFromFormWithKey(formName, keyFieldId, keyValue, createIfMissing = true, earlyTermination = true, alwaysScanOnMiss = false)
    

    It creates in Javascript an index on a first pass and then does looks up from there (set earlyTermination to false and alwaysScanOnMiss to true). When you’re in a tight loop this should improve performance by doing the record loop once to build the index and then you can do a similar sort of roughly constant time retrieval for matching records. It’s still two loops but you remove the nesting and replace it with a more optimised data structure.

    First step is to create a new script field in your Contracts form and in it you want to add in the code we use to grab the filename from the PDF:

    record.getFieldValue('fld-e870153bd0a647c9823ca998c213d1fd')[0].filename;
    

    You’ll need to tick the “Update records when saving” option when creating that to populate the new field in all of your record. Essentially we’re just copying the filename as a new field. At this point you might also want to setup a search to look for records that have this field empty because that seems likely a bug. You’ll also need the field ID from the form panel (underneath the “Description” field) which I refer to later as “fld-scriptfieldidhere” that you’ll need to change.

    Using the code you provided as a basis, something like this should get you some of the way there:

    document.getFormNamed('Script Manager').runScriptNamed('getRecordFromFormWithKey');
    
    function Update_Records() {
    
        var csvForm = document.getFormNamed("csv");
    
        // Contracts
        var keyword_id = 'fld-a2126cbe512646e9ba144fb5a90b06dc';
        var pdf_id = 'fld-3ea77ccc18604174b722ece105965c44';
    
        // get use fixed field Id
        var csvPdf_id = 'fld-4bcd0f1fba5c4178bb8d10a112b17489';
        var csvKeyword_id = cvsForm.getFieldNamed('Keyword').getId();
    
        // Loop over all csv entries
        for (entry of csvForm.getRecords()) {
            // get pdf file name of CSV record
            var csvPdfName = entry.getFieldValue(csvPdf_id);
    
            // replace spaces with underscores
            csvPdfName = csvPdfName.replace('/ /g', '_');
            console.log("Processing: " + csvPdfName);
    
            contract = getRecordFromFormWithKey("Contracts", "fld-scriptfieldidhere", csvPdfName, false, false, true);
    
            if (!contract) {
                console.log('Unable to find matching PDF record: ' + csvPdfName);
                continue;
            }
    
            console.log("Found match: " + csvPdfName);
    
            // Update contract record
            var type_of_agreement_id = 'fld-6af499ed439143b297828643341d939b'
            contract.setFieldValue(type_of_agreement, 'Licensing Agreement')
    
            // This should “replace” keyword or keywords in a selected record
            var agreement_keywords_id = 'fld-a2126cbe512646e9ba144fb5a90b06dc';
            contract.setFieldValue(agreement_keywords_id, entry.getFieldValue(csvKeyword_id));
        }
        document.saveAllChanges();
    
        return 'done';
    }
    
    Update_Records();
    

    We’ve still got the outer loop that iterates over the incoming CSV form, the “Contracts” loop is removed and replaced with the call to getRecordsFromFormWithKey which internally does a loop for you but also builds an index in memory that should make subsequent accesses quicker. Watch your memory usage in Activity Monitor but you’ve got 64GB of RAM so we should be fine. The script is finding the record for you so the code that lived inside your inner for loop moves up a level though there is a check to see if we got a record back. I did some minor changes to set the keyword based on the CSV form as an example of how I think that to work.

    One thing I’ve done in scripts like this is put in a field for when it was processed to be able to skip it and also a counter to limit how many records are processed. This is useful for debugging scripts and being able to progressively execute it to get an idea of it:

    let minTime = new Date().getTime() - 86400000; // one day
    let processed = 0;
    let skipped = 0;
    
    for (...) {
    
        let previousDate = entry.getFieldValue('fld-previousdateidhere');
        if (previousDate && previousDate.getTime() > minTime) {
            skipped++;
            continue;
        }
    
        entry.setFieldValue('fld-previousdateidhere', new Date());
    
        processed++;
    
        if (processed > 100) {
            break;
        }
    
        // your existing for loop logic here
    }
    

    This uses an extra field and updates when the script is run to set it that way the next time you run the script, it skips past records it’s already “processed” so to speak and moves onto the next batch of 100. Instead of handling the date logic in code, you could also tie this into a saved search as well so that Tap Forms only gives you the candidate records.

    #42839
    nickc
    Participant

    Hi Brendan,
    Firstly thank you so much for such a useful piece of software. I am using the latest iPad version 5.3.18 and have come across some small issues :

    1. When creating a new field, the description is never shown
    2. Cannot seem to delete a pick list
    3. There is an option to colour items in a pick list but this does not work
    4. Table field entries are not searchable
    5. fields setup with pick lists using list value not field, still allow you to enter text directly into the field and not pick an entry from the list. Surely a pick list should only allow an entry to be picked from the list of different values. By setting a pick list field to allow multi-select this actually prevents text entry in the field !

    These are only minor issues. Otherwise I really enjoy using the software. Keep up the good work,
    Thanks
    Nick

    Brent S
    Participant

    Hi Sam and Daniel,

    In order to get rid of one of the loops I could move everything to the script. That is, instead of having multiple columns with different data in my CSV file that need to be looked up and replaced,

      I could reduce the CSV file to a single column that only has the PDF name

    . That might solve a number of problems (not only speed, but the ’empty records’)

    Then, all the script needs to do is a) find the matching record from the CSV form in the database that has the same PDF name, b) run the rest of the script to populate the fields in that record, and c) repeat for other records in the CSV file until finished.

    I know that if I did it this way the end of the script should look something like this if there were two fields to populate.

    function Update_Records() {

    var csvForm = document.getFormNamed(“csv”);
    var contractsForm = document.getFormNamed(“Contracts”);

    // specifies type of agreement
    var type_of_agreement_id = ‘fld-6af499ed439143b297828643341d939b’
    record.setFieldValue (type_of_agreement, ‘Licensing Agreement’)

    // This should “replace” keyword or keywords in a selected record
    var agreement_keywords_id = ‘fld-a2126cbe512646e9ba144fb5a90b06dc’;
    record.setFieldValue (agreement_keywords_id, ‘Vaccine, Animal, Bacterial’)

    Could you show me how you would take the original code we had above and simplify the beginning of the script and modify it so it works with the code I have here?

    Thanks very much for any insight you can provide.

    Cheers,
    Brent

    #42826
    Sam Moffatt
    Participant

    If you’re after checking if something isn’t “falsy” then you could simplify it to if (!upper_figure) { and JavaScript will convert it for you automatically. Per that falsy page though, it will treat zero as false.

    Some of the nuance is that if you haven’t set a value on a field then it is undefined because it hasn’t been set yet. Tap Forms for many field types maps directly to JavaScript data types. JavaScript will do some amount of type coercion which may result in unexpected results.

    #42824
    Sam Moffatt
    Participant

    Ok, so a much simpler test case, just executing this script added via “Add to Siri” in Shortcuts app on its own is enough to reproduce the problem:

    function Copy_Pasta() {
    	 return "Clipboard contents: " + Utils.copyTextFromClipboard();
    }
    
    Copy_Pasta();

    I checked what I was doing and I’m using Shortcuts x-callback-url to trigger the script which explains why it works for me when I do it and not when executed directly through the Shortcuts UI.

    I did a quick search and someone mentioned it as a bug for one of the iOS 13 betas but haven’t seen anything else. It could be that Apple is emptying the pasteboard within Shortcuts or at least the context that it hands to Tap Forms as a privacy measure. There might also be a privilege that the intent needs to flag to get the clipboard contents as well but I don’t recall seeing that last I looked.

    #42823
    Victor Warner
    Participant

    Daniel,

    Thank you again.

    Brendan,

    Could you put on the relevant help pages information on searching for nothing for different types of field? It is not easily found and confuse beginners in Javascript. I am used to searching in other apps for nothing with either ” or “” but these do not necessary work with TapForms for some field types.

    #42822
    Sebastian
    Participant

    Hi,

    The problem is with copyTextFromClipbard, not with the “To” version.

    Please, try calling this script from Shortcuts:

    
    function Copy_Pasta() {
    
    	// Retrieve the content of the clipboard sent by Shortcuts
    	var info = Utils.copyTextFromClipboard();
    
    	// Send back the content of the clipboard to see if it has been correctly retrieved:
    	Utils.copyTextToClipboard(info);
    
    	return info;
    }
    

    Your testing shortcut may be something like this:

    1. Copy something to the clipboard.
    2. Call the Tap Forms script “Copy_Pasta”.
    3. Retrieve the content of the clipboard (here is where I get ‘undefined’).

    Thanks for your interest in this matter.

    #42821
    Sam Moffatt
    Participant

    I recreated what I think you had. I created a form script that looks like this:

    function Copy_Pasta() {
    	Utils.copyTextToClipboard("My data - " + new Date());
    	return hello_world;
    }
    
    Copy_Pasta();

    Saved it, added it to Siri, enabled Siri, validated that it worked. I then went into Shortcuts, updated the “Run” script that Tap Forms created to disable the “show when run” option, created a new shortcut to run the Shortcut that Tap Forms created and then retrieved the clipboard. Since it copies the date, I can see if it is executing each time. I did also note that the input for my call to the “Run” shortcut listed the clipboard as the input under the “more” option but I’m not sure that matters.

    Do you mind using something simple like the above to validate that it’s working and changing over time?

Viewing 15 results - 1,531 through 1,545 (of 2,952 total)