web-dev-qa-db-fra.com

Django - Navigation en surbrillance basée sur la page actuelle?

Je construis une webapp qui a plusieurs sections principales. Chaque section comporte plusieurs sous-sections. J'ai un fichier main_nav.html qui contient le nav pour la section principale. Ceci est ajouté au fichier HTML basé avec la commande {% include ... %} dans le modèle base.html. De plus, j'ai plusieurs fichiers de navigation de sous-section, chacun étant ajouté à une page donnée avec la même commande {% include ... %}

Toutes les barres de navigation sont très simples, juste du texte avec des balises <a href...>

Je veux mettre en évidence le lien pour la section principale actuelle et la sous-section actuelle. Comme cette application Web est plutôt grosse, j'espérais pouvoir le faire sans ajouter d'informations spécifiques à une page. De plus, je veux que cela «fonctionne» à mesure que la webapp s'étend pour inclure plus de sections et de sous-sections. Par exemple, cela pourrait-il être fait en regardant l'URL réelle utilisée? J'espérais mettre cela dans les fichiers de navigation eux-mêmes et ne pas avoir à charger de variable ou quoi que ce soit dans chaque vue Django.

Ainsi, par exemple, le nav ressemble à ceci:

(main ->)            [Systems][Invoices][Work Orders][Admin]
(system sub-nav ->)  [Owner][Billing][Contacts]

Donc, si je suis dans la section Billing de Systems, je veux que le lien Systems en gras et le lien Billing en gras (ou un autre surlignage simple)

Ou:

(main ->)                 [Systems][Invoices][Work Orders][Admin]
(Work-Orders sub-nav ->)  [Create New][Outstanding]

Si je suis dans la section Outstanding de Work Orders, le lien Work Orders et le lien Outstanding doivent être mis en surbrillance. 

Des idées?

37
Garfonzo

En supposant que vous utilisiez render_to_response avec RequestContext ou que vous utilisiez la méthode render ou les vues basées sur les classes de Django 1.3, vous aurez l'objet requête disponible dans votre modèle. À partir de là, il suffit simplement d’accéder au chemin actuel et de le comparer aux valeurs attendues:

<a href="/some/path/to/be/highlighted/"{% if request.path == '/some/path/to/be/highlighted/' %} class="active"{% endif %}>Some Link</a>

Dans Django 1.3, j'aime économiser la redondance et utiliser l'opérateur as pour la recherche d'URL:

{% url 'some_urlpattern_name' as url %}
<a href="{{ url }}"{% if request.path == url %} class="active"{% endif %}>Some Link</a>

Répétez autant que nécessaire pour chaque lien.

57
Chris Pratt

En développant la réponse acceptée par Chris, vous pouvez utiliser le fait que le langage de modèle Django prend en charge in pour la correspondance partielle. Donc, par exemple, si vous avez des URL comme

/people/directory
/people/profiles/joe
/people/profiles/edit

et vous voulez que l'élément de navigation principal "Personnes" soit mis en évidence pour tous ces cas, utilisez quelque chose comme:

{% if "/people/" in request.path %}class="active"{% endif %}
8
shacker

Je pensais que je mettrais mon approche à la disposition des autres pour qu'ils envisagent de le trouver dans Google.

Dans mes modèles, j'ai quelque chose comme ça:

{% block pagename %}homepage{% endblock %}

Ensuite, dans mon modèle principal, quelque chose comme ceci (afin que le nom de la page du modèle héritant soit disponible pour la page rendue):

<span id="_pageName" style="display:none">{% block pagename %}{% endblock %}</span>

Mes liens ressemblent à ceci:

<li data-link-name="homepage"><a href="{% url "pages:home" %}">Home</a></li>

Tout ce dont vous avez besoin est d’un peu de javascript pour appliquer votre classe CSS au bon lien lors du chargement de la page. Le mien ressemble à ceci:

$(function() {
    var pageName = document.getElementById('_pageName');
    if (pageName != null) { pageName = pageName.innerHTML; }
    else { pageName = ''; }
    if (pageName.length > 0) {
        $("li[data-link-name='" + pageName + "']").addClass('active');
    }
});

Très simple, vous permet de contrôler le lien à mettre en surbrillance en ajoutant un petit bloc à vos modèles.

6
fabspro

Dans une autre question similaire, j'ai vu jpwatts ', 110j ' s, nivhab 's & - réponses de Marcus Whybrow , mais ils ont tous semble manquer de quelque chose: quid du chemin racine? Pourquoi est-il toujours actif?

Donc, j'ai fait un autre moyen, plus facile, qui permet au "contrôleur" de décider par lui-même et je pense que cela résout la plupart des gros problèmes.

Voici mon tag personnalisé:

## myapp_tags.py

@register.simple_tag
def nav_css_class(page_class):
    if not page_class:
        return ""
    else:
        return page_class

Ensuite, le "contrôleur" déclare les classes CSS nécessaires (en fait, le plus important est de déclarer sa présence au modèle)

## views.py

def ping(request):
    context={}
    context["nav_ping"] = "active"
    return render(request, 'myapp/ping.html',context)

Et enfin, je le rends dans ma barre de navigation:

<!-- sidebar.html -->

{% load myapp_tags %}
...

<a class="{% nav_css_class nav_home %}" href="{% url 'index' %}">
    Accueil
</a>
<a class="{% nav_css_class nav_candidats %}" href="{% url 'candidats' %}">
    Candidats
</a>
<a class="{% nav_css_class nav_ping %}" href="{% url 'ping' %}">
    Ping
</a>
<a class="{% nav_css_class nav_stat %}" href="{% url 'statistiques' %}">
    Statistiques
</a>
...

Ainsi, chaque page a sa propre valeur nav_css_class à définir et, si elle est définie, le modèle est rendu actif: aucun besoin de request dans le contexte du modèle, aucune mise en page d'URL et plus de problèmes liés aux pages multi-URL ou aux pages racine.

3
DestyNova

En développant la réponse de fabspro, voici une façon de procéder basée sur les URL de pages et avec Vanilla js.

<div id="navbar">
    <ul>
        <li data-link-name="home">
            <a href="{% url 'home' %}"><span>Home</span></a>
        </li>
        <li data-link-name="parent">
            <a href="{% url 'myapp:index' %}"><span>Parent</span></a>
        </li>
        <li data-link-name="child1">
            <a href="/myapp/child1/grandchild1"><span>Child 1</span></a>
        </li>
    </ul>
</div>

<script>
    var path = location.pathname;
    if (path == "/") {
        pageName = "home";
    } else if (path.startsWith("/myapp/child1")){
        pageName = "child1";
    } else if (path.startsWith("/myapp")) {
        pageName = "parent";
    }

    document.querySelector("li[data-link-name='" + pageName + "']").classList += "active";
</script>

Il y a beaucoup de flexibilité ici. Par exemple, le lien Parent ci-dessus serait mis en surbrillance pour toutes les URL qu'il contient, à l'exception de /child1. Le lien Child 1 amènerait l'utilisateur à la page /grandchild1, mais le lien serait actif pour tous les grandchildren dans child1. N'importe quel type de logique personnalisée pourrait être écrit vraiment.

0
Shashwat Black