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 - 2,161 through 2,175 (of 2,987 total)
  • Author
    Search Results
  • #38446
    Brendan
    Keymaster

    Hi Paul,

    You really don’t need a script to do this sort of thing if you’re using the Mac version.

    There’s an Advanced Find & Replace function under the Records menu which would let you set a value in all of the records for a specified field.

    You can also use the Fill Down function from the Multi-Column List View by typing your value in the field in the first row, then selecting that cell and all the cells beneath it and then using the Fill Down function under the Edit menu.

    Do you have the Mac version?

    Thanks,

    Brendan

    #38445
    Paul Hirst
    Participant

    I wanted to add a new field to a form and have it set to a default value. I can do this with new records but I have over 2000 existing records and wanted to add this default value to the new field in each existing record as well. I assume the best way to achieve this is with a script but I am not great with scripting. I assume it is a very short script so was wondering if someone would be able to provide the script to be able to do this. I can see the setFieldValues function but don’t know how I write the scripting to be able to cycle through each record and populate the relevant field.

    #38407
    Sam Moffatt
    Participant

    It sounds like you have two main data structures:

    1. A master list of all of your people/contacts, presumably with their email address.
    2. A set of email types or ‘campaigns’ that you want to send to a subset of your contacts.

    There are a few ways I’d model this: a really simple way with a single form, a way with two forms and a slightly more complicated way with three forms.

    The base are your people or ‘Contacts’ and you say you’ll have multiple email types/campaigns. You’re wanting to see all of the types/campaigns that the contact is available for as a property of the contact so you could model this as a single form with a lot of checkboxes at the end. Not the worlds most elegant solution but if there isn’t any more data than if they should get this email or not, then keep it simple.

    Now if there are more details about the email type or campaign, then this would bring us to the two form solution. The second becomes your ‘Campaigns’ form and stores the campaign details. I’d model it so that you use a Link to Form field type set to Many to Many with the Show Inverse and then for each contact you add them to the campaign. Then the campaign can give you a list of all of the people who are supposed to be targeted to it. The campaign could also contain the body of the email you wish to send as well.

    The challenge with this is exporting the list out to a CSV/Excel file means that the linked structure is flattened. You could work around this by putting fields in the contact form for each of the email types/campaigns but at that point you might as well just have a single form. For export purposes you could use a script field to automatically export a list of which campaigns the person is a member of but that’d require you to use Excel to expand the contents of the exported data as a post processing step.

    This brings me to the third option which is using three forms. We keep our “Contacts” form for the contact details and we keep the “Campaigns” form for the campaign detail and then we create a third form for targets of the campaign, let’s call it “Campaign Targets”. In the “Contacts” form we create a Link to Form 1:M field pointing to our “Campaign Targets” field with show inverse relationship ticked and in “Campaigns” we do a similar Link to Form 1:M field to “Campaign Targets”.

    Now to link a person to the campaign, we can create a new campaign target from the contact record and then select the campaign we want to use or vice versa we can create new campaign targets from the campaign and pick the people to include.

    There are a few advantages of taking this approach:

    • You can get either all campaigns a person is in or all people that a campaign is targeting by going from their respective forms creating a natural export filter.
    • You can add calculation or script fields into the link form with content from either parent form (contact or campaign).
    • You can export a flat list of contact to campaign easily and do filtering in third party tooling.

    The first and third options achieve what I think you’re after without requiring a script field though you might want to use a calculation field to pull in the data you care about from the other two forms.

    Hopefully this helps :)

    #38406
    Daniel Leu
    Participant

    I think you can do everything in your master form. In the master form, add a tag field of type text. Then you can add tags for the different member groups. Use commas or spaces to separate them. Then have filters for the different groups. This way, a member can take part of several groups.

    I use something very similar with a custom layout. To assign a tag, I use a script with a Prompter where I use a pre-populated list.

    Cheers, Daniel

    ---
    See https://lab.danielleu.com/tapformspro/ for scripts and tips&tricks

    #38405
    Gary Beberman
    Participant

    I’m testing Tap Forms now, trying to use it to update an email list. I have two sources:

    – A master list of people
    – A related list with a smaller number of email addresses. Members of this list should be sent a specific kind of email. So, this relationship would be one-to-one, right? That is, if Tap Forms had that as an option. Many addresses in the master list, though would not have related records here. I coded it as a JOIN with “Show Inverse Relationship” checked.
    – In the future, there will likely be more of these lists for different email types. So, the same address could be linked to multiple times. But each relationship would still be one-to-one.

    The objective is to export the master list along with that additional field showing a person should receive that kind of email.

    I coded a calculation field in the master file as:

    IFNOTEMPTY(Still::Email;”Y”;””)

    I can see related records. But, the calculated field is blank. Any advice? Do I have to do this with scripts?

    Thanks!

    Gary

    #38381

    In reply to: Question on Note Field

    Brendan
    Keymaster

    Hi Rocky,

    I’m sorry but the Script function has no access to formatting the text within Note fields.

    Thanks,

    Brendan

    #38377
    Rocky Machado
    Participant

    I think I know the answer here, but thought I would ask. Is it possible to format data in a note field via code? Or when I create text and save it to a note field. Is it possible to send it tags that would format the data when creating via a script.

    Thanks, rocky

    #38372
    Martin Inchley
    Participant

    A simple Calculation (number) field is warming my brain!

    IF(Type = "Dividend";24;32)

    “Type” is the name of a Script field which contains “Dividend” or one of two other values.
    24 and 32 are two arbitrary numbers to help me sort things out.

    With this Calculation, all the records have 24 in the Calculation field, no matter whether Type contains “Dividend” or one of the other values.

    With IF(Type = "";24;32), all the records still show 24.
    With IF(TaxYear = "1718";24;32), all the records in Tax Year 1718 show 24. The others show 32, as expected.

    I can’t see what I’m doing wrong when referencing the field “Type”.

    #38335
    Martin Inchley
    Participant

    In multi-column view with “Show sections” enabled, when my records are sorted on a Date field, the sections are set automatically to include the records for each month. Is there a way of changing that default section period to, say, a year or a day?

    I have a Script field that holds a record’s applicable tax year in 4-digit format (e.g. 1819). When I sort on that field to get some totals for a tax year, the multi-column view shows no sections at all. This is all regardless of showing/hiding Group summaries, and showing/hiding the Calculations row. Nor do sections show up if I sort (e.g.) on account number

    #38332
    Marcus
    Participant

    Thanks, Brendan.
    I tried that already by using var.toFixed(2),
    but this is running in a TypeError: toFixed is not a function.
    This happens only when the script is running over such an affected value, for other values toFixed is working.

    #38326
    Brendan
    Keymaster

    It’s a byproduct of the use of the Objective-C doubleValue method. The formatting and rounding according to the decimal places and Number Format settings doesn’t happen until display time. But internally the value is as it is. You would need to perform some JavaScript rounding of the values yourself if you need to do that.

    #38306
    Brendan
    Keymaster

    I know where you got this from:

    https://stackoverflow.com/questions/27746418/send-email-with-attachment-using-javascript-for-automation

    But that’s JavaScript for Automation. That is, from AppleScript (but using JavaScript instead of the AppleScript language).

    That won’t work from within JavaScriptCore, which is what Tap Forms uses.

    #38305
    Brendan
    Keymaster

    Hi Eddy,

    Did you try this from within Tap Forms? I just tried, but I get Can't find variable Application error. I’m not sure that Application is supported from within the JavaScriptCore framework.

    #38303
    Brendan
    Keymaster

    I don’t have an exact timeline right now. I’m just trying to fix up a memory issue with running scripts. The memory isn’t being released properly. Hopefully not too much longer.

    #38298
    Sam Moffatt
    Participant

    Based on a reply I added on the time delay post I wrote a while back, I decided to clean up and better document the script.

    There are three functions:

    • delay – simple spin lock delay mechanism for blocking execution for duration milliseconds.
    • rateLimitedDelay – ensure that a script blocks for at least minTime milliseconds since the last execution tracked by key.
    • rateLimitedCallback – non-blocking method to execute callback no more frequently than minTime milliseconds since the last execution tracked by key.

    The first use case is pretty simple: call it and wait until the duration expires. The second one is for ensuring you don’t go through a code path too quickly but if you haven’t called it lately it will immediately call it. The third one is used to optionally execute callback if you haven’t executed it in the last minTime milliseconds which is useful for avoiding spamming log messages or other similar events. It enables you to put in a callback but if it’s recently executed to immediately skip it (it’s not blocking). I built this to support a REST progress interface for ensuring it didn’t post updates more frequently than once every few seconds.

    This script uses a pattern I’m adopting of including a simple test case at the end. If you execute the script directly, it’ll run the test case as a sample of how to run. This means when you import you need to also define a variable called PARENT_SCRIPT which is used to disable the test. Technically you can set PARENT_SCRIPT to any value but I use the format FORM NAME::SCRIPT NAME:

    var PARENT_SCRIPT = 'Products::Update SKUs for Product';
    document.getFormNamed('Script Manager').runScriptNamed('Rate Limiter');
    

    Test case:

    	console.log('Message 1 at ' + new Date());
    	rateLimitedDelay('test');
    	rateLimitedDelay('test');
    	rateLimitedCallback('callback', function() { console.log('Callback 1: ' + new Date()) }); 
    	console.log('Message 2 at ' + new Date());
    	delay(3000);
    	rateLimitedCallback('callback', function() { console.log('Callback 2: ' + new Date()) });
    	rateLimitedDelay('test');
    	console.log('Message 3 at ' + new Date());
    	delay(6000);
    	rateLimitedCallback('callback', function() { console.log('Callback 3: ' + new Date()) });
    	console.log('Message 4 at ' + new Date());
    	rateLimitedDelay('test');
    	console.log('Message 5 at ' + new Date());
    	rateLimitedCallback('callback', function() { console.log('Callback 4: ' + new Date()) });
    

    Here’s the full script:

    // ========== Rate Limiter Start ========== //
    // NAME: Rate Limiter
    // VERSION: 1.0.0
    // CHANGELOG:
    //   1.0.0: Initial release.
    /**
     * Rate Limiter module provides utilities to limit and delay
     * over time.
     */
    if (typeof rateLimiter === 'undefined')
    {
    
    	var rateLimiter = {};
    	
    	/**
    	 * Spin lock delay mechanism.
    	 *
    	 * This will block execution until the time limit.
    	 *
    	 * @param {integer} duration - The length of the delay in milliseconds.
    	 */ 
    	function delay(duration)
    	{
    		let now = new Date();
    		let future = now.getTime() + duration;
    		while((new Date()).getTime() < future) { }
    	}
    	
    	/**
    	 * Blocking rate limited delay mechanism.
    	 *
    	 * This will block a request until a minimum time has been elapsed.
    	 * If based on the last execution of the `key`, `minTime` milliseconds
    	 * have not elapsed, this will block until that time has elapsed.
    	 *
    	 * `key` is shared with rateLimitedCallback.
    	 *
    	 * @param {string}  key - The key to validate the last execution.
    	 * @param {integer} minTime - The minimum amount of time between execution.
    	 */
    	function rateLimitedDelay(key, minTime = 5000)
    	{
    		if (typeof rateLimiter[key] === 'undefined')
    		{
    			rateLimiter[key] = 0;
    		}
    		let now = new Date().getTime();
    		let nextExecution = rateLimiter[key] + minTime;
    		if (now < nextExecution)
    		{
    			delay(nextExecution - now);
    		}
    		rateLimiter[key] = new Date().getTime();
    	}
    
    	/** 
    	 * Non-blocking rate limited callback executor.
    	 *
    	 * This will execute `callback` only if `callback` hasn't been 
    	 * executed as `key` for at least `minTime` milliseconds since
    	 * the last execution. If it has been executed then it will not
    	 * execute this instance.
    	 *
    	 * `key` is shared with `rateLimitedDelay`.
    	 *
    	 * @param {string}   key - The key to validate the last execution.
    	 * @param {function} callback - Callback to execute.
    	 * @param {integer}  minTime - The minimum amount of time between executions.
    	 */
    	function rateLimitedCallback(key, callback, minTime = 5000)
    	{
    		if (typeof rateLimiter[key] === 'undefined')
    		{
    			rateLimiter[key] = 0;
    		}
    		let now = new Date().getTime();
    		let nextExecution = rateLimiter[key] + minTime;
    		if (now > nextExecution)
    		{
    			callback();
    			rateLimiter[key] = new Date().getTime();
    		}
    	}
    }
    
    // Tests
    if (typeof PARENT_SCRIPT === 'undefined')
    {
    	console.log('Message 1 at ' + new Date());
    	rateLimitedDelay('test');
    	rateLimitedDelay('test');
    	rateLimitedCallback('callback', function() { console.log('Callback 1: ' + new Date()) }); 
    	console.log('Message 2 at ' + new Date());
    	delay(3000);
    	rateLimitedCallback('callback', function() { console.log('Callback 2: ' + new Date()) });
    	rateLimitedDelay('test');
    	console.log('Message 3 at ' + new Date());
    	delay(6000);
    	rateLimitedCallback('callback', function() { console.log('Callback 3: ' + new Date()) });
    	console.log('Message 4 at ' + new Date());
    	rateLimitedDelay('test');
    	console.log('Message 5 at ' + new Date());
    	rateLimitedCallback('callback', function() { console.log('Callback 4: ' + new Date()) });	
    }
    // ========== Rate Limiter End ========== //
    
Viewing 15 results - 2,161 through 2,175 (of 2,987 total)