Create a Web Screen list with real time filtering by injecting JSON 2017-06-07

Learn how to inject JSON data into an AutoTools Web Screen so that you can dynamically process it

  1. joaomgcd
    IMPORTANT: There's an easier way to get Tasker data into Web Screens by using Web Screen Variables. If that's all you need, please use that. If you really need to inject JSON into a page then go ahead and use this :)

    In this tutorial we're going to be injecting some JSON data into an AutoTools Web Screen, which will then use that data to dinamically generate a list of apps depending on what's written in a text box.

    This is how it'll look like in the end:

    STEP 1 - QUERY APPS AND WRITE JSON


    • Create a Task called App List
    • Add an AutoLaunch Query action and accept it right away to get all available apps
    • Add an AutoTools Write JSON action
    • Under Arrays set Add to Array Key to apps
    (i) This will create an array called apps at the base of a JSON object. More about writing JSON here.
    • In Array Object Keys write name,package,icon
    • In Array Object Values write %allabels()|%alpackages()|%alicons()|
    (i) This will create a list of apps in the JSON array, each with a name, package name and icon
    • Accept and go back to Tasker
    • Add a Flash action to show that the JSON was correctly created.


    STEP 2 - SHOW APP LIST


    (i) This will create a JavaScript variable called appdata with the JSON data we created before. This appdata variable will then be used by the page to display the app list.
    • Accept and go back to Tasker


    STEP 3 - TEST


    If you now run the Task a list of your apps should show up. If you write something in the textbox on the top right the app list should be filtered. :cool:

    If you click on an app it'll launch the app, assuming you create a profile to launch it as shown in STEP 6 of this tutorial.



    Explanation of the web page used in this tutorial
    The page used in this example is a simple HTML page that takes whatever is in the appdata JavaScript variable and uses to create a list of apps.
    Let's go through the various parts of the page:

    Styling
    Code (CSS):
            input{          
                position: fixed;
                right: 16px;
            }      
            .app img{
                width: 50px;
                pointer-events: none;
            }
            .app span{
                pointer-events: none;
            }
    This part simply sets the elements in the right positions and makes images 50px in width.

    Testing
    Code (Javascript):
    if(!window["appdata"]){
                var appdata = {"apps":[
                    {
                        "name":"Test",
                        "package":"test",
                        "icon":"test.png"
                    }
                ]};
            }
    This creates the appdata variable if it doesn't already exist. Allows for easier testing on your PC where the real appdata is not available

    HTML
    HTML:

    <input type="text" onkeyup="filter();" id="filterinput" />
    <div id="apps"></div>
    <div class="app"><img src="test.png" /><span>name</span></div>
    This is the HTML body of the page.
    It contains:
    • a text input box where you can write the name of the app. When you write something in it, the filter() function will be called (we'll create that ahead
    • an empty apps element where the list of apps will be created
    • an element with the class app that will be used as the template for each app. Has an image and a name element. This will be removed via JavaScript when the true list of apps is created. The sole purpose of this element is to be cloned for each single app. It makes creating the HTML code for each app much easier.
    Removing App HTML template
    Code (Javascript):
            var appNodeFromDocument = document.querySelector(".app");
            var appNode = appNodeFromDocument.cloneNode(true);
            appNodeFromDocument.parentNode.removeChild(appNodeFromDocument);
    In this piece of code I clone the app element and then remove it from the body of the HTML page. This way I can use this element to create each app to be shown on the page.

    Filter Function
    Code (Javascript):
            var filter = function(){
                var filterText = document.querySelector("#filterinput").value;
                var filtered = appdata.apps;
                if(filterText){
                    filterText = filterText.toLowerCase();
                    filtered = filtered.filter(app=>app.name.toLowerCase().indexOf(filterText)>=0);
                }
                var appsElement = document.querySelector("#apps");
                appsElement.innerHTML = "";
                for(var app of filtered){
                    var appElement = appNode.cloneNode(true);
                    appElement.app = app;
                    appElement.querySelector("span").innerHTML = app.name;
                    appElement.querySelector("img").src = "file://" + app.icon;
                    appElement.onclick = e => window.location.href = "autotoolscommand://openapp=:=" + e.target.app.package;
                    appsElement.appendChild(appElement);
                }
            };
    This will be called every time the text in the text input box changes. It will generate the app list depending on what's written there.

    Code (Javascript):
                var filterText = document.querySelector("#filterinput").value;
    Gets the current text from the input box element from the page.

    Code (Javascript):
                var filtered = appdata.apps;
                if(filterText){
                    filterText = filterText.toLowerCase();
                    filtered = filtered.filter(app=>app.name.toLowerCase().indexOf(filterText)>=0);
                }
    Gets the app list from the appdata variable. Then, if there's text in the input box, it'll filter the app list by its name (using lower case comparison so that it's case insensitive).

    Code (Javascript):
                var appsElement = document.querySelector("#apps");
                appsElement.innerHTML = "";
    Gets the apps element from the page and clears whatever is inside it so we can populate it with a new filtered app list.

    Code (Text):
                for(var app of filtered){
                    var appElement = appNode.cloneNode(true);
                    appElement.app = app;
                    appElement.querySelector("span").innerHTML = app.name;
                    appElement.querySelector("img").src = "file://" + app.icon;
                    appElement.onclick = e => window.location.href = "autotoolscommand://openapp=:=" + e.target.app.package;
                    appsElement.appendChild(appElement);
                }
    For each app in the filtered app list, we'll create a new app element on the page and set the app property on it (so we can use it when clicking it)
    Then for this app element:
    • set its text (span) to the app name.
    • Set its image source to the app icon (prefixed by "file://" so that the local files generated by the AutoLaunch Query will have the correct path)
    • Set its on click action to issuing the openapp=:=package AutoApps command. We get the package from the click event's target's app (which we set before, remember?)
    Finally we append this new app element to app list with the appendChild function.

    Do First Filter
    Code (Javascript):
            filter();
    Finally we want to populate the app list with all apps when first creating the page, so run the filter() function once. Because the text input doesn't have any text yet, all apps will be shown.