Can AI Assistants Help Visual Developers Build Web Apps Faster?

With the help of AI assistants, visual developers can build web apps and prototypes faster than ever before. Here's how it works.

Can AI Assistants Help Visual Developers Build Web Apps Faster?

Over the last week, my Twitter timeline has overflowed with users sharing their ChatGPT results. Last night the FOMO kicked in, and I had to take it for a spin.

What is ChatGPT?

ChatGPT is a variant of the GPT-3 (Generative Pretentious Transformer 3) language model that is designed to be used in a conversational context. This means that it is trained to generate relevant and coherent responses to a given conversation. Like other large language models, ChatGPT can generate human-like text on a wide range of topics, but its ability to respond in a conversational manner sets it apart from other models.

The challenge

At Alphi, our most common support enquiry is users asking how they can display data from an Alphi endpoint on their website. Typically we would point them to a nocode/lowcode frontend framework like WeWeb, Wized or AlphiJS.

Sometimes users aren't looking for another tool or framework; instead, they want a Javascript snippet to add to their website.

Could ChatGPT help solve this issue? 🤔

The result

The AI assistant was able to generate the Javascript code to fetch a list of blog posts and display them on the page.

Additionally, it was able to fix an XSS vulnerability when prompted, convert the function to async await and generate a HTML template using TailwindCSS.

Transcript

