Reputation: 675
So I have the following dilemma:
I am using Brython and everything is working ok. I have a small piece of code that executes ajax requests for me and I added that in the header to bind everything on the current elements in the page.
from browser import document, ajax
# URL Query String
qs = ''
# URL to work on
url = ''
def post_data(url, qs):
req = ajax.ajax()
# Bind the complete State to the on_post_complete function
req.bind('complete', on_post_complete)
# send a POST request to the url
req.open('POST', url, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
# send data as a dictionary
req.send(qs)
def get_data(url, qs):
req = ajax.ajax()
req.bind('complete', on_get_complete)
# Bind the complete State to the on_get_complete function
req.open('GET', url+'?'+qs, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
req.send()
def on_post_complete(req):
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
else:
document["main_area"].html = "error " + req.text
def on_get_complete(req):
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
else:
document["main_area"].html = "error " + req.text
def account_click(ev):
get_data("/account", qs)
def contact_link_click(ev):
get_data("/contact", qs)
def logo_link_click(ev):
get_data("/main_page", qs)
def products_link_click(ev):
get_data("/products_page", qs)
def register_link_click(ev):
get_data("/register", qs)
document['login_link'].bind('click', account_click)
document['contact_link'].bind('click', contact_link_click)
document['logo_link'].bind('click', logo_link_click)
document['register_link'].bind('click', register_link_click)
document['running_link'].bind('click', products_link_click)
document['fitness_link'].bind('click', products_link_click)
document['tennis_link'].bind('click', products_link_click)
document['football_link'].bind('click', products_link_click)
document['golf_link'].bind('click', products_link_click)
Ok now my bigger problem is the fact that register_link
is not in the page from the beginning. To be more exact register_link
will only be loaded into the DOM after the login_link
link is clicked after which the register link does nothing because the event was unable to be bound on it from the get go.
Now I know that I could easily bypass this just by importing this again in that page but I would want to avoid redundant imports and i'm not really sure exactly how to go about doing this.
EDIT: Or is there a way in brython to wait for the DOM to be loaded completely?
Upvotes: 0
Views: 584
Reputation: 401
As you noticed, writing account_click
like this :
def account_click(ev):
get_data("/account", qs)
document['register_link'].active = True
document['register_link'].bind('click', register_link_click)
doesn't work, because the program doesn't wait for get_data
to complete before executing the next 2 lines.
A solution is to write a specific version of get_data
and on_get_complete
for this case (I have supposed that the "register_link" button is in the page, but initially disabled):
def complete_register(req):
"""Called when the Ajax request after "login_link" is complete."""
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
# enable "register link" button and add binding
document['register_link'].disabled = False
document['register_link'].bind('click', register_link_click)
else:
document["main_area"].html = "error " + req.text
def get_data_and_register(url, qs):
req = ajax.ajax()
req.bind('complete', complete_register)
req.open('GET', url+'?'+qs, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
req.send()
def account_click(ev):
get_data_and_register("/account", qs)
Another option would be to keep the generic functions get_data
and on_get_complete
, and add an optional parameter callback:
def get_data(url, qs, callback=None):
req = ajax.ajax()
req.bind('complete', lambda req:on_get_complete(req, callback))
# Bind the complete State to the on_get_complete function
req.open('GET', url+'?'+qs, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
req.send()
def on_get_complete(req, callback=None):
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
if callback is not None:
callback(req)
else:
document["main_area"].html = "error " + req.text
Upvotes: 1
Reputation: 110146
This is nothing common sense can't work for you - and Brython in this respect does just the same as Javascript: any DOM element you want to change needs to exist before you try to modify/bind it.
For decades the "usual" way to do that in Javascript has been place the bindings in a function and just call it at the bottom of the page, or on the body
tag onload
event, after everything else is loaded. "Modern" Javascript code "solves" this by using jQuery or other framework and its ready()
method.
You have to do the same there - the timer might work, but it is risky. And, of course, elements that just exist after one or more of the other functions are triggered should be dealt with inside the respective functions:
def account_click(ev):
get_data("/account", qs)
document['register_link'].bind('click', register_link_click)
Upvotes: 0