How can I replicate **bold** in my django template? - javascript

I am trying to replicate how stack overflow allows the user to type text and produces it below at the same time. The code below in the Django Template works for this.
{% block head %}
<script>
function LiveTextUpdate() {
var x = document.getElementById("myInput").value;
document.getElementById("test").innerHTML = x;
}
</script>
{% endblock %}
{% block body %}
<div class = typing_container>
<div class = note_text>
{{ note_form.note }}
</div>
</div>
<div class = output_container>
<div class = output_note_text>
<p id="test" ></p>
</div>
</div>
The following is in the forms.py file:
class NoteForm(ModelForm):
class Meta:
model = NoteModel
fields = [
'note'
]
widgets = {
'note' : Textarea(attrs={'placeholder' : 'Start a new note', 'class' : 'updated_task_commentary', 'id' : 'myInput', 'oninput' : 'LiveTextUpdate()' }),
}
How can I replicate the ability to bold text when the text is surrounded by "**" please?

Related

infinite scroll working but not populating all data because of javascript call

In my web site I want to show the user ratings - for that I used the infinite scroll but I am facing one problem.
When it first loads the data before calling the <a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a> it is showing the star with the count of vote,but when after calling the <a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a> it is not showing the star.
my views.py
#login_required
def ratings_user(request,pk):
ratings = VoteUser.objects.filter(the_user_id=pk).order_by('-pk')
paginator = Paginator(ratings, 1)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
return render(request,request.session['is_mobile']+'profile/ratings.html',{'ratings':posts})
html
{% extends 'mobile/profile/base.html' %}
{% block title %}
Ratings
{% endblock %}
{% block leftcontent %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet">
{% endblock %}
{% block middlecontent %}
<div class="infinite-container">
{% for i in ratings %}
<div class="infinite-item">
<div class="w3-container w3-card w3-white w3-round w3-margin">
<img src="{{ i.the_user.profile.avatar.url }}" alt="Avatar" class="w3-left w3-circle w3-margin-right" style="width:40px;height:40px;border-radius:50%;">
{% with user=i.the_user.profile %}{{ user.prenom|title|truncatewords:2 }} {{ user.nom|title|truncatewords:1 }}{% endwith %}
<br>
<span class="stars" data-rating="{{ i.vote.vote }}" data-num-stars="5" ></span>
<hr class="w3-clear">
<p>
{{ i.commentaire|linebreaksbr }}
</p>
<span class="glyphicon glyphicon-user"></span> {% with user=i.the_sender.profile %}{{ user.prenom|title|truncatewords:2 }} {{ user.nom|title|truncatewords:1 }}{% endwith %}
</div>
</div>
{% endfor %}
</div>
{% if ratings.has_next %}
<a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a>
{% endif %}
{% endblock %}
{% block rightcontent %}
{% endblock %}
{% block js %}
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0]
});
</script>
<script>
//ES5
$.fn.stars = function() {
return $(this).each(function() {
var rating = $(this).data("rating");
var fullStar = new Array(Math.floor(rating + 1)).join('<i class="fas fa-star"></i>');
var halfStar = ((rating%1) !== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
var noStar = new Array(Math.floor($(this).data("numStars") + 1 - rating)).join('<i class="far fa-star"></i>');
$(this).html(fullStar + halfStar + noStar);
});
}
//ES6
$.fn.stars = function() {
return $(this).each(function() {
const rating = $(this).data("rating");
const numStars = $(this).data("numStars");
const fullStar = '<i class="fas fa-star"></i>'.repeat(Math.floor(rating));
const halfStar = (rating%1!== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
const noStar = '<i class="far fa-star"></i>'.repeat(Math.floor(numStars-rating));
$(this).html(`${fullStar}${halfStar}${noStar}`);
});
}
</script>
<script>
$(function(){
$('.stars').stars();
});
</script>
{% endblock %}
I have tried to put the <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet"> inside the class="infinite-item" but it does not help.what might be the reason for that ? Thanks.
Since yesterday I am on this question I tried everything.
This is another user that has tried to help me here https://stackoverflow.com/a/69930878/15042684 but I did not really understand could you please help me to understand it with some code.
this is his answer:
It doesn't look like .stars() will look for new elements being added to the DOM. You should look for a callback function configuration option within Waypoint.Infinite that you can call .stars() on the new elements.
Assuming you are using waypoint's Infinite Scroll, you can use the onAfterPageLoad callback
onAfterPageLoad
Default: $.noop.
Parameters: $items.
This is a callback that will fire at the end of the request cycle, after new items have been appended to the container. It is passed one parameter, which is a jQuery object of all the items that were appended during the page load.
Note that despite using the jquery convention of $name indicates a jquery object and stating is a jquery object, in this case, trial and error shows that $items are the DOM elements, not a jquery object.
No example provided in the docs, so it will probably look something like:
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
onAfterPageLoad: function(items) {
$(items).find(".stars").stars();
}
});
</script>

