<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tony</title>
    <description>The latest articles on DEV Community by Tony (@tony_9bf2c6743fcf7).</description>
    <link>https://dev.to/tony_9bf2c6743fcf7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2954391%2F7fe82227-81b0-4fa0-8455-cb47c400e7f9.png</url>
      <title>DEV Community: Tony</title>
      <link>https://dev.to/tony_9bf2c6743fcf7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tony_9bf2c6743fcf7"/>
    <language>en</language>
    <item>
      <title>Showcasing three recent improvements to Anvil</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Tue, 11 Nov 2025 11:26:11 +0000</pubDate>
      <link>https://dev.to/anvil/showcasing-three-recent-improvements-to-anvil-25e8</link>
      <guid>https://dev.to/anvil/showcasing-three-recent-improvements-to-anvil-25e8</guid>
      <description>&lt;h2&gt;
  
  
  We've made changes to improve your developer experience
&lt;/h2&gt;

&lt;p&gt;Anvil is always evolving to give its users full power to make any web app they wish. In this article, we'll go over three recent features that we made specifically to give more control and options when building web apps with Anvil.&lt;/p&gt;

&lt;p&gt;Here's what our latest efforts empower you to do, with nothing but Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use industry-standard design language, with the &lt;strong&gt;Material 3 theme&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use smart and secure databases, with &lt;strong&gt;Model Classes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Build easily navigable multi-page apps, with Anvil's &lt;strong&gt;routing dependency&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see all these features in action, take a look at &lt;a href="http://anvil.works/learn/examples/hr-workflow?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;this example app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply industry-standard design language
&lt;/h2&gt;

&lt;p&gt;How your app looks is, understandably, a huge priority when it comes to building an Anvil app. So, we've given you more tools to get your app to look exactly how you want it to.&lt;/p&gt;

&lt;p&gt;First off, our new &lt;strong&gt;Material 3 Theme&lt;/strong&gt; is here with plenty of shiny and sleek components for you to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjpsyzhw3t5fe86zbazb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjpsyzhw3t5fe86zbazb.png" alt="The updated homepage of the HR Workflow App. Its sleek new look uses the new Material 3 Theme." width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Anvil Material 3 Theme is available for both &lt;a href="https://anvil.works/docs/ui/app-themes/material-3#how-to-use-the-material-3-theme?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;new apps and existing apps&lt;/a&gt;. It is &lt;a href="http://anvil.works/docs/ui/app-themes/material-3?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;exhaustively documented&lt;/a&gt; and updated regularly.&lt;/p&gt;

&lt;p&gt;Secondly, we've changed our approach to themes and enhanced the ability for you to &lt;strong&gt;create your own themes and components&lt;/strong&gt;. &lt;a href="https://anvil.works/docs/deployment/dependencies?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;Apps used as dependencies can now share their custom components&lt;/a&gt;. You can make an entire app filled with components styled exactly how you see fit, and then use this app as a dependency. This lets you build a library of components, themes and layouts that you can then use in any other app. In fact, that's exactly how we built the Material 3 Theme!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensure secure and powerful database interactions
&lt;/h2&gt;

&lt;p&gt;Dealing with data can be difficult -- you need your data to be flexible, modifiable and accessible, yet secure. This is where &lt;strong&gt;Model Classes&lt;/strong&gt; come in. Model Classes let you handle all validation, observation and transformation in one single Python script, letting you enjoy all the benefits of a secure database without compromising on flexibility.&lt;/p&gt;

&lt;p&gt;Here are a few things Model Classes enable you to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have your user rows automatically calculate the age of the user they represent, using their registered date of birth.
&lt;/li&gt;
&lt;li&gt;Ensure the execution of specific code whenever a new row is created or updated.
&lt;/li&gt;
&lt;li&gt;Check for permission when a user attempts to modify a row.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, let's say that we have an app where users can create accounts, and we want to notify the app owner whenever a new user is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from anvil.tables import app_tables
import anvil.email