💬
Create a javascript function that does the following. On page load make a get request to https://jsonplaceholder.typicode.com/posts. Then if the request was successful display each item in the response on the page
🤖
Here is a JavaScript function that does the following: on page load, it makes a GET request to https://jsonplaceholder.typicode.com/posts. If the request was successful, it displays each item in the response on the page:
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // display each item in the response on the page
      response.forEach(item => {
        let div = document.createElement("div");
        div.innerHTML = item.title;
        document.body.appendChild(div);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. Note that this code uses the fetch API, which is not supported in all browsers. If you need to support older browsers, you may need to use a polyfill or a different approach to make the HTTP request.
💬
That was great. When displaying each item clone the element with the id template. Also bind the response to the corresponding field.
🤖
Here is a revised version of the JavaScript function that does the following: on page load, it makes a GET request to https://jsonplaceholder.typicode.com/posts. If the request was successful, it clones the element with the id "template" for each item in the response, and binds the response to the corresponding fields:
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "template"
      let template = document.getElementById("template");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = template.cloneNode(true);
        clone.querySelector(".title").innerHTML = item.title;
        clone.querySelector(".body").innerHTML = item.body;
        document.body.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with the id "template" that contains the structure for each item in the response. The structure of the template should include elements with classes ".title" and ".body" to bind the data to the corresponding fields in the response.
💬
When binding the data use attributes rather than class selectors. To keep things unified use the following naming convention [data-bind="{{item.key}}"]
🤖
Here is a revised version of the JavaScript function that does the following: on page load, it makes a GET request to https://jsonplaceholder.typicode.com/posts. If the request was successful, it clones the element with the id "template" for each item in the response, and binds the response to the corresponding fields using data attributes:
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "template"
      let template = document.getElementById("template");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = template.cloneNode(true);
        clone.querySelector("[data-bind='title']").innerHTML = item.title;
        clone.querySelector("[data-bind='body']").innerHTML = item.body;
        document.body.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with the id "template" that contains the structure for each item in the response. The structure of the template should include elements with the data attribute data-bind="title" and data-bind="body" to bind the data to the corresponding fields in the response.
💬
Excellent! I did notice an XSS vulnerability when binding the data could you fix this?
🤖
Yes, there is an XSS vulnerability in the previous code when binding the data from the response to the page. To fix this, we can use the textContent property instead of the innerHTML property to set the text of the elements. This will prevent any potentially dangerous HTML code from being executed.Here is a revised version of the JavaScript function that does the following: on page load, it makes a GET request to https://jsonplaceholder.typicode.com/posts. If the request was successful, it clones the element with the id "template" for each item in the response, and binds the response to the corresponding fields using data attributes, while preventing any XSS vulnerabilities:
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "template"
      let template = document.getElementById("template");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = template.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        document.body.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with the id "template" that contains the structure for each item in the response. The structure of the template should include elements with the data attribute data-bind="title" and data-bind="body" to bind the data to the corresponding fields in the response.
💬
Impressive! Instead of appending the items to the body, could you append them to the element with the id blogList?
🤖
Yes, instead of appending the items to the <body> element, we can append them to an element with the id "blogList". Here is a revised version of the JavaScript function that does the following: on page load, it makes a GET request to https://jsonplaceholder.typicode.com/posts. If the request was successful, it clones the element with the id "template" for each item in the response, and binds the response to the corresponding fields using data attributes, while preventing any XSS vulnerabilities. It then appends the cloned elements to the element with the id "blogList":
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "template" and the element with the id "blogList"
      let template = document.getElementById("template");
      let blogList = document.getElementById("blogList");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = template.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        blogList.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with the id "template" that contains the structure for each item in the response, and an element with the id "blogList" to which the cloned elements will be appended. The structure of the template should include elements with the data attribute data-bind="title" and data-bind="body" to bind the data to the corresponding fields in the response.
💬
Rename the template elements id from template to blogTemplate
🤖
Yes, we can rename the id of the template element from "template" to "blogTemplate". Here is a revised version of the JavaScript function that does the following: on page load, it makes a GET request to https://jsonplaceholder.typicode.com/posts. If the request was successful, it clones the element with the id "blogTemplate" for each item in the response, and binds the response to the corresponding fields using data attributes, while preventing any XSS vulnerabilities. It then appends the cloned elements to the element with the id "blogList":
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "blogTemplate" and the element with the id "blogList"
      let template = document.getElementById("blogTemplate");
      let blogList = document.getElementById("blogList");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = template.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        blogList.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with the id "blogTemplate" that contains the structure for each item in the response, and an element with the id "blogList" to which the cloned elements will be appended. The structure of the template should include elements with the data attribute data-bind="title" and data-bind="body" to bind the data to the corresponding fields in the response.
💬
You almost got it, it looks like the variable name template was not updated to match the id of the element
🤖
You are correct, the variable name template in the previous code was not updated to match the new id of the element. In this revised version of the code, I have updated the variable name to blogTemplate to match the id of the element:
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "blogTemplate" and the element with the id "blogList"
      let blogTemplate = document.getElementById("blogTemplate");
      let blogList = document.getElementById("blogList");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = blogTemplate.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        blogList.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display it on the page
      let div = document.createElement("div");
      div.innerHTML = error.message;
      document.body.appendChild(div);
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with the id "blogTemplate" that contains the structure for each item in the response, and an element with the id "blogList" to which the cloned elements will be appended. The structure of the template should include elements with the data attribute data-bind="title" and data-bind="body" to bind the data to the corresponding fields in the response.
💬
Could you display the error modal with the id errorModal and set the text content for the element [data-bind="error"] to be the error message.
🤖
Yes, we can display the error modal with the id "errorModal" and set the text content for the element with the data attribute data-bind="error" to be the error message. Here is a revised version of the JavaScript function that does this:
function makeRequest() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "blogTemplate" and the element with the id "blogList"
      let blogTemplate = document.getElementById("blogTemplate");
      let blogList = document.getElementById("blogList");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = blogTemplate.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        blogList.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display the error modal and set the error message
      let errorModal = document.getElementById("errorModal");
      errorModal.querySelector("[data-bind='error']").textContent = error.message;
      errorModal.style.display = "block";
    });
}
// make the request on page load
makeRequest();
🤖
To use this function, you can include it in a <script> tag on your page and call the makeRequest function. The page should also include an element with
💬
Perfect, finally rename the function get getBlogPosts
🤖
Yes, we can rename the function from makeRequest to getBlogPosts to better reflect its purpose. Here is a revised version of the JavaScript function with the new name:
function getBlogPosts() {
  // make a GET request to https://jsonplaceholder.typicode.com/posts
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then(response => {
      // if the request was successful, process the response
      if (response.ok) {
        return response.json();
      }
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    })
    .then(response => {
      // get the element with the id "blogTemplate" and the element with the id "blogList"
      let blogTemplate = document.getElementById("blogTemplate");
      let blogList = document.getElementById("blogList");
      // for each item in the response, clone the template and bind the data
      response.forEach(item => {
        let clone = blogTemplate.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        blogList.appendChild(clone);
      });
    })
    .catch(error => {
      // if there was an error, display the error modal and set the error message
      let errorModal = document.getElementById("errorModal");
      errorModal.querySelector("[data-bind='error']").textContent = error.message;
      errorModal.style.display = "block";
    });
}
// make the request on page load
getBlogPosts();
🤖
To use this function, you can include it in a <script> tag on your page and call the getBlogPosts function
💬
Thanks, this worked perfectly! Could you change the code to use async await?
🤖
Yes, we can use the async and await keywords to make the code easier to read and write. Here is a revised version of the JavaScript function that uses async and await:
async function getBlogPosts() {
  try {
    // make a GET request to https://jsonplaceholder.typicode.com/posts
    let response = await fetch("https://jsonplaceholder.typicode.com/posts");
    // if the request was successful, process the response
    if (response.ok) {
      let responseJson = await response.json();
      // get the element with the id "blogTemplate" and the element with the id "blogList"
      let blogTemplate = document.getElementById("blogTemplate");
      let blogList = document.getElementById("blogList");
      // for each item in the response, clone the template and bind the data
      responseJson.forEach(item => {
        let clone = blogTemplate.cloneNode(true);
        clone.querySelector("[data-bind='title']").textContent = item.title;
        clone.querySelector("[data-bind='body']").textContent = item.body;
        blogList.appendChild(clone);
      });
    } else {
      // if the request was not successful, throw an error
      throw new Error("Request failed: " + response.statusText);
    }
  } catch (error) {
    // if there was an error, display the error modal and set the error message
    let errorModal = document.getElementById("errorModal");
    errorModal.querySelector("[data-bind='error']").textContent = error.message;
    errorModal.style.display = "block";
  }
}
// make the request on page load
getBlogPosts();
🤖
To use this function, you can include it in a <script> tag on your page and call the getBlogPosts function. The page should also include an element with the
💬
Blimey! Can you create a HTML template?
🤖
Yes, we can create an HTML template for the page that includes the required elements and structure. Here is a basic template that you can use:
<!DOCTYPE html>
<html>
  <head>
    <title>Blog Posts</title>
    <style>
      /* add styles for the page here */
    </style>
  </head>
  <body>
    <h1>Blog Posts</h1>
    <div id="blogList">
      <!-- this is the template for each item in the response -->
      <div id="blogTemplate">
        <h2 data-bind="title"></h2>
        <p data-bind="body"></p>
      </div>
    </div>
    <!-- this is the error modal -->
    <div id="errorModal" style="display: none;">
      <h2>An error occurred</h2>
      <p data-bind="error"></p>
    </div>
    <script>
      // include the JavaScript function here
    </script>
  </body>