Javascript adds another div instead of overwriting

I am trying to change the chart content with the following script:
function switchType() {
var e = document.getElementById("typeSelect");
var selected_value = e.options[e.selectedIndex].value;
console.log(selected_value)
anychart.onDocumentReady(function () {
var ents = {{ entities_dict|safe }}
var dropdown = document.getElementById("typeSelect");
var val = dropdown.value;
/*
var data = [
{value: 'GeopoliticalEntity',
children: [
{% for i in entities_dict.get('GeopoliticalEntity') %}
{value: "{{ i }}"},
{% endfor %}
]}
];
*/
var data = [
];
data.push({value: val,
children: [
{value: "country"},
{value: "europe"},
{value: "German"},
]})
//let result = data.map(a => a.children);
// create a chart and set the data
var chart = anychart.wordtree(data, "as-tree");
// set the chart title
chart.title("Word Tree: Data (Tree)");
// set the container id
chart.container("word_tree");
// initiate drawing the chart
chart.draw();
});
}
This is my HTML
<div class="container">
<div class="jumbotron">
{% for k in survey %}
<h2 class="display-4">Keyword Analysis</h2>
<h2 class="display-5">Most frequent keywords</h2>
<div id="word_cloud" style="width: 1000px; height: 500px; margin-bottom:5px;"></div><br>
<h2 class="display-5">Keyword frequency and their relevance score</h2>
<div id="bubble_chart" style="width: 1000px; height: 500px;"></div><br>
<h2 class="display-5">Entities found in responses</h2>
<select id="typeSelect" onchange="switchType()">
{% for key in entities_dict.keys() %}
{% if loop.first %}
<option selected="selected" value="{{ key }}">{{ key }}</option>
{% else %}
<option selected="selected" value="{{ key }}">{{ key }}</option>
{% endif %}
{% endfor %}
</select>
<div id="word_tree" style="width: 1000px; height: 500px;"></div>
{% endfor %}
</div>
</div>
The result is that it creates the chart, then creates another one below, and another one on each select change.
Is there any way to overwrite the requested div instead of appending another one to the HTML page?
This piece of code I found on this thread solved it for me: How to overwrite html element from javascript?
if (element) {
// Get its parent
parent = element.parentNode;
// Create the new element
newElement = document.createElement('div');
// Set its ID and content
newElement.id = "word_tree";
// Insert the new one in front of the old one (this temporarily
// creates an invalid DOM tree [two elements with the same ID],
// but that's harmless because we're about to fix that).
parent.insertBefore(newElement, element);
// Remove the original
parent.removeChild(element);
}

Adding HTML <a> href Attribute to Javascript is not working

