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,246 through 1,260 (of 2,951 total)
  • Author
    Search Results
  • #44601
    Brendan
    Keymaster

    Hi Redrock,

    There’s no custom layouts function on the iOS version of Tap Forms.

    And linked records always display in a separate list on iOS. At some point I might change that to display like the Table field does, which displays inline on the parent record as a table of sub-records.

    So if you need to display things visually like that, you would want to use a Table field instead of a Link to Form field.

    Or alternatively, you could write a script which picks out a field from the Link to Form field’s form and displays that in a list of values on the parent record.

    Thanks,

    Brendan

    #44595
    Sam Moffatt
    Participant

    You’re using a bunch of global variables, each time you do var thing then thing becomes a global variable when you’re doing it outside of a function. That’s why you can use the variables almost anywhere though in general that’s not best practice. The prompter uses this technique in part because it’s an async call but once we’ve stepped out of that, it’s best to use actual arguments and return values. When you do var inside the function, it’s scoped to the function and not accessible outside it. Let’s rewrite this slightly to use an input variable for inputID and return a value:

    function convertIMDBtoTMDB(inputID) {
        fetchURL = `
        https : // api.themoviedb.org/3/find/${inputID}?api_key=${tmdbAPI}&language=en-US&external_source=imdb_id`;
        var tmdbResp = Utils.getJsonFromUrl(fetchURL);
        var tmdbID = tmdbResp.movie_results[0].id;
        console.log(JSON.stringify(tmdbID))
        if (! tmdbID) {
            console.log("Request to get code failed");
            return "";
        } else {
            return tmdbID;
        }
    }
    

    Same function except we’re accepting an inputID as an argument and then returning the tmdbID. I left the tmdbAPI alone because I feel it’s a constant more than a variable and something you’d want to leave in global scope. Where possible you want to explicitly tell a function what it’s inputs are, in this case literally inputID but even in the other places it’s better to be explicit:

    function fetchCreditsFromURL(itemID) {
        fetchURL = `https://api.themoviedb.org/3/movie/${itemID}/credits?api_key=${tmdbAPI}&language=en-US`;
        return Utils.getJsonFromUrl(fetchURL);
    }

    That way you know where a variable is coming from and you’re less likely to have a variable in global scope accidentally trashed. Nothing in Javascript is straight forwards so I was looking for a good resource and this page on demystifying Javascript variable scope has some great details on how it works and where some of the pitfalls are.

    Instead of relying on the global changing, assign it to a variable in the right scope and then pass it along to anything else that needs it. Hopefully that helps get you a little further :)

    #44591

    In reply to: Shopping List

    robinsiebler
    Participant

    Ok, I added the checkmark field. In addition, I added a Search Filter for unchecked items and a script you can use to remove checked items.

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

    In reply to: Shopping List

    robinsiebler
    Participant

    SO just to verify:
    1. If you manually add an item to the Shopping List, the categopy is not added.
    2. If you manually run the script, the category is added.
    3. If you run the Shortcut the category is added.

    If all of that is true, I think all that I have to do is a add a field script to the Shopping List form that will update the category.

    I will try that and get back to you.

    #44584

    In reply to: Shopping List

    Roger Cuthbert
    Participant

    I added Naan manually and the shopping list record did not add the category.

    I created a shortcut as you suggested. Added Naan to the clipboard and ran your script and the category is added correctly.

    #44583

    In reply to: Shopping List

    robinsiebler
    Participant

    And the item you are adding is in the Product form and has a category? If so, could you try this? Add the item in question to the clipboard and just run the script ‘Get Item from Clipboard’. Let me know what happens.

    #44572

    In reply to: Shopping List

    robinsiebler
    Participant

    I fixed some bugs and added a notes field. I also added another 100 products to the products form. In addition, I updated the Shortcut to prompt for a note (see screen shot). However, Siri is stupid! If you say ‘No’ when you are prompted for a note, Siri bails on the entire script! So, instead of saying ‘No’, say ‘Later’ and you will not be prompted for the note.

    I should mention that you have to manually create the Shortcut using the attached screenshot as a guide. I have no clue how to share a shortcut outside of the Apple ecosystem.

    Attachments:
    You must be logged in to view attached files.
    #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?

Viewing 15 results - 1,246 through 1,260 (of 2,951 total)