{"assignment":{"_schema_version":2,"course_id":37,"date_created":"2022-06-28T19:00:00+00:00","date_modified":"2025-09-12T14:39:11.292868+00:00","extra_instructor_files":"","extra_starting_files":"","forked_id":null,"forked_version":null,"hidden":false,"id":1032,"instructions":"## Events\n\n-   Normal: Start, Execute, End\n-   Interactive: Start, Events -> Output, Never End!\n\nSo far, most of our programs have been straightforward: the program is started, execution occurs, and then the program ends naturally.\nBut most programs that you use every day are not like that.\nYou start the program, a window appears, and then the program waits for you to do something.\nEach time you click a button, or type some text, or scroll with your mouse, the program reacts in an appropriate way.\nThese input events trigger output, and the program allows you to do these interactions as many as you'd like.\nThe web browser you are using right now is a great example of a program like this.\nYou can keep scrolling and clicking and typing, until you eventually close the program.\nMastering this new model will greatly enhance the kinds of programs that we can build.\nWe will build these programs using Drafter.\nBefore we can talk about interactivity, however, we need to talk about **state**.\n\n## Drafter State\n\n```python drafter-state\nfrom drafter import *\n\n@route\ndef index(state: int) -> Page:\n    content = Div(\"Current number: \", bold(str(state)))\n    return Page(state, content)\n\nstart_server(7)\n```\n\nA central part of any program is the **state**.\nSimply put, the state is the value of all the variables at any given point in time.\nEach statement of a program is executed in the context of the current state.\nAs your program runs, the state can change, and those changes can affect how the program behaves.\nAssignment statements can be used to update the state, for example, using operators and function calls.\n\nState in Drafter is an absolutely essential part of the program.\nRoute functions take the current state as an argument and return a new state as part of the `Page` (along with the content).\nPreviously, we had no state in our Drafter programs, but now we can use state to create more dynamic and interactive applications.\nSo now we have TWO parameters for the `Page` function.\nTo make this more obvious, we have used a temporary variable `content` to hold the content of the page (although that could have been passed in directly).\n\nIn the Drafter program shown here, the state is represented by the `state` parameter in the `index` function. When we call the `start_server` function, we pass in an initial state of `7`. We can use the `state` parameter inside of the body of the `index` function to customize the content of the page, in this case rendering the text \"Current number: 7\".\n\n## Buttons\n\n```python drafter-button\nfrom drafter import *\n\n@route\ndef index(state: int) -> Page:\n    next_state = 1 + state\n    content = Div(\n        \"Current Number: \", bold(str(state)),\n        Button(\"Increase\", \"index\")\n    )\n    return Page(next_state, content)\n\nstart_server(7)\n```\n\nTo manipulate the state in Drafter, you can use the `Button` component to create interactive elements. When the button is clicked, it will call the specified route function with the current state.\n\nDrafter buttons take in the label for the button and the name of a route.\nNotice we said a function _name_, not a function call.\nBy providing the name of the route instead of calling the route function, we delay the execution of that function until the button is clicked.\nWhen the button is clicked, Drafter will call the `index` function with the current state, which creates a new `Page` with the latest state (`8`) displayed and creates a new state that has been incremented by one.\n\nThe result is that every time you click the button, the state is updated and the page is re-rendered with the new state. So when the page first loads, the number `7` is displayed and the state is `8`. Then the number `8` is displayed and the state is `9`, and so on.\n\n## Multiple Routes\n\n```python drafter-multiple-routes\nfrom drafter import *\n\n@route\ndef index(state: int) -> Page:\n    content = Div(\n        \"Current number: \",\n        bold(str(state)),\n        Button(\"Increase\", \"increase_state\"),\n        Button(\"Decrease\", \"decrease_state\"),\n    )\n    return Page(state, content)\n\n@route\ndef increase_state(state: int) -> Page:\n    return index(state + 1)\n\n@route\ndef decrease_state(state: int) -> Page:\n    return index(state - 1)\n\nstart_server(7)\n```\n\nThings might be a little clearer if we look at a more sophisticated application with multiple buttons and multiple routes.\nIn this example, we have buttons to increase and decrease the state, each with their own route function.\nWhen the application loads, it displays the current number and the state stays the same.\nWhen you click a button, Drafter will call the corresponding route function with the current state, allowing you to modify the state in different ways.\nThose route functions in turn reuse the `index` function to generate the page content.\nSo if you click the \"Increase\" button, the state will be incremented by 1, and if you click the \"Decrease\" button, the state will be decremented by 1.\n\n## Conditional Logic in Routes\n\n```python drafter-if-route\nfrom drafter import *\n\n@route\ndef index(state: str) -> Page:\n    content = Div(\n        \"Guess the password\",\n        TextBox(\"guess\"),\n        Button(\"Submit\", \"check_password\")\n    )\n    return Page(state, content)\n\n@route\ndef check_password(state: str, guess: str) -> Page:\n    if state == guess:\n        content = Div(\"Correct! The password is: \", bold(guess))\n    else:\n        content = Div(\"Incorrect!\", Button(\"Try again\", \"index\"))\n    return Page(state, content)\n\nstart_server(\"grapefruit\")\n```\n\nSince routes are just functions, you can use them to encapsulate any logic you need for your application. This means we can use `if` statements, for example to return different page content based on the current state or user input.\nTo do so, we must also learn about another new component: `TextBox`.\nThe `TextBox` component function takes in a unique name for the textbox (which is not shown to the user).\nThat name will be matched to a parameter in a route function, if any buttons are pressed.\n\nIn this example, the `guess` parameter in the `check_password` function will be populated with the value entered in the `TextBox` when the \"Submit\" button is clicked.\nThis allows the `check_password` function to access the user's input and use an `if` statement to check if they have correctly guessed the password (which is stored in `state`).\nDepending on whether the guess is correct or not, the function can return different content to the user.\nThe incorrect guess case is handled by displaying a message and providing a button to restart the guessing process.\n\n## Keeping the Logic Coherent\n\n-   State: Always the same type throughout the application, always representing the same thing, even if its value changes. Every route function takes the current state as its first parameter.\n-   Route Parameters: Changes depending on what the current route needs, based on the previous route's components. Route parameter values are temporary and do not persist between routes, so must be saved to the state if needed.\n\nA confusing aspect of Drafter's routing system is that it can be easy to lose track of the current state and the flow of data between different route functions. You have to think critically about whether you need to update the state in the current route, or in a route linked by a button.\nThe general rule of thumb is that the `index` function does not update the state; instead, you should have buttons that link to other routes which update the state, possibly using parameters.\n\nYou also need to separate out the _state_ from the other parameters being passed to the route functions.\nThe state always represents the same type of thing, even if its specific value changes. The state is meant to be permanently available through the application.\nThe parameters, on the other hand, are completely dependent on what the user is currently interacting with. They can change from one route to another, and are often used to capture user input or other temporary data.\nData that gets captured from the user might update the current state, so it's important to keep track of both the state and the parameters as the user interacts with the application.\n\n## Summary\n\n-   State management is crucial in Drafter applications, as it allows for consistent and predictable behavior across different routes.\n-   Route functions can encapsulate complex logic, including conditional statements and user input handling.\n-   Understanding the distinction between state and route parameters is key to effectively managing data flow in your application.\n","ip_ranges":"","name":"3B3) Events Reading","on_change":"","on_eval":"","on_run":"","owner_id":1,"owner_id__email":"acbart@udel.edu","points":1,"public":true,"reviewed":false,"sample_submissions":[],"settings":"{\n  \"small_layout\": true,\n  \"disable_timeout\": true,\n  \"header\": \"Events\"\n}","starting_code":"","subordinate":false,"tags":[],"type":"reading","url":"bakery_if_events_read","version":15},"ip":"216.73.216.157","submission":{"_schema_version":3,"assignment_id":1032,"assignment_version":15,"attempts":0,"code":"","correct":false,"course_id":37,"date_created":"2026-05-20T14:01:45.335385+00:00","date_due":"","date_graded":"","date_locked":"","date_modified":"2026-05-20T14:01:45.335385+00:00","date_started":"","date_submitted":"","endpoint":"","extra_files":"","feedback":"","grading_status":"NotReady","id":2036910,"score":0.0,"submission_status":"Started","time_limit":"","url":"submission_url-10c5560d-ddd1-43c4-bf94-6a5d7fe00510","user_id":2044668,"user_id__email":"","version":0},"success":true}
