When building apps in FlutterFlow, you'll need to decide how your app should respond to certain events. These events can range from app lifecycle events, like page or widget loading, data changing, user interactions, and more. This is where Actions come in. Actions are in fact, functions. An Action is how you specify how your app should respond to certain events. An app is full of events and triggers, so that's why I decided to dedicate one module to this topic. Imagine you have a card item that opens a card page in an e-commerce app when you tap on it. OnTap is an event the user will trigger on a specific item. Then, we can specify an Action such as opening a card page or navigating to another page. In this example, we only have one event and an Action call responding to the event happening. But that's not always the case. Typically, these Actions may need to happen in different strategies such as conditionally, sequential, or in parallel execution and asynchronous versus synchronous functions. In app development, this is called control flow, which refers to the order in which individual statements, instructions or functions calls are executed or evaluated. Proper control flow ensures your app behaves as expected under various conditions and user interactions. All right, let's go a little bit deeper to understand better. One of the fundamental aspects of control flow is use of conditionals, which allow your app to make decisions and execute different blocks of code based on a specific criteria. Conditional statements are expressions that evaluate either true or false. Depending on the result of these evaluations, different logic sequences are executed. These examples demonstrate multiple conditions. For example: if user is logged in, true, then we're going to show a welcome message. But if not, then we're going to check if user is guest and if his user is a guest, then we're going to show a guest message. Otherwise we're going to prompt the user to a login page. Another logic flow is sequential. Sequential logic flow means that Actions are executed one after other. Each Action waits for the previous one to complete before starting. This approach is useful for tasks that depend on the outcome of the previous Actions. For example, consider submitting a form, waiting for a server response, and then showing a confirmation message. Each step follows the previous one in sequence. On the other hand, parallel logic flow involves multiple Actions being executed at the same time, independent of each other. This method is ideal for tasks that can be done simultaneously and do not depend on each other's outcomes. It can help with performance to run in parallel. For instance, you might want to load data from multiple sources simultaneously to speed up the data fetching process. By running these tasks in parallel, you can improve efficiency and reduce waiting time. Finally, let's talk about asynchronous versus synchronous functions. Asynchronous functions or operations that do not complete immediately and may finish at a later time due to factors like network delays or long computation times. Depending on the use case, these functions can be either blocking or non-blocking. For example, network requests such as fetching data from API or database operations like reading or writing data, or asynchronous operations. But when I say blocking or non-blocking, what do I really mean? Blocking Actions are operations that halt the execution of subsequent Actions until they are fully completed. These Actions typically involve tasks that take time, like network requests or animations. If you want to imagine what a code snippet means for this case, you can think of the "await" keyword, as we spoke about it in module 3. In this case, the app awaits the Actions that fetch function because it takes some time to complete it and provide a result from an API. Then it goes to the next line, "result.products". On the other hand, non-blocking Actions allow the program to continue executing other tasks while waiting for the initial Actions to be completed in the background. In the generated code, when an asynchronous function is made non-blocking, FlutterFlow removes the await keyword. This means the subsequent function will not wait for the asynchronous Action to complete, and will move on to the next task immediately. Fantastic. That was about different logic flow and asynchronous functions. So let's now see what we're going to cover in this module after this overview. First, we're going to go through the Actions and how you can create them in FlutterFlow. Then you will learn about different types of triggers and also how you run Actions differently. Then you will learn how to develop reusable Actions using Action blocks. And finally we will see how Actions are reflected in the generated code. All right. Cannot wait to get started. Let's get into it. Essentially, designing interactivity in FlutterFlow involves two steps: one, listening for interaction or Action triggers. For example, waiting for a button to be clicked. And then responding to an interaction or Actions, for example when the button is clicked - What to do? Action triggers represent a specific event, while Actions are functions executed in response to the triggered event. Depending on the element, you may have different triggers that can occur in different scenarios. For example, when a system event happens, like when a page is loading, when a user is interacting with the app, like when they're clicking or tapping on a button, when a state is changing, like when you have a dropdown menu and you select something from it. But then the question is how can you create an Action on an element? That can be done with the Action Flow Editor, which is a visual node based editor that simplifies the process of creating and managing business logics, Actions, and triggers. Typically, there are four steps that you need to take. First, select an element like a Button. From the property panel, select an Action icon and then open the Action Flow Editor. Then select an Action Trigger to define when to do this Action and when this Action should happen, And then add an Action with your business logic that should be executed. Well, you may say right now, how can you define a logic? Defining logic containing an Action or a set of Actions can involve many things. Maybe you want to update the value of a state variable. This way you can conditionally change widget properties based on their value. You may want to execute some query or API call to fetch data and display in your app. You may want to navigate a different part of your app, like open a new page and show a dialog. When you are defining your logic and if you have more than one action to define, You can add them in three different ways. First, you can add them via Add Conditional Action. This option adds a condition node. It includes an input for a Boolean expression and then two Action branches. The Action in each branch will be executed based on whether the Boolean expression evaluates to true or false. But sometimes you need a single condition. A single condition flow allows you to define a condition by comparing two values. These values can be set manually or derived from variables, and the condition will return either true or false. There are different operators for the comparison, such as greater than, equal to, greater than or, equal to, and so on. Sometimes you must combine conditions and have multiple conditions weight and logic or or logic. Multiple Conditions Flow lets you combine multiple single condition using logical AND/OR operators. when you're using AND, that means both single conditions, or all of the single conditions, should be true. When you are using OR, that means one of the conditions in the flow can be true And it goes to the true branch. It's useful for more complex decision making processes. The next way to define Actions is to Add Loop. Sometimes you might want to trigger a specific Action multiple times. For example, an app might fetch data from a server, and you want to handle network errors by retrying requests several times. Every loop requires a condition, and the Action within the loop will continue to trigger as long as the condition holds true. When the condition becomes false, the loop terminates And the next Actions in the workflow will trigger. Let me give you tip: be careful with loop Actions as they can cause your app to enter an infinite loop if the loop never becomes false. Always ensures that the condition will be met at some point so that the loop can exit. If the intended operation is completed before the condition becomes false, you must add a loop break Action in your workflow to exit the loop. Loop breaks are statements used to exit the loop prematurely before the loop's normal termination condition is met. They are typically used to stop the loop when a certain condition is satisfied, preventing unnecessary iterations and allowing the program to proceed to the next section of Actions. Next is parallel execution. We learned about parallel execution in the overview video. This option lets you add two Action flow branches that will be executed in parallel, allowing multiple Actions to occur simultaneously. Essentially, when you add Actions, they come sequentially after each other. This option help you to make them parallel. And last but not least, before we go to our demo to implement an Action, when you add an Action or select one in the Action Flow editor, you have several options to define. From navigation to state management to animations and custom Actions and so on. Throughout this course, we're going to make a lot of Actions and triggers in different modules. But for now, let's move on to the next video and see how we can implement these Actions in different scenarios in our application. So far in the previous demos, we created a Profile Settings page together. So I already proactively created two more pages: the address list - Let's quickly review how I build it. It's going to have the app bar. I'm going to open the widget tree so that we can explore together. Then I have a container that is going to have a Row and an Icon, and then a Text. And obviously in the property panel I have set, the Container's properties to feel and look like what you're seeing on the screen. Then, I use ListView to generate a list of addresses. But each list of addresses is a Container that is going to have a border radius and a border color. And then, it will contain a Column. Let's explore quickly. This Column is going to have a Row with three items: Text, another Text and a Button that looks like a text button. And I just duplicated the other one, but with a slightly different color. All right, that's my Addresses. What are we going to do right now? We're going to make an Action from profile settings. And when I click on the addresses, on the Icon button, I just want to move this page to the next page. So what we're going to do we're going to select the element. Then I go to the property panel and click on Actions. And on Actions you will see that I have access to Action Flow Editor. So I'm just going to open that. And for these elements, I have multiple trigger types like onTap, double tap or on long press. So I'm just going to select the onTap. Since this is going to be a single navigation I'm just going to click on an Action. So but we're going to do also conditional loop and parallel quickly in this demo. Let's do an Action. You need to define your Action right now. What do you want to do in this case? There's multiple options. So at this point I just going to navigate to a page. And when I open that I will see a list of pages. Just going to select AddressListPage. So I will leave the rest as is. So my Action is finished for this button. Let's do another one. Let's do the Floating Action Button. So here is a button that I want to actually have two Actions. Let's select the Action button, go to property Panel and open the Action Flow editor. And onTap. This time, I want to have a conditional Action. We need to make a condition here. So I'm going to make it a simple permission. Go to the global properties and you will find different things. Let's say if this is where I want to just trigger these so it goes to there. True. So then I'm going to click on add to add another Action here. So you can actually create a chain of Actions. So in this case I want to say "if this is true" then do the Action. In this case, let's say I just want to show a Dialog. I'm just going to search for dialog.. informational... or let's say confirm dialog. A Confirm dialog. It says whether you want to continue doing that or not. So I'm just going to say, "Confirm Invitation". No message. Cancel and confirm. And as you can see, you also have a non-blocking option here. So it doesn't apply here. In this case I'm just going to have a blocking one and then continue. Now let's do the false branch. So if it's not web then let's show another Action. Let's show... Information dialog and say "Sorry. It's not web". You can continue changing this Action by adding more Actions and even have a final Action in each of these cases. Let's say if in each of these cases you want to continue showing another Action, well, let's put it like I want to navigate to HomePage. All right. Now I've created a conditional one. And also we created a single Action. I'm going to go and run my application in Test Mode for testing. Okay. My test mode is up and running, but I cannot actually go from HomePage to ProfilePage. Let's fix that. Here's my home page. I'm going to drag and drop a Button. Will align it in the center. And give you the text. Then I'll open the Action Flow Editor. And on tap, I will add an Action. Go to Profile Settings. All right. That's good. Now go back to Test Mode and I will reload. Let me also close the debug panel to just make it a bit cleaner. There you go. So now I can click on this button and it goes to the profile settings page. And if I click on this button then it goes to the address page. So and as you can see the back is also working because this is part of the default system. But how about "invite"? So we're running actually in Test Mode. So it's kind of like a web application. So if I click on that then it shows me a confirmation modal. If I confirm then it goes back to the home page. That's exactly what we were defining as an Action. Let's go back and do one more thing. So I also created another product release page. This was my design. So let's quickly break down this layout because it will help you to understand how you can build your own layout. I'm going to open the widget tree and I'll go back to the design. We have this app bar and as you can see, I already created that circle image The DropDown, and I left actually this one to do it together just because I wanted to demonstrate this Stack - Wwe never have done that together. So then we have this search, which is this search is a TextField. And if you look at the properties, I kind of define the properties to look like my design. Then I had this Column which has a Row and another Row. And similar to this one, we also have another one with a Row and another Row. And if I wanted to just break it down, this looks like let's say a Column. Then I have this image and a heart on top of it, which is an a Stack. And then I had two Text here, which is two Text in a Column. So then here is entirely a Column starting from stacked and two Text in the Column. So fairly simple right? Let's just quickly see what I've done. Here is my category. And as you can see if I open my widget tree - let me just collapse - You can see it's a Row. And another Row. And the first Row I have two texts. And then in the second Row I have multiple Columns. And each Column is going to have an image and a text. Right. So simple. Breaking down our UI into Columns, Rows, ListViews and other widgets. Then I have the top selling. So it's going to have a Row and another Container here which contains a ListView that is generating different Columns. And these Columns are going to have a Stack and two Text. So here is the Text, Text and a Stack here with Image and Icon. So because we have never done the Stack together, we just want to actually create this part a card together very quickly. I'm going to start with a Container here. And then I will actually select in Stack. And then drag and drop it to my container. Let me see the widget tree. Okay. Looks good. Then in my Stack I have: Button as well as a Text. So let's choose an icon button. Drag and drop to the stack. And I also have a Text that has a background field of primary text, which is it means that I need a Container in my Stack and that Container requires a Text. Okay. Sounds good. Let's open the widget tree. Here is my Stack. So what I'm going to do right now I'm going to change the text now to number one. Then I'll go to Container and just make it A circle. Change the diameter. And of course the field color to Primary. I'll make sure that everything is center aligned, including the child. The Text also is white. So I'm just going to go to the text now. And change the text color to secondary background or primary text. Depends on what you want. So actually I want a white one. So then I'll check the secondary background. All right. That's good. Now I go back to my Icon button very quickly. I will remove the fill color. Instead, I will add a border color of primary. And the size of two. And the radius is going to be 40. Just to make it circular. And as you can see right now it's a stack. So I can just go to my Container. The second child of the Stack. All right. Now I need to move This Container to the top left. So I'm just going to select the container again. And now if I go to that alignment I can actually select the top left. But it goes all the way to the other container is because actually we don't need these container. I'm going to show you a tip here. You can actually right click on this one that you don't need and just select "Remove Widget" and voila. So that parent widget is going to be removed. And now you have a Stack with Icon and Container. So obviously the icon button also needs A proper icon. And its color should match the color of the design. So one more thing - we need to go back to alignment and make sure that the alignment is now correct. And so what we're going to do right now we're going to move the icon a bit to the left. All right. Great. I can play around a little bit to make it nicer. But I guess, my point was to show you how you can use a stack and that's enough. Now I'm going to select the profile page and go to the Actions in the property panel and open the Action Flow editor. So this time, I'm going to click on onTap and select Add Parallel Action. And as you can see you can have multiple Actions in parallel running. So let's say I'm going to have two Actions right now. Let me just delete the other ones. I'm going to have two Actions in this case. So let's add different type of Action here. One tip for you is that you can copy and paste your Action. Let's do this. Let's say when you click on that I just want to do two things. I want to actually navigate to the profile page. And at the same time, in parallel I want to actually select the haptic feedback like a little bit like vibrating in your phone. Now these two Actions are happening together. And once they are done, then I can do a final Action by showing a notification in my SnackBar. But let's see, maybe you want to change your first Action after you navigate. Then you also want to clear or hide any other messages from a SnackBar. All right, that's it. Now I have two Actions in parallel and some Actions even sequentially happening, like Action one and two. Okay. I want to show you one more thing. When you have different elements, you're going to have different triggers. Like for example, if I select the page right now and open the Action Flow Editor, then I'm going to have on page load, phone shake or shortcut press. And these are interesting ones right. So when a page is loading you can for example load the data and set the state and show that. So we're going to actually do that in the upcoming modules. Just wanted to show you what is possible. Let's now go back to our test mode and reload. All right. This time I am in the product list. So if I click on there now if I tap on the profile avatar, you'll see that actually I'll see the message while the haptic is not happening because I don't have a real device. But if you connect the actual real device, you will also feel that. And it also navigates to this page. Beautiful. Let's go back again to the Action Flow editor for our profile avatar. And I want to give you a couple of tips here. First thing first is that you can actually click on the context menu and copy an Action. And if you'd like, when you want to add an Action you can actually paste Actions or set of Actions. So here it is. That's one tip. Simply you can disable an Action if you need. And sometimes you may need to reorder your Action so you can use the arrows to reorder. Let's say if I have another Action here let's say navigate back for example. It's just an example. And then I can say do this first and do this one third. So I can do that. As you can see changing the order. So I'm just going to delete this one. Or you can even actually call it if you want and cut the chain. I'm just going to cut this one for now. Beautiful. Let's do one more thing before we end this session. So I'm going to go back to my profile settings page. Select the icon where we've just added an Action in an Action flow editor. And the tip here is that just like the other elements that you select and you can make add documentation. We talked about documentation in the previous modules. You can actually select an Action and you're going to have the documentation in the editor. You can also write your documentation here. This documentation is going to be reflected in generated code which we're going to explore that in the generated code in this module. Beautiful. That's how you can work with Actions and triggers and make your application interactive. So we're going to use Actions and triggers quite a lot throughout this course for other purposes as well. Like for example, when we are working with APIs or fetching the data from backend and so on and so forth. Stay tuned for more exciting Actions in the upcoming modules. For now, let's move on to the next video and learn about how we can make reusable Action Blocks. We have seen how Actions are created and work. But what if you want to have a set of Actions that needs to be repeated on certain events and on different elements and scenarios? That's actually Action Blocks. An Action block is a set of Actions that perform a specific task and can be reused in different parts of the app. If you find yourself repeatedly performing a particular set of operations in your app, it may be helpful to create an Action Block. This allows you to break down complex Actions into smaller, More manageable units, making them easier to understand and modify in the future. Let me give you an example. In module 6, we discussed the different scopes of our app from the app or project level, to the component level. Action Blocks have different scopes, which determines their availability. App level Action Blocks are usable across the entire app. You can create an app-level Action block from any Page or Component, and it will be accessible for viewing or editing from anywhere in the app. Internally, an App Block Action can only access the state variables available in the scope. For example, App State variables. Page level Action Blocks that are restricted to a Page in which they were created. Page level Action Blocks can access Page State variables and App State variable. Component level Action blocks are restricted to the component in which they were created. Component level Action Block can access Component states variables, Page states variables, and App states variables. In module ten, you will learn a lot about variables, different data types, and more in depth about these scopes. So wait for this module to come. Defining the flow of an Action block is similar to defining Actions. The key difference lies in choosing the scope and defining the input and output values of the Action Block. When you create an Action Block, you have three main configuration. You should set a name that essentially will be reflected in generated code. You need to define what is received as an input to this Action. Or in other words, you need to define your parameters. Let me give you an example here. For example, you can define a Product ID that is going to be passed to this Action And finally, a return value for this Action block. All right, that's it. Let's see one example of putting everything together for creating an Action Block. So in the previous demo for Profile Avatar, we created a set of Actions. Which is going to run in parallel, but imagine now we're going to have this avatar on all pages. What should we do in this case? So this is a type of the reusability of the Actions, where you can go to the property settings and click on Action Blocks. As you can see you have now two scopes for this: app level and page level. Since this Action Block is going to be available in the entire app in all pages, I'm going to select the app level. So let me show you a quick trick here. I'm going to open the Action Flow editor. I'm going to cut the entire chain. And then I'll go back to my Action Block and then create a new Action Block. Let's call it Avatar.. Action. So here, instead of creating all the Actions again I'm just going to paste these Actions. All right. Beautiful. I have everything that I needed. Close this right down. There's a couple of things that you need to know here. First thing that you can define parameters which at this point we're not going to define that. But you will learn in the upcoming modules how you can pass parameters. And also this Action can return a value. At this point I'm not going to enable this, but we will use that in the upcoming modules and you will see it in action. All right. Now my Action Block is created in an app level. So I can go back to the Actions. I'm going to open the Action Flow editor, select onTap. And now if I click on Action you see that there's a new action popping up under App Action Block. And that is avatar Action. So I'm just going to click on that and that's it. So now you have a set of Actions automatically set for you. You don't need to define them again. Now let's say if I go back to another page let's say or release page while I have the same app bar with the same avatar, then I can select my avatar and will open the Action Flow editor and onTap if I click on Action, even though I am now in another page, I still have access to my Avatar Action. Voila! That's it. Let's do one more thing. So in the profile setting page, let's say you want to actually have a similar Action on all of these buttons, but you're not going to leave this Page for these Actions, just going to stay on this Page. So I'm just going to go to Action Block. You'll see my in app level I still see my Action Block, but I'm going to change that to Page Level. If I create an Action right now let's put it like "SettingItem". And I will just define an Action. Let's say haptic just to give some feedback. I will also rename the name of my Action to look nicer. Fantastic. I'm going to close, and this time, if I go to this Action to Action Flow editor, I, I can add a new add Action Block where as you can see I have a page or app level. So I'm going to select the page and you see this SettingItem action is appearing here. And if I select the app Action I will see the avatar. So because I want the page I'm just going to select this. And that looks good. I can now repeat this for all of this which is fantastic. This is a way that you can reuse your Actions logic. And the good thing is that if you go back to the Action Block and go to that say page setting and add another thing here, let's say another Action, for example, let's show snack bar or maybe hide snack bar. So the good thing is that this is going to actually happen in all of those other Actions that you're using the Action Block. So let me just quickly go back to the OrderList and demonstrate the profile avatar. And this time, if I go back to Action Block, you'll see that in App Block I'll see my avatar Action. But if I change to page level, there's nothing here. Fantastic. So that's the purpose of a scoping as well. Let's quickly test see if it's working. All right. That's good. Let's go to the profile setting. Working. It's working. Let's now go to the product list. Click on avatar. Still working. And if I go to the product list and click on avatar. Still working. Lovely. That's what we were looking for. Let's move on to the next video and talk about generated code and see what we have done here, how it will appear in the generated code. All right after adding Actions and playing around with different triggers. Now it's time to locate these Actions in the generated code. So I'm going to give you a tip here, because this course is just about giving you tips and best practices. So we created multiple pages and added different Actions. First thing is that you'll see in my Project Issues. Now I have two warnings. This is because we have two minor problems. They're not blocking But they are nice to fix. For example Disable Action. So we have an Action that is disabled and will not be performed. This is more of an informative. So if I click on that it actually goes directly to my Action Flow Editor with deliberately made this Action disabled. So if you really don't need that, you can actually go ahead and delete it. Another issue we see is about Primary Scroll and multiple Primary Scroll widgets nested with each other. So because if I click on that it actually navigate me to the root column of my page. And if I go to the property panel all the way down, see that this is a scrollable and it's a primary widget. So I'm just going to make either of these disabled. Either this is not a scrollable which is not needed. Or if it's a scrollable then it's going to be not primary. And then everything is going to be fixed. So you may wonder what is primary? When you enable the primary it actually makes the screen as scrollable anyway. So that's why this one is not needed. So it's up to you which one you want to make it enabled. So I'm just going to actually right now I'm just going to make the primary disabled. And you see now in the project issue we have nothing. Another good practice is that because we are now in a very good working condition, I'm just going to make sure I am committing everything so far I have created, let's say, adding Actions. So my branch is going to be part one and I just committed everything. Another good practice would be if I want to create a new version so far, so that we know everything up until here is working. Now I'm going to go back to my FlutterFlow desktop app. So as you can see, everything is synced with my project already. So I have my product list page and also the address list page that I created. Alternatively, you can go to the developer menu, either download the code or use the FlutterFlow CLI using terminal and export everything. All right, back to my VSCode editor. And we're going to explore some of this code. First thing first if I go to the profile page now I'm going to have my new page address list page as well as the setting page. Let's explore this because we added already navigation. I'm going to scroll to the builder right now. And we're going to go and check the Floating Action Button. That's where we added one of our Actions. And as you can see we added onTap or onPressed in Flutter. And that's just a function. And as you can see it's just a function here. Since we already have a conditional Action, you'll see that we have an if/else block here. And that's how we are writing our logic for conditional. So let's actually review another Action that we added to. So if I now scroll down a bit I'll go to the row which I added an Action to one of the icons to go to the address list. Here is my FlutterFlow icon buttons. And as you can see, I have still another trigger here onPressed, which is going to have just a simple function here. And as you can see, the function is just calling a push name to another page which is for navigating through pages. Or we're going to learn about navigation in upcoming modules. Don't worry about that. But we did also one thing for this Action and that was documenting. And as you can see, the documentation that I have written in the FlutterFlow Action editor, it's also appearing here. Here is the line I'm documenting this Action. We did another Action in the product list. So let me just go to the product list and find the profile avatar. The profile avatar was on AppBar and in the leading position. And as you can see right now in the generated code, actually it's wrapped with an Inkwell where you can have the ripple effect and gesture detection where you can have onTap. An interesting thing is happening right now. Each of our Actions are coming as one line here. So the pushNamed, scaffold messenger for hiding the snack bar, and the haptic feedback, they are going to happen at the same time. That's the parallel effect. And as you can see, we're using a future that is going to run each of these in parallel. And once that is resolved because we have the "await", then we're going to show the final SnackBar show. "Thanks for clicking". Let's quickly review that next to our FlutterFlow Action editor. All right I'm going to go back to my app builder. Select the profile open and there you go. Let me just make it a bit. And there you go. Here's my Action. So the navigation, the hiding the snack bar, and the haptic. And then at the end, showing snack bar. And there's one more thing. So we already added Action blocks. So where are those Action blocks? In fact, the we're going to have a new folder and a file called actions.dart. If I open that you will see that my AvatarAction that I added as an app level Action block is appearing here. And of course this is just going to be a function, right. Because Actions are functions and it's a parallel function we just reviewed. But if I now go back to the product list page that I use that parallel Action, you see that in the leading onTap trigger. Now I have the Action block avatarAction. We did also another Action and a page level scope. So let's go to the profile setting page which it. And there you go. And this time you see onPress not only we have the Action we already had, but also there is another Action settingItemAction, which is coming from the model of this page. And if I navigate in, that's going to be the Action that is defined in the model for this page, which is scoped to this page only. Fantastic. And that was about Actions triggers and Action blocks in the generated code. Let's go ahead and see in the next video what we have learned together in this module.