Rendering MPTT structure with open/close possibility in django template - python

I need to render my MPTT model as tree with dropdown (open/close every node that contains children) possibility and buttons that will open/close all the nodes in that tree in 1 click.
I tried to find some ready-to-use examples, but best that I found is this:
<ul class="navbar-nav mr-auto">
{% recursetree thecategories %}
{% if node.level == 0 %}
{% if not node.is_leaf_node %}
<!-- Let op: <li> tag wordt steeds onderaan aangevuld, ander werkt het niet...-->
<li class="dropdown nav-item">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">
<span class="mainBarItem">{{ node.ctg_Title }}<span class="caret"></span> </span></a>
{% else %}
<li>{{ node.ctg_Title }}
{% endif %}
{% else %}
{% if not node.is_leaf_node %}
<li class="dropdown-submenu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">
<span class="nav-label">{{ node.ctg_Title }}<span class="caret"></span></span></a>
{% else %}
<li>{{ node.ctg_Title }}
{% endif %}
{% endif %}
{% if not node.is_leaf_node %}
<ul class="children dropdown-menu">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
with some CSS and JS, but it is not that I need.
Actually I need to render just one tree at a time. I'm passing variable {{ product }} in my template that is just a root node. And for now I have this code from MPTT docs example that just render it as a list:
{% for product,structure in product.get_family|tree_info %}
{% if structure.new_level %}
<ul>
<li>{% else %}</li>
<li>{% endif %}
{% if product.purchased %}
<span style="color: #f5e642">{{ product.code }}</span>
{% else %}
{{ product.code }}
{% endif %}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}
Also tried Nestable2, but it doesn't work for me, and IDK why. It renders as it should with drag and drop possibility but without possibility to open/close parent nodes (buttons are rendered but doesn't work).
I'm weak at front end development (Know just the basics of JS).
I thought maybe I can use some ready-to-use components in Jquery or Vue.js or anything else? Or will it be easier just in vanilla js? I appreciate any help and advices.

If anyone interested in how I did it, here is a simple code:
HTML
<ul id="myUL">
{% recursetree product.get_family %}
<li>
{% if node.is_leaf_node %}
<span class="leaf">{{ node.code }}</span>
{% else %}
<span class="caret parent">{{ node.code }}</span>
<ul class="nested">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
CSS
ul, #myUL {
list-style-type: none;
}
/* Remove margins and padding from the parent ul */
#myUL {
margin: 0;
padding: 0;
}
/* Style the caret/arrow */
.caret {
cursor: pointer;
user-select: none; /* Prevent text selection */
}
/* Create the caret/arrow with a unicode, and style it */
.caret::before {
content: "\25B6";
color: black;
display: inline-block;
margin-right: 6px;
}
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.caret-down::before {
transform: rotate(90deg);
}
/* Hide the nested list */
.nested {
display: none;
}
/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
.active {
display: block;
}
Javascript
'use strict';
var togglers = document.getElementsByClassName("caret");
var i;
for (i = 0; i < togglers.length; i++) {
togglers[i].addEventListener("click", function () {
this.parentElement.querySelector(".nested").classList.toggle("active");
this.classList.toggle("caret-down");
});
}

Related

How to Add icon "eye" in Flask WTForms PasswordField

