Tips and Tricks#
Printing#
You can see Python print statements as output in the console and get with this info on the Python side of objects.
JavaScript Integration#
ngapp provides seamless integration with JavaScript, allowing you to execute JavaScript code, manipulate the DOM, and access browser APIs directly from Python. There are three main ways to interact with JavaScript:
Direct JavaScript access with `.js`
Deferred execution with `call_js()`
Quasar framework integration with `.quasar`
Event handler creation with `create_event_handler()`
These functions call be called from any component or from the app itself.
Direct JavaScript Access (.js)#
The .js property provides immediate access to the JavaScript runtime environment. This allows you to execute any JavaScript function or access any JavaScript object directly.
Basic Usage:
# Access console
self.js.console.log("Hello from Python!")
# Access DOM
element = self.js.document.getElementById("my-element")
element.style.backgroundColor = "red"
# Access window object
self.js.window.alert("Alert from Python!")
# Create new JavaScript objects
canvas = self.js.document.createElement("canvas")
ctx = canvas.getContext("2d")
DOM Manipulation Examples:
# Create and append elements
div = self.js.document.createElement("div")
div.textContent = "Created from Python"
div.style.color = "blue"
self.js.document.body.appendChild(div)
# Query selectors
elements = self.js.document.querySelectorAll(".my-class")
for element in elements:
element.style.display = "none"
# Event listeners
def handle_click(event):
self.js.console.log("Button clicked!")
button = self.js.document.getElementById("my-button")
button.addEventListener("click", handle_click)
Browser API Access:
# File picker
options = {"multiple": False, "accept": ".json"}
file_picker = self.js.showOpenFilePicker(options)
# Local storage
self.js.localStorage.setItem("key", "value")
value = self.js.localStorage.getItem("key")
Important Notes:
Cannot be used in
__init__
methods (JavaScript environment not ready yet)Only available after the component is mounted
Use
call_js()
for initialization-time JavaScript execution
Deferred JavaScript Execution (call_js)#
The call_js()
method ensures safe JavaScript execution by automatically deferring function calls until the JavaScript environment is ready. This is essential for code that needs to run during component initialization.
Basic Usage:
def my_js_function(js):
js.console.log("This runs when JS is ready")
# Safe to call in __init__ or anytime
self.call_js(my_js_function)
With Parameters:
def setup_element(js, element_id, color):
element = js.document.getElementById(element_id)
if element:
element.style.backgroundColor = color
# Pass additional arguments
self.call_js(setup_element, "my-div", "lightblue")
Complex Initialization Example:
class MyComponent(Component):
def __init__(self):
super().__init__()
# This won't work in __init__ - JS not ready yet
# self.js.console.log("This would fail!")
# This works - deferred until JS is ready
def initialize_js(js):
js.console.log("Component initialized")
# Set up event listeners
element = js.document.querySelector(f"#{self._fullid}")
element.addEventListener("click", self.handle_click)
# Initialize third-party libraries
if hasattr(js.window, "myLibrary"):
js.window.myLibrary.init({
"target": element,
"options": {"theme": "dark"}
})
self.call_js(initialize_js)
Return Values:
Note that call_js()
doesn’t return values directly since execution is deferred. For getting return values, use the direct .js
property after the component is mounted.
Quasar Framework Integration (.quasar)#
The .quasar
property provides access to the Quasar framework’s $q
object, giving you access to all Quasar utilities, plugins, and services.
Notifications:
# Basic notification
self.quasar.notify("Operation completed!")
# Advanced notification with options
self.quasar.notify({
'message': 'File uploaded successfully!',
'color': 'positive',
'icon': 'cloud_upload',
'position': 'top',
'timeout': 3000,
'actions': [
{
'label': 'Dismiss',
'color': 'white',
'handler': lambda: None
}
]
})
# Different notification types
self.quasar.notify({
'type': 'negative',
'message': 'Error occurred!',
'caption': 'Please try again'
})
Dialogs:
# Simple dialog
self.quasar.dialog({
'title': 'Confirm Action',
'message': 'Are you sure you want to delete this item?'
}).onOk(lambda: self.delete_item())
# Prompt dialog
def handle_input(value):
print(f"User entered: {value}")
self.quasar.dialog({
'title': 'Enter Name',
'prompt': {
'model': '',
'type': 'text',
'label': 'Your name'
}
}).onOk(handle_input)
# Custom dialog with HTML
self.quasar.dialog({
'title': 'Custom Content',
'html': True,
'message': '<p>This is <strong>HTML</strong> content</p>'
})
Platform Detection:
# Check platform
if self.quasar.platform["is"].mobile:
print("Running on mobile")
if self.quasar.platform["is"].desktop:
print("Running on desktop")
Dark Mode:
# Toggle dark mode
self.quasar.dark.toggle()
# Set dark mode
self.quasar.dark.set(True) # Enable dark mode
self.quasar.dark.set(False) # Disable dark mode
# Check current mode
if self.quasar.dark.isActive:
print("Dark mode is active")
Screen Information:
# Get screen info
screen = self.quasar.screen
print(f"Width: {screen.width}px")
print(f"Height: {screen.height}px")
# Responsive breakpoints
if screen.lt.md: # Less than medium
print("Small screen")
elif screen.gt.lg: # Greater than large
print("Large screen")
Important Notes:
Cannot be used in
__init__
methodsOnly available after component mounting
Provides access to all Quasar
$q
object functionalitySee Quasar documentation for complete API reference
Common Patterns and Best Practices#
1. Initialization Pattern:
class MyComponent(Component):
def __init__(self):
super().__init__()
# Use call_js for initialization
self.call_js(self._setup_javascript)
def _setup_javascript(self, js):
# JavaScript setup code here
js.console.log("Component ready")
def on_mounted(self):
# Use .js for immediate access after mounting
self.js.console.log("Component mounted")
2. Error Handling:
def safe_js_operation(self):
try:
result = self.js.someRiskyOperation()
return result
except Exception as e:
self.quasar.notify({
'type': 'negative',
'message': f'JavaScript error: {str(e)}'
})
return None
3. Async Operations:
def handle_async_operation(self):
def on_success(result):
self.quasar.notify("Operation successful!")
def on_error(error):
self.quasar.notify({
'type': 'negative',
'message': 'Operation failed'
})
# Use JavaScript promises
promise = self.js.fetch("/api/data")
promise.then(on_success).catch(on_error)
Event Handler Creation (create_event_handler)#
The create_event_handler()
method creates properly wrapped event handlers that can be safely attached to JavaScript events. This is essential for handling DOM events and controlling event behavior.
Basic Usage:
def my_click_handler(event):
print(f"Clicked element: {event}")
# Create the event handler
handler = self.create_event_handler(my_click_handler)
# Attach to DOM element
button = self.js.document.getElementById("my-button")
button.addEventListener("click", handler)
Event Control Parameters:
def handle_form_submit(event):
print("Form submitted")
# Custom validation logic here
handler = self.create_event_handler(
handle_form_submit,
prevent_default=True, # Prevents default action of the event
stop_propagation=True, # Stops the propagation of the event
stop_immediate_propagation=False, # Stop immediate propagation of the event
return_value=None # Value returned by event handler
)
form = self.js.document.querySelector("form")
form.addEventListener("submit", handler)
Common Event Handling Patterns:
class InteractiveComponent(Component):
def __init__(self):
super().__init__()
self.call_js(self._setup_event_handlers)
def _setup_event_handlers(self, js):
js = self.js
# Mouse events
mouse_handler = self.create_event_handler(self.on_mouse_move)
js.document.addEventListener("mousemove", mouse_handler)
# Keyboard events
key_handler = self.create_event_handler(
self.on_key_press,
prevent_default=False # Allow normal key behavior
)
js.document.addEventListener("keydown", key_handler)
# Window events
resize_handler = self.create_event_handler(self.on_window_resize)
js.window.addEventListener("resize", resize_handler)
def on_mouse_move(self, event):
# Access event properties
x, y = event.x, event.y
print(f"Mouse at: {x}, {y}")
def on_key_press(self, event):
# Handle keyboard input
if event.key == "Escape":
self.close_dialog()
elif event.ctrlKey and event.key == "s":
self.save_data()
def on_window_resize(self, event):
# Responsive behavior
width = self.js.window.innerWidth
if width < 768:
self.switch_to_mobile_layout()
These JavaScript integration features make ngapp extremely powerful for creating rich, interactive web applications while maintaining the convenience of Python development.