Flask jinja2 update div content without refresh page - javascript

Need achieve some features like [http://webonise.co.uk/][1] when click on contact,resume,resources link will update (location URL&div content) but without refresh the page.
Flask view function
#app.route('/')
def index():
flash('Welcome')
return render_template('index.html')
Under index.html is extends base.html
{% block content %}
{{super()}}
<section class="content">
<i class="mdi-event"></i>Event
<i class="mdi-contact"></i>Contact
<div class="board">
{# dynamic template #}
{# without using {{% include 'event.html' %}} #}
</div>
</section>
{%- endblock %}
How can i dynamic rendar event.html / contact.html content when different link is click and rendar under {# dynamic template #} without refresh the page ?
<!--event.html-->
<ul class="list">
<li>
<h3>123</h3>
<p>abc</p>
</li>
</ul>
What I try
import jinja2 Environment but still no idea how to achieve this
env = Environment(autoescape=True,
loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')))
#app.route('/')
def index():
board = env.get_template('event.html')
flash('Welcome Home Tyler')
return render_template('index.html', board=board)
Is there really need ajax technique get/post method to achieve all this?

You can use Flask-Sijax which helps you add Sijax support to your Flask app. Sijax is a python/jquery library that makes AJAX easy to use on your web applications. Alternatively you could do this:
<script>
$(document).ready( function() {
$('#next').click(function() {
$.ajax("{{ url_for('yourroute') }}").done(function (reply) {
$('#container').html(reply);
});
});
});
</script>
<input type="button" id="next" value="Next" />
<div id="container"></div>

Related

Hide and show elements inside Django HTML template

I have 2 buttons orders, and suppliers., and want to show data in a Django web app when the corresponding button is clicked. To do this my home.html looks like
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
$(".button_order").click(function(){
$(".myorders").show();
$(".mysupplier").hide();
});
$(".button_supplier").click(function(){
$(".myorders").hide();
$(".mysupplier").show();
});
});
</script>
syle.css looks like;
.myorders,
.mysupplier{
font-size: 25px;
display: none;
}
This works perfectly fine until I use normal data like;
<body>
{%block content %}
<button class="button_order" >ORDERS</button>
<button class="button_supplier" >SUPPLIER</button>
<p class="myorders" >
This is my order
</p>
<p class="mysupplier">
my supplier is cool
</p>
</body>
But when I try to use data into <p class="mysupplier"> or <p class="myorders" > from my databases, the hide property no longer works, like below part.
<p class="myorders">
{% for element in orders %}
{% for key,val in element.items %}
<ul><li>{{key}}:{{val}}</li></ul>
{% endfor %}
<hr class="new1">
{% endfor %}
</p>
I should get Order data from database only when ORDER button is clicked, but my server shows all data from before without even clicking the button. How to maintain hide and show the property of my data.
my views.py looks like
from django.shortcuts import render
client = MongoClient("mongodb://localhost:27017/")
db=client.inventory_data
def home(request):
collection_data_1 = db['orders']
orders = list(collection_data_1.find())
collection_data_2= db['suppliers']
suppliers = list(collection_data_2.find())
return render(request,'home.html',{'orders': orders,'suppliers':suppliers})
The loop in template is executed when rendering template. You pass all your data from view to template. if you just want to hide it from display add to your js:
<script>
$(document).ready(function(){
$(".mysupplier").hide();
$(".myorders").hide();
$(".button_order").click(function(){
$(".myorders").show();
$(".mysupplier").hide();
});
$(".button_supplier").click(function(){
$(".myorders").hide();
$(".mysupplier").show();
});
});
</script>
but if you would like to dynamicly fetch current data from db by pressing button i recommend use htmx (htmx.org)

Create a vanilla JavaScript confirm delete modal when deleting a Django object

Most answers for this on Stack Overflow are written using Ajax and or jQuery. For an assignment I need it to be vanilla JS. This is what I have so far. Strangely I have a working delete button with a GET request method. Not a POST method as it normally would be. I'm not sure why and honestly got it working without the confirmation modal with trial and error.
This is what I have so far:
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='vgHome'), # relative path to VideoGames homepage
path('about/', views.about, name='vgAbout'), # relative path to VideoGames about page
path('news/', views.news, name='vgNews'), # realtive path to VideoGames news page
path('gallery', views.gallery, name='vgGallery'), # relative path to VideoGames gallery page
path('library/', views.library, name='vgLibrary'), # relative path to VideoGames user library
path('library/create', views.create_game, name='addGame'), # realative path to game create form
path('library/<int:game_id>/game_info', views.game_info, name='gameInfo'), # realative path to each games info page
path('library/<int:game_id>/update', views.update_game, name='updateGame'), # relative path to update selected game
path('library/<int:id>/delete', views.delete_game, name='deleteGame'), # relative path to delete selected game
]
views.py
from django.shortcuts import render, get_object_or_404, HttpResponseRedirect, redirect
from django.contrib import messages
from .forms import GameForm
from .models import Game
# Displays VideoGames app homepage
def home(request):
return render(request, 'VideoGames/videogames_home.html')
# Displays VideoGames about page
def about(request):
return render(request, 'VideoGames/videogames_about.html')
# Displays VideoGames news page
def news(request):
return render(request, 'VideoGames/videogames_news.html')
# Displays VideoGames gallery page
def gallery(request):
return render(request, 'VideoGames/videogames_news.html')
# Displays VideoGames user library page
def library(request):
games_list = Game.objects.all()
context = {
'games_list': games_list,
}
return render(request, 'VideoGames/videogames_library.html', context)
# Displays each games details page, linked from library
def game_info(request, game_id):
game = get_object_or_404(Game, pk=game_id)
return render(request, 'VideoGames/game_details.html', {'game': game})
def create_game(request):
if request.method == 'POST':
form = GameForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Game successfully added!')
return redirect('vgLibrary')
else:
messages.error(request, 'Please fix fields with errors!')
else:
form = GameForm()
return render(request, 'VideoGames/game_form.html', {'form': form})
def update_game(request, game_id):
game = get_object_or_404(Game, pk=game_id)
form = GameForm(request.POST or None, instance=game)
context = {'form': form}
if form.is_valid():
form.save(commit=False)
form.save()
messages.success(request, 'Game successfully updated!')
return redirect('vgLibrary')
return render(request, 'VideoGames/game_update.html', context)
def delete_game(request, id=None):
game = get_object_or_404(Game, id=id)
if request.method == 'GET':
game.delete()
messages.success(request, 'Game successfully deleted!')
return redirect('vgLibrary')
else:
return render(request, 'VideoGames/game_details.html', {'game': game})
Template where delete button is located (game_details.html)
{% extends 'VideoGames/videogames_base.html' %}
{% load staticfiles %}
{# Page/Tab Title #}
{% block title %}Video Games | Library | {{ game.game_title }}{% endblock %}
{# Using parent stylesheet + adding page specific css file as well #}
{% block stylesheets %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static 'VideoGames/css/vg_details.css' %}">
{% endblock %}
{# Homepage background image #}
{% block pagetop-css %}{% endblock %}
<!-- Showcase text for homepage -->
{% block page-title %}<h1>{{ game.game_title }}</h1>{% endblock %}
{% block page-subtitle %}{%endblock %}
{% block appcontent %}
<h4 class="info-head">Developer</h4>
<ul class="details">
<li>{{ game.game_developer }}</li>
</ul>
<h4 class="info-head">Release Date</h4>
<ul class="details">
<li>{{ game.game_release }}</li>
</ul>
<h4 class="info-head">Your Rating</h4>
<ul class="details">
<li>{{ game.rating }}</li>
</ul>
<h4 class="info-head">Genre</h4>
<ul class="details">
<li>{{ game.game_genre }}</li>
</ul>
<h4 class="info-head">Platform</h4>
<ul class="details">
<li>{{ game.game_platform }}</li>
</ul>
{% endblock %}
{% block button1 %}Update{% endblock %}
{% block button2 %}Delete
{% endblock %}
{% block button3 %}Library{% endblock %}
{% block javascript %}
{{ block.super }}
<script>
function myFunction() {
window.confirm("Do you really want to delete {{ game.game_title }} from your library?")
}
</script>
{% endblock %}
As you can see from the template I am just using a basic confirm function to give some sort of confirmation, but that doesn't even work as if I click cancel it still goes through. My guess is it has something to do with the delete view using a GET method instead of a Post method.
window.confirm returns a Boolean indicating whether the user clicked confirm. This value is false if the user clicked cancel. You need to only open deleteGame if the user confirmed.
function myFunction() {
if (window.confirm("Do you really want to delete {{ game.game_title }} from your library?")) {
window.location.href="{% url 'deleteGame' game.id %}";
}
}

How to pass a modified sortable list from html to another html?

I am writing web application by Flask. I made a sortable list in HTML using jquery-sortable.js. I want to pass the new sequences of the list after making modification from one HTML to another HTML.
I have tried to use GET/POST methods. However, it didn't work. Nothing was passed to another HTML.
home.html
<script>
...
$('#sortedList').val(sorted_list);
...
</script>
<form action="http://localhost:5000/about" method="POST">
{{ form.hidden_tag() }}
<div class="form-group" style="display: none;">
{{ form.sortedList.label(class="form-control-label") }}
{{ form.sortedList(class="form-control form-control-lg") }}
</div>
<div class="form-group">
{{ form.submit(class="btn btn_outline-info") }}
</div>
</form>
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class SortedForm(FlaskForm):
sortedList = StringField('Sorted List', validators=[DataRequired()])
submit = SubmitField('Submit')
main.py
#app.route("/about", methods=['GET', 'POST'])
def about():
form = SortedForm()
if form.validate_on_submit():
flash(f'Sorted list passed {form.sortedList.data}~', 'success')
return render_template('about.html', title='About', form=form)
about.html
{% extends "layout.html" %}
{% block content %}
{{ form.sortedList.data }}
{% endblock content %}

load more feature or endless pagination

I recently learnt I need pagination otherwise page won't load faster.
so I implemented it.
But now that I finished implemented, I realize I have some problem.
My web has a format like this
The above is the top part of the page
and the above is the below part of the page.
all my posts are going into the below part, and because more posts I write more posts will be there I implemented pagination.
the pagination works fine, but when I go to the next page the top part remains there while the below part shows new posts. (I have implemented this without realizing the existence of the top part)
I don't want my users to see the top part every time they click next page.
I think I have two ways to solve this problem.
One is to somehow not show the top part when they click next page.
Or
I use load more button to show more posts instead of going into another page.
Problem is I don't know how to do either one of them..can some one please help me?
def category_detail(request, slug):
obj = NewsCategory.objects.get(slug=slug)
newsInCat = obj.news_set.all() #for the list of news
paginator = Paginator(newsInCat, 25) # Show 25 contacts per page
page = request.GET.get('page')
try:
news_set = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
news_set = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
news_set = paginator.page(paginator.num_pages)
bestInCat = obj.news_set.get_bestInCat()
context = {
"obj":obj,
"news_set":news_set,
"newsInCat":newsInCat,
"bestInCat":bestInCat,
}
return render(request, "news/category_detail.html", context)
<div class="row">
<div>
{% for news in news_set %}
<div class='col-sm-4'>
<div class="content">
<figure class="story-image">
</figure>
<div id="forever "style="margin-bottom:30px;">
<a href='{{news.get_absolute_url }}' style="text-decoration:none; color:#282E5C;"><h4 style="font-size: 18px;
font-weight: 400;">{{news.title}}</h4></a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="pagination">
<span class="step-links">
<!-- {% if news_set.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ news_set.number }} of {{ news_set.paginator.num_pages }}.
</span> -->
{% if news_set.has_next %}
Load More
{% endif %}
</span>
</div>
1) in the html you can show top block if page number equals 1. For example
{% if news_set.number==1%}
{{ top_block}}
{% endif %}
<div class="row">
<div>
{% for news in news_set %}
<div class='col-sm-4'> ....
2) you can render partial html if request is ajax
Here is simple code
views.py
def category_detail(request, slug):
obj = NewsCategory.objects.get(slug=slug)
newsInCat = obj.news_set.all() #for the list of news
paginator = Paginator(newsInCat, 25) # Show 25 contacts per page
page = request.GET.get('page')
try:
news_set = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
news_set = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
news_set = paginator.page(paginator.num_pages)
if request.is_ajax():
context = {
'news_set':news_set
}
return render(request,"news/category_detail_ajax.html",context)
else:
bestInCat = obj.news_set.get_bestInCat()
context = {
"obj":obj,
"news_set":news_set,
"newsInCat":newsInCat,
"bestInCat":bestInCat,
}
return render(request, "news/category_detail.html", context)
category_detail_ajax.html
{% for news in news_set %}
<div class='col-sm-4'>
<div class="content">
<figure class="story-image">
</figure>
<div id="forever "style="margin-bottom:30px;">
<a href='{{news.get_absolute_url }}' style="text-decoration:none; color:#282E5C;"><h4 style="font-size: 18px;
font-weight: 400;">{{news.title}}</h4></a>
</div>
</div>
</div>
{% endfor %}
javascript
jQuery(document).on('click','.load-more',function(e){
e.preventDefault();
jQuery.ajax({
url:jQuery(this).attr('href')
}).done(function(data){
jQuery('.row>div').append(data);
});
});

This is deleting my page, Ajax jQuery

For some reason my ajax success call deletes my page content and replaces the entire page with "success"
{% extends "base.html" %}
{% block title %}Plan{% endblock %}
{% block content %}
<div id="form">
<a>Welcome to planning</a>
{{form.as_p}}
<button id="button">Submit</button>
</div>
<div id="content"> </div>
<script>
$('button#button').click(function() {
$.ajax({
url:'submit',
success: function(data) {
$('div#content').text(data);
},
});
});
</script>
{% endblock %}
Here are my views being called:
def planning(request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('loginregistration.views.login'))
form = planForm()
return render(request, 'plan.html', {'form':form})
def submitplan(request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('loginregistration.views.login'))
if request.is_ajax:
POST = request.POST
msg = "Success"
print request.POST
return HttpResponse(msg)
Can someone also tell me ajax is suppose to recognize my html ids?
$('div#content') is probably your pages id.
Change
<div id="content"> </div>
to
<div id="data"> </div>
and do
$('div#data').text(data);

Categories

Resources