Looking to add an icon toggle to a password field.
In my forms.py I have:
class LoginForm(FlaskForm):
email = StringField("Email Address", validators=[DataRequired(), Email()])
eye_icon = Markup('<i class="icon-eye" id="togglePassword" style="margin-left: -30px; cursor: pointer;"></i>') # Not currently doing anything
password = PasswordField("Password", validators=[DataRequired()])
And in my login.html
<div class="form-group">
{% if form.email.errors %}
{{ form.email(class_="form-control is-invalid", placeholder="Email") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span> {{ error }} </span>
{% endfor %}
</div>
{% else %}
{{ form.email(class_="form-control ", placeholder="Email") }}
{% endif %}
</div>
<div class="form-group">
{% if form.password.errors %}
{{ form.password(class_="form-control is-invalid", placeholder="Password") }}
<div class="invalid-feedback">
{% for error in form.password.errors %}
<span> {{ error }} </span>
{% endfor %}
</div>
{% else %}
{{ form.password(class_="form-control shadow-none", placeholder="Password") }}
<i class="icon-eye" id="togglePassword" style="margin-left: -30px; cursor: pointer;"></i>
{% endif %}
</div>
And I have my JS that toggles between showing the password. I just don't see how I can get the eye icon to show on the right of the password field like it shows on most login screens
I had to wrap the tag in a span tag, and add a class to my css to get it to work:
{{ form.password(class_="form-control ", placeholder="Password") }}
<span class="p-viewer"><i class="icon-eye" id="togglePassword" style="margin-left: 100px; cursor: pointer;"></i></span>
and css:
.p-viewer {
z-index: 9999;
position: absolute;
top: 30%;
right: 10px;
}
you could remove the styling from the password field, and apply it to a div that surrounds both the password field and the icon.

Does PasswordResetConfirmView.py auto populate uid and token?

The view definitely does not populate on my end but password_reset_confirm.html in the demo template folder seems to do that.
password_reset_confirm_form.html
urls.py
path("dj-rest-auth/password/reset/confirm/<str:uid>/<str:token>/",
# TemplateView.as_view(template_name="password_reset_confirm.html"),
PasswordResetConfirmView.as_view(),
name='resend-email-verification'
),
Edit: maybe this webpage here is not the same page in django-rest-auth demo folder.
In django, it is defined as (in django code):
urls.py
path('reset/<uidb64>/<token>/',views.PasswordResetConfirmView.as_view(),name='password_reset_confirm'),
path('reset/done/',views.PasswordResetCompleteView.as_view(),name='password_reset_complete')
Then, you can customize according to your need and override it by inheriting it in your own views.py file.
Answer credits to GitHub user, riteshbisht.
What I am seeing is UI of browsable API of django rest framework that does not have this functionality for reading url and populating form field unless I tell it to.
For it to do this, I created templates/rest_framework/api.html file and inserted following code inside it:
api.html
{% extends "rest_framework/base.html" %}
{% block style %}
{{ block.super }}
<style>
#btn-link {
border: none;
outline: none;
background: none;
display: block;
padding: 3px 20px;
clear: both;
font-weight: 400;
line-height: 1.42857143;
color: #A30000;
white-space: nowrap;
width: 100%;
text-align: left;
}
#btn-link:hover {
background: #EEEEEE;
color: #C20000;
}
</style>
{% endblock %}
{% block userlinks %}
{% if user.is_authenticated or response.data.access_token %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
{% firstof user.username 'Registered' %}
<b class="caret"></b>
</a>
<ul class="dropdown-menu dropdown-menu-right">
{% url 'rest_user_details' as user_url %}
<li>User</li>
<li>
{% url 'rest_logout' as logout_url %}
<form action="{{ logout_url }}" method="post">
{% csrf_token %}
<button type="submit" id="btn-link">Logout</button>
</form>
</li>
</ul>
</li>
{% else %}
{% url 'rest_login' as login_url %}
<li>Login</li>
{% url 'rest_register' as register_url %}
<li>Register</li>
{% endif %}
{% endblock %}
{% block script %}
{{block.super}}
<script type="text/javascript">
var url_elements = window.location.pathname.split('/');
if (url_elements.length >= 3){
var uid = url_elements[url_elements.length - 3];
if (uid !== undefined){
$('input[name=uid]').val(uid);
}
var token = url_elements[url_elements.length - 2];
if (token !== undefined){
$('input[name=token]').val(token);
}
}
</script>
{% endblock %}

Why can't select one object in django

I'm creating a ecommerce store using django And tried s many things to do this.index page is working pretty well but I want select specific product when I click .ex: when I click a shoe I want to enter shoe detail page with shoe image and all the necessary details.Here is my home page.And also I highly recommend to check my all code because you can't get any idea with only this code.github source code here.thanks dinindu
{% extends 'store/main.html'%}
{% load static %}
{% block content %}
<style>
img:hover{
opacity: 0.5;
}
</style>
<div class="row">
{% for product in products %}
<div class="col-lg-4">
<a href="{% url 'productDetail' Product.name %}"><img
class="thumbnail" src="{{product.imageURL}}"></a>
<div class="box-element product">
<h6><strong>{{product.name}}</strong></h6>
<hr>
<button data-product="{{product.id}}" data-action="add"
class="btn btn-outline-secondary add-btn update-cart">Add to
Cart</button>
<h4 style="display: inline-block; float:
right"><strong>Rs {{product.price}}</strong></h4>
</div>
</div>
{% endfor %}
</div>
{% endblock content %}
you could do something like this, an adapt it to your project:
Views:
def product_list(request):
products = Product.objects.all()
return render(request,'list.html',{'products': products})
def product_detail(request, id):
product = Product.objects.get(id=id)
return render(request,'detail.html',{'product': product,})
urls:
path('products/', views.product_list, name='product_list'),
path('products/<int:id>/', views.product_detail, name='product_detail')
templates
list.html
{% for product in products %}
<div>
<a href="{% url 'product_detail' product.id %}">
<img src="{ product.image.url }}">
</a>
{{ product.name }}
</div>
{% endfor %}
detail.html
<div>
<img src="{{ product.image.url }}">
<h2>{{ product.name }}</h2>
<h3>{{ product.price }}</h3>
<h4>{{ product.digital }}</h4>
</div>

Using boostrap in django template correctly

I have this hierarchical order of models: courses, study programmes, departments and faculties. I have 2 columns in bootstrap. The first column lists all faculties, with their specific departments and the study programmes of each department. The second column lists all courses. I want that when someone clicks on a faculty, to display the specific courses for that faculty in the second column by replacing all courses, same for departments or study programmes. Now, I tried something, but I don't know how to achieve this result. I don't know how to list courses for each faculty, as you can notice, I put faculties.0 as a test.
<script>
$('#btnClick').on('click', function () {
if ($('#1').css('display') != 'none') {
$('#2').show().siblings('div').hide();
} else if ($('#2').css('display') != 'none') {
$('#1').show().siblings('div').hide();
}
});
</script>
<div class="row">
<div class="col-md-3">
<div class="jumbotron">
<h4>Search courses</h4>
<hr>
<br>
<ul>
{% for faculty in faculties %}
<li id="btnClick">{{ faculty.name }}</li>
<ul>
{% for department in departments %}
{% if department.faculty == faculty %}
<li>{{ department.name }}</li>
<ul>
{% for study in studies %}
{% if study.department == department %}
<li>{{ study.name }}</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-9">
<div class="jumbotron">
<div id="1">
<h3>All courses</h3>
<ul>
{% for course in courses %}
<li>
<a id="first" href={{ course.slug }}>{{ course.name }}</a>
</li>
{% endfor %}
</ul>
</div>
<div id="2" style="display:none;">
<h3> {{ faculties.0 }} courses</h3>
<ul>
{% for course in courses %}
<li>
<a id="first" href={{ course.slug }}>{{ course.name }}</a>
<p>chinchin</p>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
This is how it looks like now: https://i.imgur.com/fLq7MH2.png
Ok, so I think part of your problem is that you want a second, hidden div, with Faculty specific courses listed, however your current HTML template is only ever going to give you one hidden div, with a single faculties courses in. You need to have one hidden div per faculty.
NB: I wouldn't do it this way using hidden divs, personally I'd use Bootstrap's tab/pill style.
Anyway, I think the below should give you the sort of result you are looking for. Obviously I can't test it with your models. I've changed the template to use the related objects notation rather than your if == style.
I've also changed the jQuery a bit. Hopefully it's ok, although it will have the effect that the #1 div will only be visible before any links are clicked.
UPDATED: I had missed the {{ }} around the faculty.name in the div id's and I also hadn't wrapped the jQuery script in a $(document).ready() or included the jQuery cdn. It should work as intended now.
UPDATED 2: Changed the id of elements to use the faculty.pk which should be a number and avoid any issues with spaces.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
$('.btnClick').on('click', function() {
var faculty_id = $(this).attr('id');
$('#'+faculty_id+'_tab').show().siblings('div').hide();
})
})
</script>
<div class="row">
<div class="col-md-3">
<div class="jumbotron">
<h4>Search courses</h4>
<hr>
<br>
<ul>
{% for faculty in faculties %}
<li class="btnClick" id="fac_{{ faculty.pk }}">{{ faculty.name }}</li>
<ul>
{% for department in faculty.department_set.all %}
<li>{{ department.name }}</li>
<ul>
{% for study in department.study_set.all %}
<li>{{ study.name }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-9">
<div class="jumbotron">
<div id="1">
<h3>All courses</h3>
<ul>
{% for course in courses %}
<li>
<a class="first" href={{ course.slug }}>{{ course.name }}</a>
</li>
{% endfor %}
</ul>
</div>
{% for faculty in faculties %}
<div id="fac_{{ faculty.pk }}_tab" style="display:none;">
<h3> {{ faculty.name }} courses</h3>
<ul>
{% for department in faculty.department_set.all %}
{% for study in department.study_set.all %}
{% for course in study.study_set.all %}
<li>
<a class="first" href={{ course.slug }}>{{ course.name }}</a>
<p>chinchin</p>
</li>
{% endfor %}
{% endfor %}
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
</div>
</div>

Display different <div> depending on arrays length

I'm on my first JinJa2 project.
I want to display cars. A car can have one or more options.
If a car has one option, show that. If it has more, hide it for the moment.
Here's my code:
//...
{% set products = ['Audi', 'BMW', 'Mercedes', 'Porsche'] %}
{% set options = ['Small', 'Sport', 'Coupe', 'Jeep'] %}
{% for product in products %}
{% include '../car-product-item.html' with context %}
{% endfor %}
{% if options|length > 1 %}
//If a car has more options, hide this options for the moment
<div class="order-more-options" style="display: none; background: green">
{% for product in options %}
{% include '../car-product-item.html' with context %}
{% endfor %}
</div>
{% elif options|length == 1 %}
//If a car has one option, show this option
<div class="order-more-options" style="display: block; background: orange">
{% for product in options %}
{% include '../car-product-item.html' with context %}
{% endfor %}
</div>
{% endif %}
//...
For some reason its not working. The options are always hidden.
What am I doing wrong?
I checked a Tutorial, the Docu and another SO-Question but nothing helped.
For me it works fine, when I skip the
{% include ...
commands using the following code:
{% set products = ['Audi', 'BMW', 'Mercedes', 'Porsche'] %}
{% set options = ['Small', 'Sport', 'Coupe', 'Jeep'] %}
{% if options|length > 1 %}
<div>more than one options</div>
<div class="order-more-options" style="display: none; background: green">
{% for product in options %}
{{product}}
{% endfor %}
</div>
{% elif options|length == 1 %}
<div>exactly one option</div>
<div class="order-more-options" style="display: block; background: orange">
{% for product in options %}
{{product}}
{% endfor %}
</div>
{% endif %}
Do you use the correct path to car-product-item.html? Try to put the file car-product-item.html to the templates folder and change your include-lines to {% include '/car-product-item.html' ...%}.

Categories

Resources