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,291 through 1,305 (of 2,989 total)
  • Author
    Search Results
  • #44565

    In reply to: Shopping List

    robinsiebler
    Participant

    I added over 200 products to the products database and also added the ‘Combine Items’ script

    Attachments:
    You must be logged in to view attached files.
    #44564

    In reply to: Shopping List

    robinsiebler
    Participant

    I added a script (Combine Items) to combine duplicate items into one.

    function combineItems() {
    	// Combine duplicate items into one item
    
    	var dict = {};
    	var records = form.getRecords();
    	var item_id = 'fld-097c3d751c854b1fb4b528238d48b2c4';
    	var quantity_id = 'fld-285e2c9de4924b7fbba2fd8311ceb625';
    
    	for (var i = 0, count = records.length; i < count; i++){
    		item = records.getFieldValue(item_id);
    		quantity = records.getFieldValue(quantity_id);
    		record_id = records.getId();
    
    		if (dict[item] === undefined) {
    			dict[item] = [quantity, record_id];
    		} else {
    			dict[item][0] = dict[item][0] + quantity;
    			form.deleteRecord(records);
    			rec = form.getRecordWithId(dict[item][1]);
    			 rec.setFieldValue(quantity_id, dict[item][0]);
    			form.saveAllChanges();
    		}
    	}
    }
    
    combineItems();
    #44563
    Sam Moffatt
    Participant

    Let’s take a step back and look at focusing on just handling the object we’re getting back. Looking at the API, it’s returning an object and then an array for cast. Let’s look at what printing that out could look like as a script. I’m going to remove the variables in the header and prompter at the bottom just to cut down a little and let us focus.

    // variables header above here
    function fetchCastFromURL() {
        fetchURL = `https://api.themoviedb.org/3/movie/${itemID}/credits?api_key=${tmdbAPI}&language=en-US`;
        return Utils.getJsonFromUrl(fetchURL);
    }
    
    function getCast() {
        var cast = fetchCastFromURL();
        return cast;
    }
    
    function getData() {
        getCast();
    }
    
    // prompter code below here
    

    That’s not going to do a lot beyond (hopefully) make the web request. Let’s expand getCast a little:

    
    function getCast() {
        var cast = fetchCastFromURL();
        console.log(JSON.stringify(cast));
        return cast;
    }
    

    All going well you should see the same JSON representation in the console as we would see from the API. Sometimes cast can be falsy if the request fails, so let’s handle that:

    
    function getCast() {
        var cast = fetchCastFromURL();
        if (!cast) {
            console.log("Request to get cast failed");
            return [];
        }
        console.log(JSON.stringify(cast));
        return cast;
    }
    

    We’re just going to return an empty array here and log a message when we fail the request. The cast result is actually a credits object, so let’s do a little rename of our methods and return the internal cast response:

    
    function fetchCreditsFromURL() {
        fetchURL = `https://api.themoviedb.org/3/movie/${itemID}/credits?api_key=${tmdbAPI}&language=en-US`;
        return Utils.getJsonFromUrl(fetchURL);
    }
    
    function getCast() {
        var credits = fetchCreditsFromURL();
        if (!credits) {
            console.log("Request to get credits failed");
            return [];
        }
        console.log(JSON.stringify(credits));
        return credits.cast ? credits.cast : [];
    }
    

    When we look at the documentation, cast is listed as an optional array element inside the credits response object. This means if it is set it should be credits.cast, you can see why we renamed the variables now. The ? syntax is a ternary operator and what we’re doing is checking if credits.cast is truthy and if it is we return it otherwise we hand back an empty array.

    Now it’s time to expand out getData() and we’re going to put a loop in just to see what we get back:

    function getData() {
        let cast = getCast();
        for (let castMember of cast) {
            console.log(castMember.name);
        }
    }
    

    All going well when this is tested we should see an array of cast members’ names printed out into our console. We might have an empty array returned and if that was an error hopefully we also got a log message saying as much (e.g. the “Request to get credits failed”) but otherwise we’ve got our listing of cast members that we can iterate over now. Let’s put the bulk of getData() back together and we’ll add some code to create a new record via a link to form field or table field:

    function getData() {
        var film = fetchDetailsFromURL();
    
        var imdbID = film.imdb_id;
    
        console.log(imdbID)
    
        var itemIds = new Set();
        var currentItemsByImdbID = {};
        var allCurrentItems = form.getRecords();
        for (let currentItems of allCurrentItems) {
            currentItemsByImdbID[currentItems.getFieldValue(imdbid_id)] = currentItems;
            itemIds.add(currentItems.getFieldValue(imdbid_id));
        }
    
        let newRecord;
        if (itemIds.has("http://imdb.com/title/" + imdbID)) {
            Utils.alertWithMessage(film.title + ' already exists.', 'Sorry.');
        } else {
            newRecord = form.addNewRecord();
            newRecord.setFieldValues({
                [title_id]: film.title,
                [released_id]: film.release_date,
                [imdbid_id]: "http://imdb.com/title/" + film.imdb_id,
                [summary_id]: film.overview,
                [runtime_id]: film.runtime,
                [tagline_id]: film.tagline,
            });
    
            document.saveAllChanges();
    
            let cast = getCast();
            for (let castMember of cast) {
                let actorRecord = newRecord.addNewRecordToField(cast_table_field_id);
                actorRecord.setFieldValues({
                    [actor_id]: castMember.name,
                    [role_id]: castMember.character,
                    [tmdb_actor_id]: castMember.id
                });
                document.saveAllChanges();
            }
        }
    
        var Poster = "https://www.themoviedb.org/t/p/w1280/" + film.poster_path
        if (Poster != null) {
            newRecord.addPhotoFromUrlToField(Poster, poster_id);
        }
        form.saveAllChanges();
    }

    We’ve pulled back in the original getData() and I’ve added a block for getting the cast and inside it we’re using addNewRecordToField to get a new record (similar to form.addNewRecord) added to the table field of the record we just created. Behind the scenes this ensures that Tap Forms links the data for us properly. We use setFieldValues as was done earlier because we’re just working with a record object (albeit one that’s a record in a table). I also add in two precautionary document.saveAllChanges() because when dealing with record creation and record linking via the scripting interface there are some quirks that can appear and explicitly flushing the state down generally makes that more consistent. The document.saveAllChanges() call is an alias for form.saveAllChanges() and does the same thing.

    I think this should work or at the very least get you a little closer to your journey.

    #44557
    robinsiebler
    Participant

    Someone expressed and interest in this, so I am uploading it. Thanks to Sam for all his help!

    This is a simple Shopping List. There are 3 forms. The actual shopping list form, a category form and a products form (which contains the items to populate the shopping list with).

    Adding an item to the shopping list is done via a Siri Shortcut (see attached screenshot).

    The expected input to the shortcut is <number> item. If a number is not provided, 1 is assumed. For example, you could say ‘3 Peaches’ or ‘Heavy Cream’.

    When an item is added to the shopping list, it will see if it exists in the product form. If it does, the item will be also given a category (if it exists). If the item does not exist, it will be added to products, but it will not have a category (this will have to be added manually).

    Items are sorted in the Shopping List alphabetically, by category.

    There is only 1 script ‘Get Item From Clipboard’ and it does all the work.

    Enjoy!

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

    Some of the challenges of the Shortcuts interface is that if there is any error in your script, you not only don’t get to see it but also then you get the behaviour where Shortcuts times out because it is waiting for a response that it’ll never get. One of the other issues is that if you have anything that invokes a UI interaction then that will get blocked. And finally we found out late last year that along the way Apple is nuking the clipboard contents so if you’re relying upon that then you’d be out of luck.

    This does mean that it’s limited in what capabilities it can do at the moment. I was thinking about it the other day and I think if it accepted a string and returned a string to Shortcuts then we’d be able to input data into the script and it can be as structured, or unstructured, as necessary for the script to handle.

    robinsiebler
    Participant

    I created a document/form/script. The script worked just fine in Tap Forms. Then I added the script to Siri. I created a Shortcut that used the action to execute the script in the form. However, it did NOT work; I got an error saying that the run was taking too long.

    When I switched to using the x-callback (as suggested), everything was happy.

    The document in question and a screenshot of the shortcut can be found in this thread

    #44546
    Sam Moffatt
    Participant

    The getFieldNamed call will return a TFField object not the field ID that you need. I think to make your code work, you’d need to do:

    var itemField = sl.getFieldNamed('Item');
    var quantityField = sl.getFieldNamed('Quantity');
    newRecord.setFieldValue(itemField.getId(), item);
    newRecord.setFieldValue(quantityField.getId(), quantity);
    

    Personally I use the field ID’s as inserting them is easy enough in the editor.

    I also generally use the x-callback interface with the script URL to invoke Tap Forms that way. You can use “Copy Script Link” from the menu in the script editor to get a link.

    #44545
    robinsiebler
    Participant

    Is there a way to disable the pop up dialog when you run a script?

    #44543
    robinsiebler
    Participant

    Ok, now I have my basic document/form/script. It runs (Yay!). But when I try to trigger it from a Siri Shortcut, nothing happens and then I get an error saying it too too long to run…

    Attachments:
    You must be logged in to view attached files.
    #44540
    Nighthawk
    Participant

    If you get to the point where you want to give up on using TF to create your shopping list, you might want to look at the app ‘AnyList’ (https://www.anylist.com). I’ve used TF for many things but I never got into scripting, so I ran into trouble trying to build my own TF shopping list. I tried AnyList and liked the free version enough to pay the $10 annual fee. Although it can handle meal planning and recipes, I only use it for lists. BTW, it’s also great for ‘To Do’ lists. The best part is that there is a web interface, a Mac app, an iOS app (both iPhone and iPad), an Apple Watch complication, and PC and Android apps (I haven’t used them). You create a free account on their server and the list is immediately synced between all your devices. To be clear, I love TF and I have used it for many things for years, most importantly to keep all our family’s medical records on all our devices and to keep them in sync. I just consider TF to be one tool in my toolbox, and for my shopping lists I found I like the AnyList tool.

    JCK
    Participant

    Inspired by this post detailing how to get watched TV shows, I decided to attempt a Movie import script via TheMovieDB’s API. I’m very new to scripting (really only used iOS Shortcuts) and have gotten stuck and could use some direction or assistance.

    The big issue I can’t seem to crack is iterating through the JSON for to pull out the cast and add them to the cast table on the form. I’ve looked through the example of the above of pulling the singular episode details, but the JSON for TheMovieDB is more robust than OMDB and I’ve confused myself.

    Any Ideas?

    var tmdbAPI = 'xxx';
    
    var title_id = 'fld-7f17a3883cf742ca90a732565f687953';
    var released_id = 'fld-4f1d3a5878914910954b65c2f782abfd';
    var imdbid_id = 'fld-0b8bd8338d8f494aa5b7099c42230e70';
    var poster_id = 'fld-bace3b81b9ab4cc9951a9445d12a63b3';
    var summary_id = 'fld-d16b4361266b48ee9c3b88afd29fd5ac';
    var runtime_id = 'fld-f096b51db4c447e18bf10298135dfaa8';
    var tagline_id = 'fld-ac1ad056b5004ed8a19f8d272ae01e2b';
    var cast_id = 'fld-0b85d9aef49f4fd58726f6830a03ba11';
    
    var actor_id = 'fld-07249465a7ea45e8830da27e62b3121d';
    var role_id = 'fld-bf225b3c443248fd97c5737312acd28b';
    
    var itemID; 
    
    function fetchDetailsFromURL() {
        fetchURL = <code>https://api.themoviedb.org/3/movie/${itemID}?api_key=${tmdbAPI}&language=en-US</code>;
        return Utils.getJsonFromUrl(fetchURL);
    }
    
    function fetchCastFromURL() {
        fetchURL = <code>https://api.themoviedb.org/3/movie/${itemID}/credits?api_key=${tmdbAPI}&language=en-US</code>;
        return Utils.getJsonFromUrl(fetchURL);
    }
    
    function getCast() {
    	var cast = fetchCastFromURL()
    	return cast
    	}
    
    function getData() {
    	var film = fetchDetailsFromURL();
    	
    	var imdbID = film.imdb_id;
    	
    	console.log(imdbID)
    	
    	var itemIds = new Set();
    	var currentItemsByImdbID = {};
       var allCurrentItems = form.getRecords();
       for (let currentItems of allCurrentItems) {
        currentItemsByImdbID[currentItems.getFieldValue(imdbid_id)] = currentItems;
        itemIds.add(currentItems.getFieldValue(imdbid_id));
      }
    	
    	let newRecord;
      	if (itemIds.has("http://imdb.com/title/" + imdbID)) {
      	  	Utils.alertWithMessage(film.title + ' already exists.', 'Sorry.');
      	} else {
    		newRecord = form.addNewRecord();
    		newRecord.setFieldValues({
         		 [title_id]: film.title,
         		 [released_id]: film.release_date,
         		 [imdbid_id]: "http://imdb.com/title/" + film.imdb_id,
        		 [summary_id]: film.overview,
        		 [runtime_id]: film.runtime,
        		 [tagline_id]: film.tagline,
          })	
    	}
    	
    	var Poster = "https://www.themoviedb.org/t/p/w1280/" + film.poster_path
    	if (Poster != null) {
       newRecord.addPhotoFromUrlToField(Poster, poster_id);
      	}
       form.saveAllChanges();
    }
    
    var prompter = Prompter.new();
    prompter.cancelButtonTitle = 'Cancel';
    prompter.continueButtonTitle = 'Go';
    prompter.addParameter('TMDB Number', 'itemID');
    
    prompter.show('Enter an TMDB code', getData)
    

    Here are the TMdb API details: https://developers.themoviedb.org/3/movies/get-movie-credits

    #44536
    Sam Moffatt
    Participant

    You can use form.runScriptNamed('Script Name') to run another form script within the form. I have a script manager form that I centralise and then I can do document.getFormNamed('Script Manager').runScriptName('Script Name') to pull that into my various scripts. This allows you to set up form scripts that are libraries of code that you can use or you can set them up to chain them together as well.

    Looking at your getItemFromClipboard method, you might want to run toLowerCase on the numeric[1] inside the switch that way if something messes with capitalisation the script doesn’t break.

    #44534
    robinsiebler
    Participant

    Ok, I actually made a lot of progress! I figured out how to use a Siri Shortcut to send text to the clipboard and get the clipboard in Tap Forms.

    I have a new script called ‘Get Item from Clipboard’ (It does more than that, but I could not figure out how to chain scripts [if that is possible]) that retrieves the clipboard, parses it, creates a new record and then…tries to populate it. However, that step is failing for some reason.

    Any help would be greatly appreciated!

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

    On mobile, the form scripts are under the “Customize Form” > “Scripts” or if you tap “Run a Script” you can also get to your scripts and manage them. Forms scripts differ from script fields in that they’re executed on demand versus script fields that are supposed to automatically update.

    The way I’ve done this sort of natural language processing is via a script field that uses Javascript regular expressions to match field contents and then update other fields. The reason for this is that if you consider your input (e.g. “3 peaches”) you’re going to want to match “peach” and map that back to a known record.

    Siri’s limited in what conversational features it can do and how applications can integrate. The way I’ve worked around this is using Siri Shortcuts to handle the interaction and then call in a form script in Tap Forms. The video uses a barcode scanner use case but you could create a trigger for Siri to ask for the item to add and then use a dictate text to prompt for input.

    #44527
    robinsiebler
    Participant

    I added saveAllChanges(). That worked. I am not sure what you mean by ‘the 3rd tab’ for scripts; I am doing this on my iPad. I didn’t really understand anything else you said (sorry!). I have attached the latest version of my document.

    I can create a Siri shortcut to run the script. Is it possible to have a Siri shortcut where my wife could say ‘Add 3 peaches to Shopping List’ and have it a) create that record and b) run the script to set the item category?

    Attachments:
    You must be logged in to view attached files.
Viewing 15 results - 1,291 through 1,305 (of 2,989 total)