I am trying to implement a Live Search using Javascript for my Django Project, I search by words is working but I am only capable of getting Titles only as a result. I am trying to add the Href so that It can direct the title to the url.
Here is what I have tried:
class Item(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(blank=False, upload_to=upload_design_to)
price = models.DecimalField(decimal_places=2, max_digits=100)
discount_price = models.DecimalField(decimal_places=2, max_digits=100, blank=True, null=True)
timestamp = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse("store:product-detail", kwargs={'slug': self.slug})
Here is the views.py
class ItemListView(ListView):
model = Item
paginate_by = 12
template_name = "store/product_list.html"
ordering = ['-timestamp']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["qs_json"] = json.dumps(list(Item.objects.values()),cls=DjangoJSONEncoder)
return context
Here is the template.html
<input id="search_here" class="mb-2 form-control" placeholder="Type to search...">
<!--Card-->
<div id="box" class='row card-group'>
{% for item in object_list %}
<div class="col-4 mb-3">
<div class="card h-100">
<a href="{{item.get_absolute_url}}">
<embed src="{{ item.image.url }}" class="card-img-top" alt="..."/>
</a>
<div class="card-body">
<h5 class="card-title">{{ item.title }}</h5>
<p class="card-text">
{% if item.description %}
{{ item.description }}
{% endif %}
</p>
</div>
<div class="card-footer">
<small class="text-muted">{{ item.timestamp }}</small>
</div>
</div>
</div>
{% endfor %}
</div>
<!--Card-->
Here is the JS
<script>
const data = '{{qs_json}}'
const rdata = JSON.parse(data.replace(/"/g, '"'))
console.log(rdata)
const input = document.getElementById('search_here')
console.log(input)
let filteredArr = []
input.addEventListener('keyup', (e)=>{
box.innerHTML = ""
filteredArr = rdata.filter(store=> store['title'].includes(e.target.value))
console.log(filteredArr)
var url = "{{item.get_absolute_url}}";
if (filteredArr.length > 0){
filteredArr.map(store=>{
box.innerHTML += `<br>${store['title']}<br>`
})
} else {
box.innerHTML = "<b>No results found...</b>"
}
})
</script>
I am currently reciving an error:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/url
My question:
How to add a link to direct to {{item.get_absolute_url}} using JS
The current code:
box.innerHTML += `<br>${store['title']}<br>`
is linking to the string literal "url".
Since var url contains the URL you want to link to, this change will create the <a> link with the href set to the value of url:
box.innerHTML += `<br>${store['title']}<br>`

Javascript inside Jinja "for" loop

I'm coding an app in Python Flask and I'm building interactive Like buttons with Javascript.
Here's my route:
#app.route('/jquery')
def jquery():
posts = Post.query.all()
return render_template('jquery.html', posts=posts)
And in the jquery.html template I have:
{% for p in posts %}
{% if p.upvotes %}
{% set pupvotes = p.upvotes %}
{% else %}
{% set pupvotes = 0 %}
{% endif %}
<p>{{ p.author.username }} says: <b>{{ p.body }}</b> <button id="
{{ p.id }}" onclick="document.getElementById('{{ p.id }}').innerHTML = {{
pupvotes }} +1 + ' Likes'">{{ pupvotes }} Likes</button></p>
{% endfor %}
Everything actually works this way, but I would like to save the results of +1 likes clicks and transfer them to a Python variable so that I can add it to the database and the updated Like numbers show up on the page after refresh.
I tried to use JavaScript function this way:
<script>
function myF1() {
document.getElementById('{{ p.id }}').innerHTML = {{ pupvotes }} +1 + '
Likes';
}
</script>
and:
onclick="myF1()"
But then only the last Like on the page gets updated with click, no matter which Like button I click.
OK, I've made it work:
Here's our Flask route:
#app.route('/ulk')
def ulk():
ppp = request.args.get('p', 0, type=int)
lpost = Post.query.filter_by(id=ppp).first()
lpost.upvotes += 1
db.session.commit()
return jsonify(result=ppp)
And here's our HTML page with some jQuery:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<script type=text/javascript>
$(function() {
$('a#like').bind('click', function() {
$.getJSON('/ulk', {
p: pid
}, function(data) {
$("#result2").text(data.result);
});
return false;
});
});
</script>
<br/><br/>
{% for p in posts %}
{% if p.upvotes %}
{% set pupvotes = p.upvotes %}
{% else %}
{% set pupvotes = 0 %}
{% endif %}
<p>{{ p.author.username }} says: <b>{{ p.body }}</b>
<a href="#" id=like>
<button id="{{ p.id }}" onclick="pid={{ p.id }};pvts = {{ pupvotes }} +1;myF1();">{{ pupvotes }} Likes</button>
</a>
</p>
<script type=text/javascript>
function myF1() {
$( "#" + pid ).text(pvts + ' Likes');
$('#' + pid).on('click', function() {
$(this).prop('disabled', true);
});
}
</script>
{%endfor%}
<br/>
<span id=result2>...</span>
</body>
</html>
You are close, however, as #MartijnPieters pointed out, you still need to communicate with the backend to update the number of likes for the post. To do so, slightly change your HTML to include a button to update the likes with a class and id. The id will be the same as the post id, and the class will be generic. Then, utilize jquery with ajax after creating a script.
First, in the Python backend, create a route to handle the updating of the likes for a post:
#app.route('/update_like')
def update_likes():
_id = int(flask.request.args.get('post_id'))
#Do something to update the database
return flask.jsonify({'success':'True'})
I suggest returning a jsonified response so that you can handle errors that may occur, such as a user liking a post twice. If you discover that that is the case, then you could return flask.jsonify({'success':'False'}) and handle that accordingly in the frontend.
Then, in the HTML:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<div class='post_wrapper'>
{%for p in posts%}
<div id='post_{{post.id}}'>
<p>{{p.author.username}} says:</p>
<p>{{p.body}}</p>
{%if p.upvotes%}
<button class='upvote' id='upvote_{{p.id}}'>Like <span id='upvotes_{{p.id}}'>{{p.upvotes}}</span></p>
{%else%}
<button class='upvote' id='upvote_{{p.id}}'>Like <span id='upvotes_{{p.id}}'>0</span></p>
{%endif%}
</div>
{%endfor%}
</div>
<script>
$(document).ready(function(){
$('.post_wrapper').on('click', '.upvote', function(){
var post_id = this.id.match('\\d+');
$.ajax({
url: "/update_like",
type: "get",
data: {post_id: post_id},
success: function(response) {
if (response.success === 'True'){
var like_val = parseInt($('#upvotes_'+post_id).text()) + 1;
$('#upvotes_'+post_id).text(like_val.toString());
}
else{
alert('You already liked that post!');
}
}
});
});
});
</script>
</html>

Do not print media from django form

I created a custom widget and included a Media class.
class MyWidget(forms.MultiWidget):
class Media:
css = {
'all': ('path-to-css.css',),
}
js = (
'path-to-js.js',
)
def __init__(self, visible_input_attrs=None, hidden_input_attrs=None):
widgets = (
TextInput(attrs=visible_input_attrs),
HiddenInput(attrs=hidden_input_attrs),
)
super(MyWidget, self).__init__(widgets)
def decompress(self, value):
if value:
return ['', value]
return [None, None]
In my form I use this widget as follows
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = [
'first_name',
'last_name',
'email',
'phone_number',
]
widgets = {
'phone_number': MyWidget(),
}
My template file
{% extends "base.html" %}
{% load static i18n crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<form id="my-form" action="" method="post" enctype="multipart/form-data">
<h2>Contact details</h2>
{% crispy user_form %}
</form>
</div>
</div>
{% endblock content %}
{% block javascript %}
{{ block.super }}
{{ user_form.media.js }}
{% endblock %}
In my template file I include the form with {% crispy user_form %} (using crispy forms). Django hereby automatically adds the CSS and JS files at the beginning of the form. Since I load JS files at the very end of every HTML page and since the included path-to-js.js file requires jQuery, I append {{ user_form.media.js }} to my javascript block in my template. As a consequence, path-to-js.js appears more than once on my page and leads to error messages because the first time path-to-js.js is loaded, jQuery is not loaded yet.
How can I avoid to load the JS files when I use {% crispy user_form %}?
Set include_media = False in your helper class.
class UserForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.include_media = False

Categories