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>`
Related
I'm using Javascript to make part of my web page editable for logged-in admin users. In one page, I have cards that display information about three people from the database. The cards contain username, skills, and bio fields. The username is also used a second time in the bio.
When the edit button is clicked, the first username, skills, and the bio without the username become editable. And when I change the username and click on the save button only the first username changes. For the one in the bio to update I need to reload the page even though they have the same id in my HTML template. How can I change the second one as well without reloading the page?
about.html:
% extends "potbs/layout.html" %}
{% load static %}
{% block script %}
<script src="{% static 'potbs/about.js' %}"></script>
{% endblock %}
{% block body %}
<div class="container">
<div class="row justify-content-center">
{% for member in team_members %}
<div class="col" id="border">
<!--If user is admin, show edit button-->
{% if user.is_superuser %}
<div class="position-relative" id="edit_button_{{member.id}}" style="display: block;">
<button class="btn btn-lg position-absolute top-0 end-0" id="edit_profile" data-id="{{member.id}}" data-username="{{member.username}}">
<i class="fa fa-edit fa-solid" style="color: white; margin-right: 5px;"></i></button>
</div>
{% endif %}
<div class="col-xs-12 center-block text-center">
<!--Display profile picture-->
<img class="pp" id="pp_{{member.id}}" src="{{member.profile_picture.url}}" alt="{{member.username}}">
<!--Edit form-->
<div class="form-group" id="edit_{{member.id}}">
</div>
<!--Display username,skills and bio-->
<div id="remove_{{member.id}}" style="display: block;">
<h3 class="username" id="username_{{member.id}}">{{member.username}}</h3>
<p class ="skills" id="skills_{{member.id}}">{{member.skills}}</p>
<div class="bio">
<strong class="username" id="username_{{member.id}}" style="font-size: large;">{{member.username}}, </strong><p id="bio_{{member.id}}">{{member.bio}}</p>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
about.js:
document.addEventListener("DOMContentLoaded", function(){
const button = document.querySelectorAll("#edit_profile")
button.forEach(function(button){
button.onclick = function(){
const memberID = button.dataset.id;
const usernameID = button.dataset.username;
const username = document.getElementById(`username_${memberID}`);
const skills = document.getElementById(`skills_${memberID}`);
const bio = document.getElementById(`bio_${memberID}`);
//Create textareas for editable fields
let edit_username = document.createElement("textarea");
edit_username.setAttribute("rows", "1");
edit_username.innerHTML = username.innerHTML
edit_username.id = `edit_username_${memberID}`;
edit_username.className = `form-control username ${usernameID}`;
let edit_skills = document.createElement("textarea");
edit_skills.setAttribute("rows", "1");
edit_skills.innerHTML = skills.innerHTML;
edit_skills.id = `edit_skills_${memberID}`;
edit_skills.className = "form-control skills";
let edit_bio = document.createElement("textarea");
edit_bio.setAttribute("rows", "5");
edit_bio.innerHTML = bio.innerHTML;
edit_bio.id = `edit_bio_${memberID}`;
edit_bio.className = "form-control bio";
edit_bio.style.borderRadius = "15px";
//Create cancel button
const cancelButton = document.createElement("button");
cancelButton.innerHTML = "Cancel";
cancelButton.id = `cancelButton_${memberID}`;
cancelButton.className = "btn btn-danger col-3";
cancelButton.style.margin = "10px";
//Create save button
const saveButton = document.createElement("button");
saveButton.innerHTML = "Save";
saveButton.id = `saveButton_${memberID}`;
saveButton.className = "btn btn-success col-3";
saveButton.style.margin = "10px";
//Hide the edit button and current content
document.getElementById(`edit_button_${memberID}`).style.display = "none";
document.getElementById(`remove_${memberID}`).style.display = "none";
//Add textarea fields to the div
document.getElementById(`edit_${memberID}`).append(edit_username);
document.getElementById(`edit_${memberID}`).append(edit_skills);
document.getElementById(`edit_${memberID}`).append(edit_bio);
document.getElementById(`edit_${memberID}`).append(saveButton);
document.getElementById(`edit_${memberID}`).append(cancelButton);
// When the cancel button is clicked
cancelButton.addEventListener("click",function(){
cancel(memberID);
})
// When the save button is clicked
saveButton.addEventListener("click", function(){
edit_username = document.getElementById(`edit_username_${memberID}`);
edit_skills = document.getElementById(`edit_skills_${memberID}`);
edit_bio = document.getElementById(`edit_bio_${memberID}`);
fetch(`/edit_profile/${memberID}`,{
method: "POST",
body: JSON.stringify({
username: edit_username.value,
skills: edit_skills.value,
bio: edit_bio.value,
})
})
.then(response => response.json())
.then(result => {
console.log(result);
if(result[`error`]){
cancel(memberID)
}
else {
username.innerHTML = result.username;
skills.innerHTML = result.skills;
bio.innerHTML = result.bio;
cancel(memberID)
}
})
.catch(error => {
console.error(error);
console.log(edit_username.value);
})
})
}
});
})
I've a project one of the models has image field to upload picture , i made it modelformset_factory to upload multiple images , but from webcam ! is there any django tips or modules to do that ? i tried this but i cant take more than one picture , and cant assign taken photo into the ImageField?
my image upload model
class Document(models.Model):
booking =models.ForeignKey(Booking,on_delete=models.PROTECT)
docs = models.ImageField(upload_to=upload_docs)
def __str__(self):
return str(self.booking.id)
my forms.py
class UploadDocumentsForm(forms.ModelForm):
class Meta:
model = Document
fields = ['docs']
UploadDocumentFormSet = modelformset_factory(Document,form=UploadDocumentsForm,extra=1,can_delete=True)
my views.py
#login_required
def add_new_image(request,id):
obj = get_object_or_404(Booking,id=id)
if request.method == 'POST':
images = UploadDocumentFormSet(request.POST,request.FILES)
if images.is_valid():
for img in images:
if img.is_valid() and img.cleaned_data !={}:
img_post = img.save(commit=False)
img_post.booking = obj
img_post.save()
return redirect(reverse_lazy("booking:add_booking",kwargs={"room_no":obj.room_no.room_no}))
else:
messages.error(request,_('take a picture or choose an image'))
images = UploadDocumentFormSet(queryset=Document.objects.none())
return render(request,'booking/add_img.html',{'obj':obj,'images':images})
const player = document.getElementById('player');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const captureButton = document.getElementById('capture');
const constraints = {
video: true,
};
captureButton.addEventListener('click', (e) => {
// Draw the video frame to the canvas.
context.drawImage(player, 0, 0, canvas.width, canvas.height);
e.preventDefault();
});
// Attach the video stream to the video element and autoplay.
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
player.srcObject = stream;
});
$('#addButton').click(function() {
var form_dex1 = $('#id_form-TOTAL_FORMS').val();
$('#images').append($('#formset').html().replace(/__prefix__/g,form_dex1));
$('#id_form-TOTAL_FORMS').val(parseInt(form_dex1) + 1);
});
<button id="addButton" class="px-4 py-1 pb-2 text-white focus:outline-none header rounded-xl">
{% trans "add new form" %}
<i class="bi bi-plus"></i>
</button>
<form action="" method="POST" enctype="multipart/form-data" dir="ltr">{% csrf_token %}
{% for form in images.forms %}
{{form.id}}
<div id="main_form" class="text-lg">
<div class="border border-purple-900 mt-2 rounded-lg p-2 text-center">
<p>{% for i in obj.takes_by.all %}
{{forloop.counter}} : {{i.full_name}}
{% endfor %}
</p>
</div>
</div>
<hr>
{{images.management_form}}
<div class="form-group mt-3" id="images">
{{ form.docs | add_class:'form-control-file' }}
</div>
<video id="player" controls autoplay></video>
<button id="capture">Capture</button>
<canvas id="canvas" width=320 height=240></canvas>
{% endfor %}
<div class="form-group mt-3" id="formset" style="display: none;">
{{ images.empty_form.docs | add_class:'form-control-file' }}
</div>
<button class="header pt-2 text-white px-4 p-1 rounded-lg mt-4">{% trans "save" %}</button>
</form>
but im not sure how to achieve it ?!
thank you for helping
I am new to Javascript. I wish to change the contents of div on selecting a particular div element.
If I select a div, the text associated with that div contents only should display. I am using a loop to display the contents. It's like a chat application. If a user clicks on a contact the messages associated with that user should display. I am using a loop to display messages and users.
What I have tried is:
Twig code:
{% set msg = query().from('messages').get() %}
{% set to_add =to_name %}
{% set to_details = query().from('users_users').where('id', to_add).get() %}
<div class="container">
<h3 class=" text-center">Messaging</h3>
<div class="messaging">
<div class="inbox_msg">
<div class="inbox_people">
<div class="headind_srch">
<div class="recent_heading">
<h4>{{auth_user().first_name}}</h4>
</div>
<div class="srch_bar">
<div class="stylish-input-group">
<input type="text" class="search-bar" placeholder="Search" >
<span class="input-group-addon">
<button type="button"> <i class="fa fa-search" aria-hidden="true"></i> </button>
</span> </div>
</div>
</div>
<div class="inbox_chat">
{% set newArray = [] %}
{% for msg in msg_details %}
{% if msg.to_name not in newArray %}
<div class="chat_list active_chat" onclick=viewMessage(this)>
<div class="chat_people">
<div class="chat_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
<div class="chat_ib">
<h5>{{msg.to_name}} <span class="chat_date">{{msg.time}}</span></h5>
</div>
</div>
</div>
{% set newArray = newArray|merge([msg.to_name]) %}
{% endif %}
{% endfor %}
</div>
</div>
<div class="mesgs">
<div class="msg_history">
<div class="incoming_msg">
<div class="incoming_msg_img">
<img src="https://ptetutorials.com/images/user-profile.png" alt="sunil">
</div>
<div class="received_msg">
<div class="received_withd_msg">
<p>{{msg.message}}</p>
<span class="time_date">{{msg.time}}</span></div>
</div>
</div>
<div class="outgoing_msg">
<div class="sent_msg">
<p></p>
<span class="time_date"></span> </div>
</div>
</div>
</div>
</div>
</div></div>
Javascript code:
<script>
function copyText(elementId){
var x = document.getElementById(elementId).textContent;
if(document.getElementById('select-text').value.length == 0)
{
document.getElementById("btn").disabled = false;
document.getElementById(elementId).style.backgroundColor = "lightblue";
document.getElementById('select-text').focus();
document.getElementById('select-text').value += x;
}
else{
document.getElementById('select-text').readOnly = true;
}
}
</script>
What my output looks like
Output
My output shows all the messages, I want to show only the particular user message. How to do so?
What my table looks like:
Table
First of all you have to fetch the data from your table using a query something like to ensure you will get one record from each from_id.
SELECT * FROM msg GROUP BY from_id;
Then you can loop in twig to create the left side elements like,
{% for distinctMsg in distinctMsgs %}
<div class="chat_list active_chat" data-userId="{{ distinctMsg.fromId }}">
<div class="chat_people">
<div class="chat_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div>
<div class="chat_ib">
<h5>{{distinctMsg.to_name}} <span class="chat_date">{{distinctMsg.time}}</span></h5>
</div>
</div>
</div>
{% endfor %}
Then in your javascript:-
$(".chat_list").on("click", function(){
// have a look here https://stackoverflow.com/questions/5309926/how-can-i-get-the-data-id-attribute
var userId = $(this).data( "userId" );
// Maybe display a loading icon in the right side div
$.ajax({
type: "POST",
url: "/api/msg/user/history", // your controller url
dataType: 'json',
headers: {
// if you have any headers to set
"Authorization": "Bearer {{ token }}"
},
data:{
"userId" : userId
}
})
.done(function (response) {
// stop displaying the loading icon
// process the response and display message history in right side
})
.fail(function (xhr, status, error) {
// show proper error message
});
});
NOTE: You will have to have jQuery in your page for Ajax functions to work.
When I changed the import method I got an error on a live search.
This is the JQUERY code I'm using. The error I'm gettin is the blogpost['title'] is empty.
I've read that it might be due to the name blogpost being the overall container, so it's not actually a single blogpost but all the blogpost, but I don't know how to fix this. I think the most helpful would be someone taking a look at the rdata and the json error. Thanks!
<script>
var data = '{{qs_json}}'
data = data.replace(/"/g, '"');
data = data.replace(/(?:\r\n|\r|\n)/g, '');
console.log(data)
rdata = JSON.parse(data)
console.log(rdata)
const input = document.getElementById('search_form')
let filteredArr = []
input.addEventListener('keyup', (e) => {
jsbox.innerHTML = ""
filteredArr = rdata.filter(blogpost => blogpost['title'].toLowerCase().includes(e.target.value.toLowerCase()))
if (filteredArr.length > 0) {
filteredArr.map(blogpost => {
jsbox.innerHTML += `
<div class="col mt-5 ml-1">
<a href="blog/${blogpost.slug}" style="text-decoration: none">
<div class= "card">
<div class='blogpost_image_container'>
<img src="${blogpost.image}" class="card-img-top" alt="blogpost image">
</div>
<div class="card-body">
<h5 class="card-title">${blogpost.title} </h5>
<p class="card-text"> ${blogpost.subtitle} </p>
<span id="category_badge" class="badge rounded-pill bg-warning text-dark"> ${blogpost.category}
</div>
</div>
</div >
</a> `
})
}
else {
jsbox.innerHTML = `<div class= "col mt-5 ml-1"> <h5 class="card-title"> No Matches Found! </h5></div >`
}
})
</script>
However the console logged Rdata shows something different:
The Console logged rdata
The error message
This is my django view import:
class BlogListView(ListView):
model = BlogPost
template_name = "blog/blog.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.GET.get('category_filter'):
cat_filter = self.request.GET.get('category_filter')
all_blogposts = BlogPost.objects.filter(
category=cat_filter)
print(all_blogposts)
else:
all_blogposts = BlogPost.objects.all()
data = serializers.serialize("json", all_blogposts)
context["qs_json"] = data
context["blogposts"] = all_blogposts
context["categories"] = Category.objects.all()
return context
And this is the forloop in the django template, not sure if it's useful.
<div class="row row-cols-1 row-cols-md-2 g-4" id="jsbox">
{% for blogpost in blogposts %}
<div class="col mt-5 ml-1">
<div class="card">
<a href="{% url 'blogpost' blogpost.slug %}">
<div class='blogpost_image_container'>
<img src="{{ blogpost.image }}" class="card-img-top" alt="blogpost image">
</div>
<div class="card-body">
<h5 class="card-title">{{ blogpost.title }} </h5>
<p class="card-text"> {{ blogpost.subtitle}} </p>
<span id="category_badge" class="badge rounded-pill bg-warning text-dark">
{{ blogpost.category }}</span>
</div>
</a>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
i'm following the Django code that dynamically generates cards according to my amount of variables i have in a bank. For each card it consumes data from an API through ajax code. However, my ajax code is not being called every loop. It is called only once. What I can do is wrong, because I need ajax to be called every loop of HTML.
{% block content %}
<div id="auto" class="row">
{% for row in list %}
{% if row.state == 1 %}
<div class="col-xs-6 col-md-4">
<div class="card">
<h5 class="card-header">{{row.description}} - Temperatura Atual (˚C)</h5>
<!--<img class="card-img-top" src="{% static 'img/gauge.png' %}" width="100" height="200" alt="Card image cap">!-->
<canvas id="myChart-{{ forloop.counter }}" class="piechart"></canvas>
<script>
var rowId = {{ row.id }}
console.log(rowId);
readTempDinamic(rowId);
//refresh();
</script>
<p class="text-center font-weight-bold" style="font-size: 0.7rem"><span id="datetime"></span></p>
Show
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock content %}
function readTempDinamic(rowId) {
var endpointTemp = '/api/weatherData/getSensor/1/' + rowId + '/'
console.log(endpointTemp);
/* ############################################################################# */
$.ajax({
method: "GET",
url: endpointTemp,
success: function(data){
var row = []
var value = []
var read_data = []
row = data.row
value = data.value
read_data = data.read_date
generateGaugeCharts(row[0], read_data[0], value[0])
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
/* ############################################################################# */
}