class User(app_tables.users.row):
    # We inherit from the Row class from our users table.
    # Through Model Classes, this allows us to add logic to our row objects.

    def _do_create():
        # This method is run every time a new row object is created.
        anvil.email.send(
            to="owner@email.com",
            subject="New User Registered",
            text = """Hello Owner!
            A new user has registered to your app.
            """
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With just this simple script, we have added logic to our data table, and now, you can too!&lt;/p&gt;

&lt;p&gt;All this and much more is dutifully explained in &lt;a href="https://anvil.works/docs/data-tables/model-classes?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;Model Classes' documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provide clear navigation
&lt;/h2&gt;

&lt;p&gt;We've built a new way to use routing for page navigation within Anvil. Our new &lt;a href="https://routing-docs.anvil.works/" rel="noopener noreferrer"&gt;routing dependency&lt;/a&gt; makes the set-up process very easy, letting you set up and configure URL routes via a script, as you would any other element of your app.&lt;/p&gt;

&lt;p&gt;Routing empowers you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let your users &lt;strong&gt;use browser bookmarks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redirect your users&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;navigation to specific app states from an external link&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxcv56rxbxmcldwse59a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxcv56rxbxmcldwse59a.gif" alt="Navigation through the HR Workflow App, handled through the Anvil routing dependency." width="600" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using routing for navigation offers a very native experience for your users, and the routing dependency lets you implement it the same way you would any other component. Our &lt;a href="(https://anvil.works/docs/client/navigation/routing?utm_source=devto_feature_roundup)"&gt;routing documentation&lt;/a&gt; is a great starting-off point, and the &lt;a href="https://routing-docs.anvil.works/" rel="noopener noreferrer"&gt;dependency's standalone documentation&lt;/a&gt; has all the technical details you could possibly ask for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dive in!
&lt;/h2&gt;

&lt;p&gt;We hope that these additional tools empower our users to build exactly what they have in mind, with all the features they desire. All you need to get started is &lt;a href="https://anvil.works/sign-up?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;sign up&lt;/a&gt;, and get coding. It's that easy.&lt;/p&gt;

&lt;p&gt;If you're looking for an example, &lt;a href="http://anvil.works/learn/examples/hr-workflow?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;this example app&lt;/a&gt; showcases all the features described here, with explanatory comments throughout the code.&lt;/p&gt;

&lt;p&gt;We also have a bunch of &lt;a href="https://anvil.works/learn/tutorials?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;tutorials&lt;/a&gt; to help if you're ever lost, and the &lt;a href="https://anvil.works/forum?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;Anvil community forum&lt;/a&gt; is filled to the brim with brilliant and helpful people, so you're never alone.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Making a Clicker Game with a Leaderboard</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Thu, 27 Mar 2025 11:07:38 +0000</pubDate>
      <link>https://dev.to/anvil/making-a-clicker-game-with-a-leaderboard-oa1</link>
      <guid>https://dev.to/anvil/making-a-clicker-game-with-a-leaderboard-oa1</guid>
      <description>&lt;h2&gt;
  
  
  Are you the Ultimate Clicker?
&lt;/h2&gt;

&lt;p&gt;Arguably, the web is built from small, often ridiculous ideas. Sometimes, you don't really feel like making the next Amazon or an internal tool to "promote synergy between stakeholders". Sometimes, you just get a fun little idea, and you want to shove that into your nearest internet pipe and share it with your friends.&lt;/p&gt;

&lt;p&gt;When I started using Anvil, I quickly realized I could use it for pretty much whatever I wanted to make, be it sleek and professional productivity-oriented tools, or, you know, &lt;strong&gt;a clicker game that my friends and I can compete in!&lt;/strong&gt; And, best of all, it could do it fast and without requiring poring over documentation for days on end.&lt;/p&gt;

&lt;p&gt;You can clone the finished app by clicking &lt;a href="https://anvil.works/build#clone:PPF6KC5YOFADVWXY%3dO4KHABTFR5VUVFKVMQC5DTZD" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is super simple: have my friends set up an account, let them click on a button as many times as they can to earn points, display all my friends’ total points on a public leaderboard, and let their competitive spirit do the rest.&lt;/p&gt;

&lt;p&gt;Anvil made the process super quick and painless, you can easily knock this down in an afternoon. Let me walk you through how I did it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Chose Anvil
&lt;/h2&gt;

&lt;p&gt;For my app, I needed a tool that provided a traditional web app structure, complete with a user interface, client-server architecture, and ideally, the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for &lt;a href="https://anvil.works/learn/tutorials/using-layouts-to-create-multi-page-app" rel="noopener noreferrer"&gt;&lt;strong&gt;multiple pages&lt;/strong&gt;&lt;/a&gt; and navigation between them&lt;/li&gt;
&lt;li&gt;Log-in system for &lt;a href="https://anvil.works/learn/tutorials/multi-user-apps" rel="noopener noreferrer"&gt;&lt;strong&gt;multiple users&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://anvil.works/docs/data-tables" rel="noopener noreferrer"&gt;&lt;strong&gt;integrated database&lt;/strong&gt;&lt;/a&gt; for storing users’ points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spoiler alert: Anvil has all of those, among many more, and they’re super easy to set up. All I had to do was create a new app using the editor, use the &lt;a href="https://anvil.works/docs/editor/form-editor" rel="noopener noreferrer"&gt;drag-and-drop interface&lt;/a&gt; to build my navigation layout, include the &lt;a href="https://anvil.works/docs/users" rel="noopener noreferrer"&gt;log-in feature&lt;/a&gt; by literally just clicking on a couple of boxes, and it even automatically created an &lt;a href="https://anvil.works/docs/data-tables" rel="noopener noreferrer"&gt;integrated Data Table&lt;/a&gt; to store all the user information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building A User Interface
&lt;/h2&gt;

&lt;p&gt;Our UI should be pretty simple: one page to get a bunch of clicks in, and another to see ourselves climbing the leaderboard.&lt;/p&gt;

&lt;p&gt;I thus created two Forms based on the navigational &lt;a href="https://anvil.works/docs/ui/layouts" rel="noopener noreferrer"&gt;layout&lt;/a&gt; I had created prior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Clicker&lt;/strong&gt; Form, which only needed a simple button and would communicate with a "Leaderboard" Data Table, storing all users' scores.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Leaderboard&lt;/strong&gt; Form, with a data grid to display the app’s top 10 users with the most points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmf6jimksuwaqfwbpgth.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmf6jimksuwaqfwbpgth.gif" alt="Image description" width="960" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a clear idea in mind, I hopped in the editor and designed my heart away. The drag-and-drop interface made it very easy to arrange the various components however I wanted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkyg5gzjmyub7p9xhy3f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkyg5gzjmyub7p9xhy3f.gif" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that was done, it was time to program the behavior of the interface with some simple Python code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering &amp;amp; Logging Users In
&lt;/h2&gt;

&lt;p&gt;I am a simple person. I do not know fancy HTML, JavaScript or CSS. That’s three whole languages, when most people only really know one. Thankfully, Anvil lets you create &lt;strong&gt;full-stack apps with nothing but Python&lt;/strong&gt;, so I can remain a simple person and still get my friends to ruthlessly compete against each other over who can click their mouse the most.&lt;/p&gt;

&lt;p&gt;The first thing I did was add a way for users to enter a username for the leaderboard. I wanted it to be so that when somebody logs in for the first time, an Alert pops up and prompts them for a username, which is then saved along with the rest of their user information in the “Users” Data Table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582pg49lysed879zwpjc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582pg49lysed879zwpjc.gif" alt="Image description" width="974" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this purpose, I created a new Form, that I named UserEdit, that would be shown upon login. I placed a Label asking the user for their username, and a TextBox for the user to type it in. I then made the content of the TextBox a &lt;a href="https://anvil.works/learn/tutorials/data-bindings" rel="noopener noreferrer"&gt;data binding&lt;/a&gt;, so I could easily use the input username in code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1hzg1845guai3hv249e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1hzg1845guai3hv249e.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Within the &lt;a href="https://anvil.works/docs/ui/forms#the-startup-form" rel="noopener noreferrer"&gt;startup Form&lt;/a&gt;'s code, right after logging the user in, I have the server check if that user already has a username. If not, I &lt;a href="https://anvil.works/docs/client/alerts-and-notifications" rel="noopener noreferrer"&gt;display an Alert&lt;/a&gt; showing the UserEdit Form I had just created.&lt;/p&gt;

&lt;p&gt;Upon confirmation from the user, the UserEdit Form then returns the username that was entered, which is sent to the server and saved within the "Users" Data Table for the current user. Finally, a row for this new user is initialized within the "Leaderboard" Data Table with zero points.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

login_with_form()
# Ask the server to check if the currently logged-in user has a name.
if not anvil.server.call('does_current_user_have_a_name'):
    # Open an Alert pop-up that prompts the user for their name.
    name = alert(UserEdit(), large=True, dismissible=False, buttons=None)
    # The obtained name is then sent to the server for user initialization.
    anvil.server.call('initialize_user', name)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Server code

@anvil.server.callable
def does_current_user_have_a_name():
  current_user = anvil.users.get_user()
  # Check that a user is currently logged in and, if so, that they have a non-empty username.
  return current_user is not None and current_user['username'] not in (None, '')

@anvil.server.callable
def initialize_user(name):
  current_user = anvil.users.get_user()
  # Add the gathered name to our user row.
  current_user.update(username=name)
  # Add a new row to the leaderboard Data Table, with our user in the user column and 0 in the points column.
  app_tables.leaderboard.add_row(user=current_user, points=0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Displaying Data From Data Tables
&lt;/h2&gt;

&lt;p&gt;With the user side of the app setup, it was time to take care of the leaderboard.&lt;/p&gt;

&lt;p&gt;For this, I used Anvil's &lt;a href="https://anvil.works/docs/api/anvil#DataGrid" rel="noopener noreferrer"&gt;DataGrid&lt;/a&gt; to display rows of the "Leaderboard" database. I placed an instance of that component in my page and named it &lt;code&gt;top_10_panel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;top_10_panel&lt;/code&gt; Data Grid component needed to communicate with the "Leaderboard" Data Table. I made the Leaderboard Form fetch the contents of the "Leaderboard" Data Table whenever shown, sort the rows by descending order of points, and set the 10 first entries to populate the DataGrid. Easy-peasy!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

def refresh_top_10_grid(self):
    top_10_clickers = anvil.server.call('get_top_10_clickers')
    # Set our DataGrid's contents to be the top 10 leaderboard rows.
    self.top_10_panel.items = top_10_clickers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Server code

@anvil.server.callable
def get_top_10_clickers():
  # Create a list containing, for each user, a dictionary with their username and points.
  all_users = [
    {
      'username': row['user']['username'],
      'points': row['points']
    } for row in app_tables.leaderboard.search()
  ]
  # Sort our list based on a descending order of points.
  all_users.sort(key=lambda x: x['points'], reverse=True)
  # Reconstruct our sorted list by enumerating it and added a ranking to each user dictionary.
  ranked_users = [
    {
      'rank': i+1,
      'username': user_dict['username'],
      'points': user_dict['points'],
    } for i, user_dict in enumerate(all_users)
  ]
  # Only return the first 10 items of our ranked list.
  return ranked_users[:10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making Components Interactive With Events
&lt;/h2&gt;

&lt;p&gt;Finally, all I had to do was make the clicker button actually increase your score on each click. Anvil components can raise &lt;a href="https://anvil.works/docs/client/events" rel="noopener noreferrer"&gt;events&lt;/a&gt;, which code can react to, in response to user interaction.&lt;/p&gt;

&lt;p&gt;When Button components are clicked they raise a 'click' event, so all I had to do was create a handler function to run when a user clicks the button. This is easily done from the Object Palette, or the Properties Panel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Funh3hzd9obcl77mwbl37.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Funh3hzd9obcl77mwbl37.gif" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the event handler in place to detect button clicks, all that remained was writing the logic into the event handler.&lt;/p&gt;

&lt;p&gt;We want every click event raised by our button to increase a &lt;code&gt;local_points&lt;/code&gt; property of the Clicker Form, which is at first initialized by fetching the amount of points of the current user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

def on_clicker_clicked(self, **event_args):
    # This event is triggered whenever the clicker button is clicked.
    self.item['local_points'] += 1
    # Refresh our data bindings to make sure our components reflect the form's newly updated `item` property.
    self.refresh_data_bindings()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clicking the button should also start a &lt;a href="https://anvil.works/docs/ui/components/basic#timer" rel="noopener noreferrer"&gt;timer&lt;/a&gt;: when that timer reaches one second, a call is made to the server with the new amount of points to save, but each button click restarts the timer. This ensures that we don’t slow down the app with as many server calls as there were clicks, but instead only make the call once the user is done clicking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

def on_clicker_clicked(self, **event_args):
    # This event is triggered whenever the clicker button is clicked.
    self.item['local_points'] += 1
    # Refresh our data bindings to make sure our components reflect the form's newly updated `item` property.
    self.refresh_data_bindings()
    # Reset the timer if it is already started...
    if self.click_buffer_timer.interval != 0:
        self.click_buffer_timer.interval = 0
    # ... then start it up again from zero.
    self.click_buffer_timer.interval = 1

def click_buffer_timer_tick(self, **event_args):
    # This event is triggered whenever the timer component
    # reaches its set interval.
    # Reset and stop our timer.
    self.click_buffer_timer.interval = 0
    with anvil.server.no_loading_indicator:
      anvil.server.call('update_current_user_points', self.item['local_points'])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Server code

@anvil.server.callable
def update_current_user_points(new_amount):
    current_user = anvil.users.get_user()
    app_tables.leaderboard.search(user=current_user)[0]['points'] = new_amount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s really all there is to it! All that was left to do was publish the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing The App
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://anvil.works/docs/deployment-new-ide" rel="noopener noreferrer"&gt;Deployment&lt;/a&gt; is so easy I could do it in my sleep. In fact, I did! And, since you have no way of proving me wrong, you’re just going to have to accept that as a fact. Isn’t this fun?&lt;/p&gt;

&lt;p&gt;All it takes is literally two clicks, and you’ll receive a shareable URL to send your friends to use your app. That way, you can focus on, you know, making the app, rather than on how to deploy it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zv0q65runffzfsv3mnm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zv0q65runffzfsv3mnm.gif" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And voilà! My game was then deployed and all I had to do was set my friends loose to compete for the title of Ultimate Clicker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to learn more?
&lt;/h2&gt;

&lt;p&gt;If you want to dive right in and take a look at the clicker app from behind the scenes, you can clone the app by clicking right &lt;a href="https://anvil.works/build#clone:PPF6KC5YOFADVWXY%3dO4KHABTFR5VUVFKVMQC5DTZD" rel="noopener noreferrer"&gt;here&lt;/a&gt;, which will let you see how it was made in more detail!&lt;/p&gt;

&lt;p&gt;Alternatively, if you want to start on your own project, our online editor is free to use and requires no installation whatsoever. We have some great &lt;a href="https://anvil.works/learn/tutorials" rel="noopener noreferrer"&gt;step-by-step tutorials&lt;/a&gt;, and a bunch of fully-featured example apps like this &lt;a href="https://anvil.works/learn/examples/ticketing-system" rel="noopener noreferrer"&gt;ticketing system app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, if you have questions or for any other reason feel like giving us a shout, you can find us in the &lt;a href="https://dev.to/forum"&gt;&lt;strong&gt;Anvil Community Forum&lt;/strong&gt;&lt;/a&gt;, it's always full of activity.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
