TL;DR: Dependency Injection (DI) is a way to share instances of services across your app without passing them through function parameters. FletX provides a simple container where you register services once and retrieve them anywhere using FletX.put() and FletX.find().
# You have to create it onceauth_service=AuthService()# Then pass it to every page and controller that needs itclassHomePage(FletXPage):def__init__(self,auth_service):# Passed as parameterself.auth_service=auth_servicedefbuild(self):returnft.Text("Home Page")classProfilePage(FletXPage):def__init__(self,auth_service):# Passed as parameterself.auth_service=auth_servicedefbuild(self):returnft.Text("Profile Page")# When creating pages, you have to pass it manuallyhome_page=HomePage(auth_service)profile_page=ProfilePage(auth_service)
This gets tedious quickly, especially with many services and pages.
fromfletximportFletX# Register once at app startupFletX.put(AuthService())# Retrieve anywhere you need itclassHomePage(FletXPage):defbuild(self):# Just grab it from the containerauth=FletX.find(AuthService)returnft.Text(f"Welcome {auth.user}")classProfilePage(FletXPage):defbuild(self):# Same service instance, no parameters neededauth=FletX.find(AuthService)returnft.Text(f"Profile for {auth.user}")
Key benefits:
- No parameter passing chains
- Services are created once (singleton pattern)
- Any page or controller can access them
- Easier to test and maintain
fromfletximportFletX,FletXAppfromservices.counter_serviceimportCounterService# Register the service in the DI containerFletX.put(CounterService())# Now run your appapp=FletXApp()app.run()
importfletasftfromfletx.coreimportFletXPagefromfletximportFletXfromservices.counter_serviceimportCounterServiceclassCounterPage(FletXPage):defbuild(self):# Get the service from the DI containercounter_service=FletX.find(CounterService)defon_increment(_):counter_service.increment()# In a real app, you'd trigger a page rebuild here# This is simplified for demonstrationreturnft.Column([ft.Text(f"Count: {counter_service.get_count()}"),ft.ElevatedButton("Increment",on_click=on_increment)])
# services/__init__.pyfromfletximportFletXfrom.auth_serviceimportAuthServicefrom.counter_serviceimportCounterServicefrom.settings_serviceimportSettingsServicedefregister_services():"""Register all app services in the DI container"""FletX.put(AuthService())FletX.put(CounterService())FletX.put(SettingsService())
classOrderService:def__init__(self):# Get dependencies from the containerself.auth=FletX.find(AuthService)self.db=FletX.find(DatabaseService)self.payment=FletX.find(PaymentService)defcreate_order(self,product_id,quantity):user=self.auth.user# Use injected dependencies...self.db.save_order(user,product_id,quantity)
# Register multiple instances with different tagsFletX.put(DatabaseService(host="localhost"),tag="local")FletX.put(DatabaseService(host="production.com"),tag="production")# Retrieve the specific one you needlocal_db=FletX.find(DatabaseService,tag="local")prod_db=FletX.find(DatabaseService,tag="production")
# Register different API clientsFletX.put(ApiClient(base_url="https://api.example.com"),tag="main")FletX.put(ApiClient(base_url="https://backup-api.example.com"),tag="backup")# Use the main APImain_api=FletX.find(ApiClient,tag="main")data=main_api.fetch("/users")# Fall back to backup if main is downifdataisNone:backup_api=FletX.find(ApiClient,tag="backup")data=backup_api.fetch("/users")
# services/auth_service.pyclassAuthService:def__init__(self):self.user=Nonedeflogin(self,username,password):# In a real app, verify credentialsself.user=usernamedeflogout(self):self.user=Nonedefis_logged_in(self):returnself.userisnotNone# services/cart_service.pyclassCartService:def__init__(self):self.items=[]defadd_item(self,product_id,quantity):self.items.append({"id":product_id,"qty":quantity})defget_total_items(self):returnsum(item["qty"]foriteminself.items)defclear(self):self.items=[]# services/__init__.pyfromfletximportFletXfrom.auth_serviceimportAuthServicefrom.cart_serviceimportCartServicedefregister_services():FletX.put(AuthService())FletX.put(CartService())
importfletasftfromfletx.coreimportFletXPagefromfletximportFletXfromservicesimportAuthService,CartServiceclassProductListPage(FletXPage):defbuild(self):auth=FletX.find(AuthService)cart=FletX.find(CartService)defadd_to_cart(product_id):ifauth.is_logged_in():cart.add_item(product_id,1)# Show confirmation...else:# Redirect to login...passreturnft.Column([ft.Text(f"Welcome {auth.user}"ifauth.is_logged_in()else"Guest"),ft.ElevatedButton(f"Add to Cart (Items: {cart.get_total_items()})",on_click=lambda_:add_to_cart(101))])classCartPage(FletXPage):defbuild(self):cart=FletX.find(CartService)returnft.Column([ft.Text(f"Cart Items: {cart.get_total_items()}"),ft.ElevatedButton("Checkout",on_click=lambda_:self.navigate("/checkout"))])
# main.pyfromfletximportFletXAppfromroutesimportsetup_routesfromservicesimportregister_services# Setup services firstregister_services()# Setup routessetup_routes()# Run the appapp=FletXApp()app.run()
# ✅ Good - Logic in serviceclassUserService:defget_user_full_name(self):returnf"{self.first_name} {self.last_name}"classProfilePage(FletXPage):defbuild(self):user_service=FletX.find(UserService)returnft.Text(user_service.get_user_full_name())# ❌ Avoid - Logic in pageclassProfilePage(FletXPage):defbuild(self):user_service=FletX.find(UserService)# Logic here - harder to test and reusefull_name=f"{user_service.first_name} {user_service.last_name}"returnft.Text(full_name)
# ✅ Good - Services for business logicFletX.put(AuthService())FletX.put(DatabaseService())FletX.put(NotificationService())# ❌ Avoid - Don't put everything in DIFletX.put({"theme_color":"blue"})# Use page state insteadFletX.put(current_user_id)# Put it in AuthService