0

I am building a web app using flask. I found that I am retying the same thing over and over with a minor edit into everyone of my HTML pages so I want to make it into a template. How can I make it a dynamic template? Below is the code that I use for my ABOUTUS page which is just one line different from my CONTACT page.

About Us Page header:

 <div id="menu">
<div class="pure-menu">
    <a class="pure-menu-heading" href="#">WebAPP</a>

    <ul class="pure-menu-list">
        <li class="pure-menu-item"><a href="/" class="pure-menu-link">Home</a></li>
        <li class="pure-menu-item menu-item-divided pure-menu-selected"><a href="/aboutus" class="pure-menu-link">About</a></li>
        <li class="pure-menu-item"><a href="/membership" class="pure-menu-link">Membership</a></li>
        <li class="pure-menu-item"><a href="/contact" class="pure-menu-link">Contact</a></li>
        {% if current_user.is_authenticated %}
            <li class="pure-menu-item"><a href="{{ url_for('logout') }}" class="pure-menu-link">Log out</a></li>
        {% else %}
            <li class="pure-menu-item"><a href="/login" class="pure-menu-link">Log in</a></li>
        {% endif %}
    </ul>
</div>

Contact Page header:

 <div id="menu">
    <div class="pure-menu">
        <a class="pure-menu-heading" href="#">WebAPP</a>

        <ul class="pure-menu-list">
            <li class="pure-menu-item"><a href="/" class="pure-menu-link">Home</a></li>
            <li class="pure-menu-item"><a href="/aboutus" class="pure-menu-link">About</a></li>
            <li class="pure-menu-item"><a href="/membership" class="pure-menu-link">Membership</a></li>
            <li class="pure-menu-item menu-item-divided pure-menu-selected"><a href="/contact" class="pure-menu-link">Contact</a></li>
            {% if current_user.is_authenticated %}
                <li class="pure-menu-item"><a href="{{ url_for('logout') }}" class="pure-menu-link">Log out</a></li>
            {% else %}
                <li class="pure-menu-item"><a href="/login" class="pure-menu-link">Log in</a></li>
            {% endif %}
        </ul>
    </div>
</div>

The only change is that I move the menu-item-divided pure-menu-selected line from one line to the other based on what template I am loading. I cannot think of a way to do this dynamically so that I can turn this into a template that I can just extend for every file.

Ben
  • 251
  • 1
  • 8
  • 23
  • Have a look at template inheritance in Jinja [link](http://jinja.pocoo.org/docs/2.10/templates/#template-inheritance) – PGHE Mar 05 '19 at 02:18
  • @PGHE I am familiar with Jinja template inheritance and that is what I am trying to build here. I just do not see a way to build it. I am familiar with base & child templates along with blocks (also named block end tags). If you could be more specific as to what you would suggest as what I should look at that would help. All the ways that I can think to currently write it are quite verbose and don't seem to save any time rather than just copying it into every page. – Ben Mar 05 '19 at 08:33
  • Just typing out loud: parameterize it in the template? Like `class="pure-menu-item {{ line.class }}"` – DinoCoderSaurus Mar 05 '19 at 13:45

1 Answers1

1

You could just use standard jinja template inheritance as mentioned in comment above.

Docs here: Template Inheritance

Method 1:

Import request method in your routes.py file,

Use jinga if condition to check whether page is pointing to current url endpoint.

<li class="pure-menu-item{% if request.path == '/contact'} menu-item-divided pure-menu-selected{% endif %}"><a href="/contact" class="pure-menu-link">Contact</a</li>

Tip: You can use flask dynamic url difination {{ url_for('contact') }} instead of hard coding urls.

Method 2: (recommended)

This is not related to flask jinja but does the work as intended in front-end but using JavaScript with jQuery library.

Add this script at the end of the template before closing body tag.

jQuery version

<script>
let current_path = "{{ request.path }}"
if (current_path === window.location.pathname) {
    $(".pure-menu-item a[href='"+current_path+"']")
    .prop("href", "#").closest('li')
    .addClass("pure-menu-item menu-item-divided pure-menu-selected");
}
</script>

Vanilla JS (plain js)

<script>
    let current_path = "{{ request.path }}"
    let current_nav = document.querySelctor("div.pure-menu-item a[href='"+current_path+"']");
    if (current_path === window.location.pathname) {
        current_nav.setAttribute("href", "#");
        current_nav.closest('li').classList.add("pure-menu-item menu-item-divided pure-menu-selected");
    }
</script>

What it does?

If the current url matches to the url specfied in navigation above, it adds the menu-item-divided pure-menu-selected class to the div and disables the current url routing by replacing the actual url to #.

Clean and elegant.

Why?

If you use JavaScript you don't have to define hundreds of {% if... %} in back-end, those if statements you defined in back-end will be checked in every pages user loads, additionally you just saved on more ifs and elses to check if loaded page is nav link's page and disable routing by change url to #. Wow you just saved millions of cpu cycles. :-)

Debendra
  • 1,132
  • 11
  • 22
  • Can you please elaborate as to why the JavaScript version is more "Clean and elegant" I am not sure I understand what the benefit of using one of the other is. It makes sense that I should use the `if` functions as that will make it better. – Ben Mar 07 '19 at 01:31
  • Because you should apply back-end `if` condition in every URL you defined, of course this is performance issue for multiple URL. When you define condition on front-end, you don't have to worry about every URL and you are ready to go in just one statement. – Debendra Mar 07 '19 at 04:36
  • I cannot get the JavaScript code above to work. Is there an error there? I feel like the issue is with the `window.location.pathname` field. Also maybe it will not work but the point of doing this was I want a template that I can extend with jinga. This would be a base template that all of my pages are built off of because it would contain the menu for the site that all pages would have. Thanks for the help here with this. I am new to JavaScript and could really use the help. – Ben Mar 24 '19 at 19:24
  • Yeah sorry, I removed the javascript variable but didn't notice I was using twice, seems like its okay now, readded. – Debendra Mar 24 '19 at 20:52