</html>
🤖
This template includes an element with the id "blogList" to which the cloned elements will be appended, an element with the id "blogTemplate" that contains the structure for each item in the response, and an error modal with the id "errorModal" that will be displayed if an error occurs. The structure of the template includes elements with the data attributes data-bind="title" and data-bind="body" to bind the data to the corresponding fields in the response, and data-bind="error" to display the error message. You can add your own styles for the page in the <style> section, and include the JavaScript function in the <script> section.
💬
You surprise me every time! I challenge you to make it look pretty by displaying the posts in a grid using TailwindCSS.
🤖
We can use TailwindCSS to style the page and display the posts in a grid. Here is a revised version of the HTML template that uses TailwindCSS classes to style the page and display the posts in a grid:
<!DOCTYPE html>
<html>
  <head>
    <title>Blog Posts</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css" />
  </head>
  <body class="bg-gray-100">
    <h1 class="text-2xl font-bold m-4">Blog Posts</h1>
    <div id="blogList" class="grid grid-cols-2 gap-4 m-4">
      <!-- this is the template for each item in the response -->
      <div id="blogTemplate" class="p-4 bg-white rounded-lg shadow-md">
        <h2 class="font-bold" data-bind="title"></h2>
        <p data-bind="body"></p>
      </div>
    </div>
    <!-- this is the error modal -->
    <div id="errorModal" class="fixed bottom-0 left-0 right-0 p-4 bg-white rounded-lg shadow-md" style="display: none;">
      <h2 class="font-bold">An error occurred</h2>
      <p data-bind="error"></p>
    </div>
    <script>
      // include the JavaScript function here
    </script>
  </body>
</html>
🤖
This template includes the TailwindCSS stylesheet in the <head> section, and uses TailwindCSS classes to style the page and display the posts in a grid. The "blogList" element uses the grid and grid-cols-2 classes to display the posts in two columns, and the gap-4 class to add a 4px gap between the columns. The "blogTemplate" element uses the p-4, bg-white, rounded-lg, and shadow-md classes to add padding, a white background, rounded corners, and a drop shadow. The error modal uses similar styles to the "blogTemplate" element, with the addition of the fixed, bottom-0, left-0, and right-0 classes to position it at the bottom of the page. You can include the JavaScript function in the <script> section as before.
💬
Could you wrap the blogTemplate element in a hidden div to prevent it from appearing in the list of blog posts?
🤖
Yes, we can wrap the "blogTemplate" element in a hidden <div> to prevent it from appearing in the list of blog posts. Here is a revised version of the HTML template that does this:
<!DOCTYPE html>
<html>
  <head>
    <title>Blog Posts</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css" />
  </head>
  <body class="bg-gray-100">
    <h1 class="text-2xl font-bold m-4">Blog Posts</h1>
    <div id="blogList" class="grid grid-cols-2 gap-4 m-4">
      <!-- this is the hidden container for the template -->
      <div style="display: none;">
        <!-- this is the template for each item in the response -->
        <div id="blogTemplate" class="p-4 bg-white rounded-lg shadow-md">
          <h2 class="font-bold" data-bind="title"></h2>
          <p data-bind="body"></p>
        </div>
      </div>
    </div>
    <!-- this is the error modal -->
    <div id="errorModal" class="fixed bottom-0 left-0 right-0 p-4 bg-white rounded-lg shadow-md" style="display: none;">
      <h2 class="font-bold">An error occurred</h2>
      <p data-bind="error"></p>
    </div>
    <script>
      // include the JavaScript function here
    </script>
  </body>
</html>
🤖
This template includes a hidden <div> element that wraps the "blogTemplate" element, with the display: none; style to hide it from view. This ensures that the "blogTemplate" element is not included in the list of blog posts when the page is rendered. The JavaScript function can be included in the <script> section as before.
💬
🤯
🤖
I'm glad I could help! Is there anything else you would like me to do?
💬
No thanks
🤖
You're welcome! If you have any other questions, feel free to ask. I'm here to help.

Summary

Whilst this was a great experiment, I would only recommend generating code snippets for production if you are well-versed in writing Javascript. Nevertheless, I am excited to see how AI assistants impact the no-code landscape over the next year and whether we will see page builders adopt the technology. The future is bright. 🌅