2017-10-10 1 views
0

J'ai donc le dilemme suivant:Brython lier un événement click à un identifiant qui est pas encore dans la page

J'utilise Brython et tout fonctionne bien. J'ai un petit morceau de code qui exécute des demandes d'ajax pour moi et j'ai ajouté cela dans l'en-tête pour lier tout sur les éléments courants dans la 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 maintenant mon plus grand problème est le fait que register_link est pas dans la page du début. Pour être plus précis, register_link ne sera chargé dans le DOM qu'après le clic sur le lien login_link, après quoi le lien de registre ne fait rien car l'événement n'a pas pu être lié dessus dès le départ. Maintenant je sais que je pourrais facilement contourner ceci juste en l'important encore dans cette page mais je voudrais éviter des importations redondantes et je ne suis pas vraiment sûr exactement comment faire ceci.

EDIT: Ou existe-t-il un moyen en brython d'attendre le chargement complet du DOM?

+0

J'ai trouvé une méthode utilisant la minuterie de Brython bu Je voudrais quand même savoir s'il y a une meilleure façon de faire cela – Nick

Répondre

1

Comme vous l'avez remarqué, écrit account_click comme ceci:

def account_click(ev): 
    get_data("/account", qs) 
    document['register_link'].active = True 
    document['register_link'].bind('click', register_link_click) 

ne fonctionne pas, car le programme n'attend pas get_data pour terminer avant d'exécuter les 2 lignes suivantes.

Une solution est d'écrire une version spécifique de get_data et on_get_complete pour ce cas (j'ai supposé que le bouton « register_link » est dans la page, mais initialement désactivé):

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) 

Une autre option serait pour maintenir les fonctions génériques get_data et on_get_complete, et ajouter un paramètre optionnel rappel:

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 
+0

ce fut une excellente idée, ne pense pas à cela et ça fonctionne parfaitement, merci – Nick

0

Cela n'a aucun sens commun ne peut pas fonctionner pour vous - et Brython à cet égard fait exactement la même chose que Javascript: tout élément DOM que vous voulez changer doit exister avant d'essayer de le modifier/lier.

Pendant des décennies, la « habituelle » façon de le faire en Javascript a été placer les liaisons en fonction et il suffit d'appeler au bas de la page ou sur l'événement tag bodyonload, après tout est chargé d'autre. Le code Javascript "moderne" "résout" ceci en utilisant jQuery ou un autre framework et sa méthode ready().

Vous devez faire la même chose - le minuteur peut fonctionner, mais c'est risqué. Et, bien sûr, des éléments qui existent juste après une ou plusieurs des autres fonctions sont déclenchées doivent être traitées à l'intérieur des fonctions respectives:

def account_click(ev): 
    get_data("/account", qs) 
    document['register_link'].bind('click', register_link_click) 
+0

Je l'ai fait aussi bien mais il essayera toujours de se lier à un ID qui "PEUT" pas encore été chargé au moment de la liaison qui serait encore me forcer à importer à nouveau mon fichier qui est inutile – Nick