I am using jqvmap to show a map series (ifthq.com scroll low left). On the USA map, I have two states with values: LA and OH, both equal to 1.
The JSON used to feed jqvmap is: {"OH":1,"LA":1}.
The map shows, but does not fill correctly. My assumption is that linear normalizeFunction would result in two states at max, and the rest at min. This is not the case.
Since the US Map is over 50 elements, and the data is only two, how do I set "default" data to zero in the jqvmap? In other words, undefined states would be equal to zero?
Thanks.
UPDATE #1: Code for question:
View definition. mbrmap is the result of the data pull:
#login_required
def index_view(request):
enlisted = models.Subscription.objects.rankset("E").active().count()
officer = models.Subscription.objects.rankset("O").active().count()
civilian = models.Subscription.objects.rankset("C").active().count()
lifer = models.Subscription.objects.lifer().active().count()
subscriptions = models.Subscription.objects.all().order_by("-Modified")
mbrcnt = models.Member.objects.values('State').annotate(c=Count('State')).exclude(State='')
mbrcnt2 = models.Member.objects.values('Country').annotate(c=Count('Country')).exclude(Country='')
mbrmap = dict([(type_and_count['State'], type_and_count['c']) for type_and_count in mbrcnt])
mbrmap2 = dict([(type_and_count['Country'], type_and_count['c']) for type_and_count in mbrcnt2])
mbrmap.update(mbrmap2)
units = models.Unit.objects.values('Unit_name', 'Hull_type', 'Hull_number').annotate(c=Count('memberunit__Member'))
context = {'mbrmap': mbrmap, 'enlisted': enlisted, 'officer': officer, 'civilian': civilian, 'lifer': lifer, 'units': units, 'Subscriptions': subscriptions}
return render(request, 'index.html', context)
html:
<div class="portlet-body">
<div id="region_statistics_loading">
<img src="{% static "img/loading.gif" %}" alt="loading"/>
</div>
<div id="region_statistics_content" class="display-none">
<div class="btn-toolbar margin-bottom-10">
<div class="btn-group btn-group-circle" data-toggle="buttons">
<a href="" class="btn grey-salsa btn-sm active">
Members </a>
<a href="" class="btn grey-salsa btn-sm">
Units </a>
</div>
<div class="btn-group pull-right">
<a href="" class="btn btn-circle grey-salsa btn-sm dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" data-close-others="true">
Select Region <span class="fa fa-angle-down">
</span>
</a>
<ul class="dropdown-menu pull-right">
<li>
<a href="javascript:;" id="regional_stat_world">
World </a>
</li>
<li>
<a href="javascript:;" id="regional_stat_usa">
USA </a>
</li>
{% comment %}<li>
<a href="javascript:;" id="regional_stat_europe">
Europe </a>
</li>
<li>
<a href="javascript:;" id="regional_stat_russia">
Russia </a>
</li>
<li>
<a href="javascript:;" id="regional_stat_germany">
Germany </a>
</li>{% endcomment %}
</ul>
</div>
</div>
<div id="vmap_world" class="vmaps display-none">
</div>
<div id="vmap_usa" class="vmaps display-none">
</div>
{% comment %}<div id="vmap_europe" class="vmaps display-none">
</div>
<div id="vmap_russia" class="vmaps display-none">
</div>
<div id="vmap_germany" class="vmaps display-none">
</div>{% endcomment %}
</div>
</div>
<!-- PAGE LEVEL SPELLS -->
{% block PageSpells %}
<!-- PLUGINS -->
<script src="{% static "plugins/jqvmap/jqvmap/jquery.vmap.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/jqvmap/jqvmap/maps/jquery.vmap.russia.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/jqvmap/jqvmap/maps/jquery.vmap.world.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/jqvmap/jqvmap/maps/jquery.vmap.europe.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/jqvmap/jqvmap/maps/jquery.vmap.germany.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/jqvmap/jqvmap/maps/jquery.vmap.usa.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/jqvmap/jqvmap/data/jquery.vmap.sampledata.js" %}" type="text/javascript"></script>
<!-- SPELLS -->
<script src="{% static "js/index.js" %}" type="text/javascript"></script>
<script src="{% static "plugins/uniform/jquery.uniform.min.js" %}" type="text/javascript"></script>
{% endblock %}
<!-- PAGE JQUERY -->
{% block Jquery %}
var mapdata = {{ mbrmap|safe }};
Index.init();
Index.initCmdSelect();
Index.initJQVMAP(mapdata); // init index page's custom scripts
{% endblock %}
javascript code:
initJQVMAP: function (mapdata) {
if (!jQuery().vectorMap) {
return;
}
var showMap = function (name) {
jQuery('.vmaps').hide();
jQuery('#vmap_' + name).show();
}
var setMap = function (name) {
var data = {
map: 'world_en',
backgroundColor: null,
borderColor: '#333333',
borderOpacity: 0.5,
borderWidth: 1,
color: '#c6c6c6',
enableZoom: true,
hoverColor: '#c9dfaf',
hoverOpacity: null,
values: mapdata,
normalizeFunction: 'linear',
scaleColors: ['#C8EEFF', '#0071A4'],
selectedColor: '#c9dfaf',
selectedRegion: null,
showTooltip: true,
onLabelShow: function (event, label, code) {
},
onRegionOver: function (event, code) {
if (code == 'ca') {
event.preventDefault();
}
},
onRegionClick: function (element, code, region) {
if (typeof mapdata[code.toUpperCase()] === 'undefined') {
var sval = 0;
} else {
var sval = mapdata[code.toUpperCase()]
}
var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase() + ' and value: ' + sval;
alert(message);
}
};
data.map = name + '_en';
var map = jQuery('#vmap_' + name);
if (!map) {
return;
}
map.width(map.parent().parent().width());
map.show();
map.vectorMap(data);
map.hide();
}
setMap("world");
setMap("usa");
//setMap("europe");
//setMap("russia");
//setMap("germany");
showMap("world");
jQuery('#regional_stat_world').click(function () {
showMap("world");
});
jQuery('#regional_stat_usa').click(function () {
showMap("usa");
});
jQuery('#regional_stat_europe').click(function () {
showMap("europe");
});
jQuery('#regional_stat_russia').click(function () {
showMap("russia");
});
jQuery('#regional_stat_germany').click(function () {
showMap("germany");
});
$('#region_statistics_loading').hide();
$('#region_statistics_content').show();
},
Of note, the initJQVMAP function is a method in the index object:
var Index = function() {....
It is initialized by the Index.initJQVMAP(mapdata); function call. Thanks.
You could try changing the colors after creating the map:
var newData = {};
for (var key in mapdata)
newData[key.toLowerCase()] = '#0071A4';
map.vectorMap('set', 'colors', newData);
Here there is a working sample.
Edit
I've also found this different solution:
var arrStates = [];
for (var key in mapdata)
arrStates.push(key);
map.vectorMap('set', 'colors', arrStates, '#0071A4');
You can use $.extend() to combine two objects, overwriting the values of one if they exist in the other (documentation here). For example:
var mySmallData = {
"OH": 1,
"LA": 1
};
var DEFAULTS = {
"OH": 0,
"LA": 0,
"WA": 0,
"ID": 0,
// etc.
};
var fullData = $.extend({}, DEFAULTS, mySmallData);
fullData would now contain:
{
"OH": 1,
"LA": 1,
"WA": 0,
"ID": 0
}
This way, you have one object that has all of your defaults and you never have to mess with it. Your sparse object can have as few data points as you want, and it will always get expanded to the full set of states.
Related
Iam building my portfolio website and i build a simple stocktracker. I added some charts from Chart.js, but somehow only one gets rendered when I excecute the code.
I managed to assign all the divs and data dynamically by making the variables dynamic. I did this by adding the portfolio id in the for loop. I can't figure out why its not working. Appreciate any help.
{% extends 'base.html' %}
{% block page_content %}
{% if user.is_authenticated %}
<body>
<div class="container">
<div class="row">
<div class="col-12">
<h2>
Welcome to the stocktracker
</h2>
<p>I build this stocktracker app to learn database operations. To get current stock data, I linked this to
the free API from Polygon.io. It's only possible to do 5 API calls per minute. You will see an error
message whenever the api calls are exceeded.
<br><br>Current features are:
<ol>
<li>Basic CRUD database operation</li>
<li>Adding portfolio's linked to user</li>
<li>Only show portfolio's linked to user</li>
<li>Show general KPI's in portfolio overview</li>
<li>KPI's calculated based on positions in portfolio</li>
<li>Adding position to portfolio</li>
<li>API connection with Polygon.io to get live stock data</li>
<li>Chart.js integration for visual representation of portfolio metrics</li>
</ol>
</p>
</div>
</div>
<div class="row">
<div class="col-8">
<h2>Select your portfolio</h2>
</div>
<div class="col-4 text-end">
<!-- Button trigger modal -->
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#addPortfolioModal">
Add new portfolio
</button>
<!-- Modal -->
<div class="modal fade" id="addPortfolioModal" tabindex="-1" role="dialog"
aria-labelledby="addPortfolioModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addPortfolioLabel">Modal title</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form name="portfolio_form" method="post">
{% csrf_token %}
<p>
{{ portfolio_form }}
</p>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close
</button>
<input type="submit" value="Submit"/>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div>
{% for portfolio in portfolios %}
<div class="row pt-4">
<div class="col-6">
<a class="btn btn-primary" href="{% url 'portfolio_detail' portfolio.pk%}">Go to {{ portfolio }}</a>
</div>
</div>
{% if portfolio.total_positions > 0 %}
<div>
{% load static %}
<div class="col-4 text-start" style="width: 50%;">
<canvas id="pie-chart{{ portfolio.pk }}"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3/dist/Chart.min.js"></script>
<script>
var randomNum_{{ portfolio.pk }} = () => Math.floor(Math.random() * (235 - 52 + 1) + 52);
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
countPositions = {{ portfolio.total_positions|safe }};
var barColors_{{ portfolio.pk }} = [];
for (let i = 0; i < countPositions; i++) {
randomGeneratedColor = rgbToHex(randomNum_{{ portfolio.pk }}(), randomNum_{{ portfolio.pk }}(), randomNum_{{ portfolio.pk }}());
while (barColors_{{ portfolio.pk }}.includes(randomGeneratedColor)) {
randomGeneratedColor = rgbToHex(randomNum(), randomNum(), randomNum());
}
barColors_{{ portfolio.pk }}.push(randomGeneratedColor);
}
var config_{{ portfolio.pk }} = {
type: 'pie',
data: {
datasets: [{
data: {{ portfolio.data_for_chart_array|safe }},
backgroundColor: barColors_{{ portfolio.pk }},
label: 'Stock ticker'
}],
labels: {{ portfolio.labels_array|safe }}
},
options: {
responsive: true
}
};
window.onload = function() {
var ctx = document.getElementById('pie-chart{{ portfolio.pk }}').getContext('2d');
window.myPie = new Chart(ctx_{{ portfolio.pk }}, config_{{ portfolio.pk }});
};
</script>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-4 pt-2">
<b>Total amount invested:</b> {{ portfolio.total_amount_invested }}
<br><b>Positions:</b> {{ portfolio.total_positions }}
<br><b>Profit:</b> {{ portfolio.total_profit }}
<br><b>Profit in %:</b> {{ portfolio.total_profit_percentage }} %
</div>
</div>
</div>
{% endfor %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</div>
</body>
{% endif %}
{% endblock %}
Somehow only the last chart gets rendered instead of all three.
You have a loop there, and in each iteration of the loop, you're using window.onload = function() {…};
Basically, you're overwriting the onload function at each iteration of the loop, so only the last overwrite survives.
What you want is to add load event listeners on the window instead of continually overwriting one single listener.
To achieve this, I would recommend replacing this:
window.onload = function () {…}
with this:
window.addEventListener('load', function() {…})`
See addEventListener
Another way of seeing that window.onload = function () {…} is problematic is the following snippet:
window.onload = function () { alert('one') };
window.onload = function () { alert('two') };
Q: What do you expect to happen on page load here?
A: Similarly to your case, only the second function (alerting "two") will be called.
I am trying to print the contents of a specific div with a class called "container" which has a number of divs having their individual classes. The problem I am facing is that when I click the print button the print preview shows the contents to be printed in completely plain format, no css styles applied. But I want the contents to be exactly the way it is being displayed in the browser. I have tried a number of ways and solutions from here but nothing seems to work. Please suggest me some way to do it. I was trying to do it with javascript. The javascript code given below is cpied as I said I was trying out all the possible ways.
javascript
$(function () {
$("#btnPrint").click(function () {
var contents = $("#content").html();
var frame1 = $('<iframe />');
frame1[0].name = "frame1";
frame1.css({ "position": "absolute", "top": "-1000000px" });
$("body").append(frame1);
var frameDoc = frame1[0].contentWindow ? frame1[0].contentWindow : frame1[0].contentDocument.document ? frame1[0].contentDocument.document : frame1[0].contentDocument;
frameDoc.document.open();
//Create a new HTML document.
frameDoc.document.write('<html><head><title>DIV Contents</title>');
frameDoc.document.write('</head><body>');
//Append the external CSS file.
frameDoc.document.write('<link href="C:\Users\Intel\Envs\test\project\static\doc.css" rel="stylesheet" type="text/css" />');
//Append the DIV contents.
frameDoc.document.write(contents);
frameDoc.document.write('</body></html>');
frameDoc.document.close();
setTimeout(function () {
window.frames["frame1"].focus();
window.frames["frame1"].print();
frame1.remove();
}, 500);
});
});
The below images are the way it is being displayed in the browser and the way it is displayed in the preview
This is how i want it to get it printed
and this is how it getting printed]2
html file
<link rel="stylesheet" href="{% static 'doc.css' %}" media="all"/>
<div class="main-container">
<div class="container" id="content">
{% if object.reportable %}
<div class="report">
<p>Reportable </p>
</div>
{% endif %}
{% if object.non_reportable %}
<div class="report">
<p>Non-Reportable </p>
</div>
{% endif %}
{% if object.over_ruled %}
<div class="over">
<p>Over Ruled </p>
</div>
{% endif %}
{% if object.equivalent_citations %}
<div class="cit">
<p><b>Equivalent Citations:</b> {{object.equivalent_citations}}</p>
</div>
{% endif %}
<div class="crt">
<p><b>In The {{object.court_type}}</b></p>
</div>
<div class="appeal">
<p><b>{{object.apelLate_type}}</b></p>
</div>
<div class="jdge">
<p> <b>Before:</b> {{object.judge_name}}</p>
</div>
<div class="party-name">
<p> <b> {{object.party_name}} </b> </p>
</div>
<div class="case-no">
<p><b>Case No.:</b> {{object.case_no}} </p>
</div>
...
<div class="container-2">
<input type="button" id="btnPrint" value="Print" />
</div>
</div>
Consider the following example: https://jsfiddle.net/Twisty/aspehr0m/7/
JavaScript
$(function() {
$("#btnPrint").click(function() {
var contents = $("#content").html();
var frame1 = $('<iframe>', {
id: "frame1",
name: "frame1"
})
.css({
"position": "absolute",
"top": "-1000000px"
})
.appendTo($("body"));
var myHTML = $("<html>");
$("<head>").appendTo(myHTML);
$("<title>").html("DIV Contents").appendTo($("head", myHTML));
$("<body>").appendTo(myHTML);
$("body > link").clone().appendTo($("body", myHTML));
$("body", myHTML).append(contents);
console.log("Content", myHTML.prop("outerHTML"));
var frameDoc = window.frames.frame1;
frameDoc.document.open();
//Create a new HTML document.
frameDoc.document.write(myHTML.prop("outerHTML"));
frameDoc.document.close();
setTimeout(function() {
frame1.focus();
window.frames.frame1.print();
frame1.remove();
}, 500);
});
});
Here you can use .clone() to make a copy of the existing Stylesheet Link. this will ensure it uses the same as the primary page.
It is consider a better practice not to mix JavaScript and jQuery, to stick to one or the other. In this case, it's a bit easier to to manage the iFrame element with native JavaScript.
Update
You might consider making a new Function: https://jsfiddle.net/Twisty/aspehr0m/38/
JavaScript
$(function() {
$.fn.printContent = function() {
var target = $(this);
var title;
if (target.attr("title") != undefined) {
title = target.attr("title");
} else {
title = "Element Contents"
}
var uid = Date.now();
var printFrame = $("<iframe>", {
id: "printFrame_" + uid,
name: "printFrame_" + uid
}).css({
position: "absolute",
top: "-1000000px"
}).appendTo($("body"));
var frameHTML = $("<html>");
$("<head>").appendTo(frameHTML);
$("<title>").html(title).appendTo($("head", frameHTML));
$("<body>").appendTo(frameHTML);
if ($("body > link").length == 1) {
$("body > link").clone().appendTo($("body", frameHTML));
}
$("body", frameHTML).append(target.html());
var winFrame = window.frames['printFrame_' + uid];
winFrame.document.open();
winFrame.document.write(frameHTML.prop("outerHTML"));
winFrame.document.close();
setTimeout(function() {
printFrame.focus();
winFrame.print();
printFrame.remove();
}, 100);
};
$("#btnPrint").click(function() {
$("#content").printContent();
});
});
Use an URL or accessible path instead of:
C:\Users\Intel\Envs\test\project\static\doc.css" rel="stylesheet" type="text/css" />
By the way, The javascript seems to be ok, your page wouldn't show content if it were misspelled
I'm trying to implement infinite scroll with django and jquery(Waypoint).
I have a ListView with a pagination of 5, but when waypoint loads second page, AJAX requests are no longer performed so I added the AJAX function on the onAfterPageLoad which helps bring back AJAX function to the newly loaded page.
That's fine, but then it introduces a bug to my code making the page loaded initially (First Page) no longer perform AJAX functions very well. It makes AJAX on the first page run 3 times if I just loaded a third page and makes AJAX on the second page run twice and so on depending on the number of pages loaded already.
I don't know if there are any cool ways to achieve this because I tried using just jquery without waypoint, but still get same errors as I get when using just waypoint making it an error. This is kinda tricky so far.
{% extends "base.html" %}
{% block content %}
{% load static %}
<div class="container" style="max-width:700px">
<div class="px-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">All Groups</h1>
<p class="lead">List of groups</p>
</div>
<div class="">
<div class="row infinite-container">
{% for group in groups %}
<div class="col-md-12 infinite-item">
<!-- <img class="img-fluid" src="https://picsum.photos/700"> -->
<a class="text-dark" href="{{ group.get_absolute_url }}">
<div class="card mb-4 box-shadow">
<div class="card-body">
<h2 style="font-size:18px;font-weight:bold;min-height:42px;">
{{group.name|truncatechars:50}}</h2>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">{{group.owner}}</small>
<small class="text-muted">{{group.date_created}}</small>
</div>
<p><a class='follow-btn' data-href='{{ group.get_group_follow_api_url }}'
data-likes='{{ page.likes.count }}'
href='{{ group.get_group_follow_url }}'>{{ group.follows.count }}
{% if request.user.profile in group.follows.all %}
Unfollow
{% else %}
Follow
{% endif %}
</a></p>
</div>
</div>
</a>
</div>
{% endfor %}
</div>
<!-- Comment for loading spinner -->
{% comment %}
<div class="d-flex d-none position-fixed" style="top:35vh;left:46vw">
<button class="btn btn-primary loading">
<span class="spinner-border spinner-border-sm"></span>
Loading...
</button>
</div>
{% endcomment %}
<!-- End of comment for loading spinner -->
<div class="row">
<div class="col-12">
{% if page_obj.has_next %}
<a class="infinite-more-link" href="?page={{ page_obj.next_page_number }}"></a>
{% endif %}
</span>
</div>
</div>
</div>
</div>
<script src="{% static "js/jquery.waypoints.min.js" %}"></script>
<script src="/static/js/infinite.min.js"></script>
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
offset: 'bottom-in-view',
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function () {
$('.loading').hide();
$(document).ready(function(){
function updateText(btn, newCount, verb){
btn.text(newCount + " " + verb)
}
$(".follow-btn").click(function(e){
e.preventDefault()
var this_ = $(this)
var badge = this_.find('.unlike-update')
var followUrl = this_.attr("data-href")
var followCount = parseInt(this_.attr("data-follows")) | 0
var addFollow = followCount + 1
var removeFollow = followCount - 1
if (followUrl){
$.ajax({
url: followUrl,
method: "GET",
data: {},
success: function(data){
console.log(data)
var newFollows;
if (data.followed){
// updateText(this_, addLike, "Unlike")
// updateText(this_, data.likescount, badge)
updateText(this_, data.followscount, "Unfollow")
} else {
// updateText(this_, removeLike, "Like")
updateText(this_, data.followscount, "Follow")
// remove one like
}
}, error: function(error){
console.log(error)
console.log("error")
}
})
}
})
})
}})
</script>
{% include 'group/snippets/group_follow.html' %}
{% endblock %}
class GroupListView(LoginRequiredMixin, ListView):
model = Group
paginate_by = 5
context_object_name = 'groups'
template_name = 'group/group_list.html'
ordering = ['-date_created']
I've got this system where I want to add in a favoriting feature where when someone clicks on the like button on a card it gets saved and displayed at port/wishlist.html but not able to go about and solve it, here is my Github Repository and some main codes.
models.py
from django.db import models
from django.contrib.auth.models import User
import datetime
YEAR_CHOICES = []
for r in range(1980, (datetime.datetime.now().year + 1)):
YEAR_CHOICES.append((r, r))
class Music(models.Model):
song = models.CharField(max_length=50, blank=False)
pic = models.ImageField(blank=False, null=True)
published_year = models.IntegerField(('year'), choices=YEAR_CHOICES, default=datetime.datetime.now().year)
description = models.CharField(max_length=80)
def __str__(self):
return self.song
class Wishlist(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,null=True)
music = models.ForeignKey(Music, on_delete=models.DO_NOTHING)
views.py
#login_required
def liked(request):
if request.method == "POST":
if user.is_authenticated:
# takes in the specific card id that is been liked and saves it and displays on Port/wishlist.html
music.save()
else:
return HttpResponse("Your card is Invalid")
else:
return HttpResponse("Your request is Invalid")
return render(request, template_name='main/wishlist.html', context={"wishlist": Wishlist.objects.all})
like.js
$(document).ready(function(){
$(".like").click(function(){
$(this).toggleClass("heart");
});
});
I would suggest doing something like this:
Here we create a new url for add to wishlist(add_to_wishlist). In like.js pass music_id through ajax with POST.If a user is login then show user's wishlisted product as heart symbol as red. And you can show wishlisted product through link in template. You can Understand all others in my code. Please try this. Thanks.
urls.py
from django.urls import path
from main import views
app_name = 'main'
urlpatterns = [
path('', views.home, name='home'),
path('signup/', views.signup, name='signup'),
path('wishlist/', views.liked, name='liked'),
path('login/', views.login_req, name='login'),
path('logout/', views.logout_req, name='logout'),
path('add-to-wishlist/', views.add_to_wishlist, name='add_to_wishlist'), # For add to wishlist
]
views.py
def home(request):
wishlisted_list =[]
if request.user.is_authenticated:
wishlisted_list = list(Wishlist.objects.filter(user_id=request.user).values_list('music_id',flat=True).order_by('music_id'))
return render(request, template_name='main/home.html', context={"music": Music.objects.all(),'wishlisted_list':wishlisted_list})
#login_required
def liked(request):
wishlist = {}
if request.method == "GET":
if request.user.is_authenticated:
wishlist = Wishlist.objects.filter(user_id_id=request.user.pk)
else:
print("Please login")
return HttpResponse("login")
return render(request, template_name='main/wishlist.html', context={"wishlist": wishlist})
#login_required
def add_to_wishlist(request):
if request.is_ajax() and request.POST and 'attr_id' in request.POST:
if request.user.is_authenticated:
data = Wishlist.objects.filter(user_id_id = request.user.pk,music_id_id = int(request.POST['attr_id']))
if data.exists():
data.delete()
else:
Wishlist.objects.create(user_id_id = request.user.pk,music_id_id = int(request.POST['attr_id']))
else:
print("No Product is Found")
return redirect("main:home")
like.js
$(document).ready(function(){
$(".like").click(function(){
var attr_id = $(this).attr('attr_id')
var action_url = $(this).attr('action_url')
var that = $(this)
$.ajax({
url: action_url,
type: "POST",
data: {'attr_id': attr_id },
headers: { "X-CSRFToken": $.cookie("csrftoken") },
success: function (result) {
console.log("Success")
that.toggleClass("heart");
},
error: function () {
alert("Please login");
}
});
});
});
home.html
{% load static %}
<link rel="stylesheet" href="{% static 'main/home.css' %}" type="text/css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.13.0/css/all.css" integrity="sha384-Bfad6CLCknfcloXFOyFnlgtENryhrpZCe29RTifKEixXQZ38WheV+i/6YWSzkz3V" crossorigin="anonymous">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Hey there,
{% if user.is_authenticated %}
<h1>{{user.username}}</h1>
{% else %}
<h1>unknown</h1>
{% endif %}
<a href="{% url 'main:liked' %}" >Wishlist</a>
<section class="cards">
{% for m in music %}
<div class="card">
<div class="top">
<div class="label1">{{m.song}}</div>
{% if m.pk in wishlisted_list %}
{% for i in wishlisted_list %}
{% if m.pk is i %}
<span class="like heart" id="id" attr_id="{{m.pk}}" action_url="{% url 'main:add_to_wishlist' %}"><i class="fa fa-heart"></i></span>
{% endif %}
{% endfor %}
{% else %}
<span class="like" id="id" attr_id="{{m.pk}}" action_url="{% url 'main:add_to_wishlist' %}"><i class="fa fa-heart"></i></span>
{% endif %}
</div>
<div class="middle">
<a href="https://google.com" id="link" target="_blank">
<div class="img-container"><img src="{{ m.pic.url }}"></div>
</a>
</div>
<a href="https://google.com" id="link" target="_blank">
<div class="bottom">
<div class="label4">{{m.description}}</div>
</div>
</a>
</div>
{% endfor %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'main/js/like.js' %}" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
</section>
wishlist.html
{% load static %}
<link rel="stylesheet" href="{% static 'main/home.css' %}" type="text/css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.13.0/css/all.css" integrity="sha384-Bfad6CLCknfcloXFOyFnlgtENryhrpZCe29RTifKEixXQZ38WheV+i/6YWSzkz3V" crossorigin="anonymous">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Hey there,
{% if user.is_authenticated %}
<h1>{{user.username}}</h1>
{% else %}
<h1>unknown</h1>
{% endif %}
<a href="{% url 'main:home' %}" >Go to Home</a>
<section class="cards">
{% if wishlist %}
{% for m in wishlist %}
<div class="card">
<div class="top">
<div class="label1">{{m.music_id}}</div>
<span class="like" id="id" attr_id="{{m.music_id.pk}}" action_url="{% url 'main:add_to_wishlist' %}"></span>
</div>
<div class="middle">
<a href="https://google.com" id="link" target="_blank">
<div class="img-container"><img src="{{ m.music_id.pic.url }}"></div>
</a>
</div>
<a href="https://google.com" id="link" target="_blank">
<div class="bottom">
<div class="label4">{{m.music_id.description}}</div>
</div>
</a>
</div>
{% endfor %}
{% else %}
<div class="card">
<div class="middle">
<div class="label1">Your Wishlist is empty...!</div>
</div>
<div class="bottom">
<div class="label4">Go to Shop</div>
</div>
</div>
{% endif %}
</section>
First things first, you need to add a primary key in the Music table assuming you name it as id
In the like.js file, you'll need to make an Ajax call to send the music ID to Django. Pass the music ID to the template when you render it so that you can pass it back during the Ajax call
like.js
$.ajax(path, {
data: {"music_id": 12345},
method: "POST",
success: function (data, textStatus, jqXHR) {
$(selector).toggleClass("heart");
},
error: function () {
console.log("Something went wrong");
}
Now, in you view, you can have something like this
view.py
def add_to_wishlist(request):
data = json.loads(request.body.decode("utf-8"))
user_id = request.user.id
music_id = data.get('domain_name'))
wishlist = Wishlist()
wishlist.user_id = user_id
wishlist.music_id = music_id
wishlist.save()
I am using django 1.10.5, booststrap 4.0 and LeafletJs 1.0.3 with routing machine plugin and geocoder.
Now I have the following problem, the collapse button of the control pannel for routing machine is not loading (its not showing up in the html code) when the map is bigger than 640 x 640px when the page is loaded the first time.
there are no problems when I make the map bigger with chrome dev tools after the page is fully loaded with the map size set in css to 640x640px or smaller.
I have a version of that works the way it should, but this is without django and bootstrap and I need it to work with both.
css code
.map-add-size{
position: relative;
width: 500px;
height:500px;
}
.html
{% extends 'base.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block css %}
<link href="{% static 'routes/css/add.css' %}" rel="stylesheet">
{{block.super}}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.3/dist/leaflet.css">
<link href="{% static 'routes/css/leaflet-routing-machine.css' %}" rel="stylesheet" >
<link href="{% static 'routes/css/Control.Geocoder.css' %}" rel="stylesheet">
{% endblock %}
{% block content %}
<h3>Add a new route</h3>
<div class="row">
<div class="route-edit">
<div class="col-xs-6">
<p>Route page information</p>
<form id="mainForm" method="post" class="form">
{% csrf_token %}
{{ routeAddForm|crispy }}
<div class="row route-edit">
<button type="submit" name="save_route" class="btn btn-primary">Save and continue</button>
</div>
</form>
</div>
</div>
</div>
<div class ="row">
<div class="cols-xs-8 map-container-div">
<p>Add start and end markers by left clicking on the map. <br>
Add markers by clicking on the lines inbetween the start and end markers<br>
Remove markers by clicking on the cross next to the address of the marker.
</p>
</div>
</div>
<div id="map-add" class="map-add-size"></div>
{% endblock %}
{%block javascript %}
{{block.super}}
<script src="{% static 'routes/js/cookie.js' %}"></script>
<script>
var csrftoken = Cookies.get('csrftoken');
</script>
<script src="https://unpkg.com/leaflet#1.0.3/dist/leaflet.js"></script>
<script src="{% static 'routes/js/leaflet-routing-machine.js' %}"></script>
<script src="{% static 'routes/js/Control.Geocoder.js' %}"></script>
<script src="{% static 'routes/js/map-add.js' %}"></script>
{%endblock%}
javascript
window.lrmConfig = {
// serviceUrl: 'https://api.mapbox.com/directions/v5',
// profile: 'mapbox/driving',
};
var map = L.map('map-add').setView([51.505, -0.09], 3);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}{r}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var geocoder = L.Control.Geocoder.mapzen('search-DopSHJw'),
control2 = L.Control.geocoder({
geocoder: geocoder,
defaultMarkGeocode: false
}).on('markgeocode', function(e){
var bbox = e.geocode.bbox;
var poly = L.polygon([
bbox.getSouthEast(),
bbox.getNorthEast(),
bbox.getNorthWest(),
bbox.getSouthWest()
]).addTo(map);
map.fitBounds(poly.getBounds());
}).addTo(map);
control = L.Routing.control(L.extend(window.lrmConfig, {
geocoder: L.Control.Geocoder.nominatim(),
routeWhileDragging: true,
reverseWaypoints: true,
showAlternatives: true,
altLineOptions: {
styles: [
{color: 'black', opacity: 0.15, weight: 9},
{color: 'white', opacity: 0.8, weight: 6},
{color: 'blue', opacity: 0.5, weight: 2}
]
},
})).addTo(map);
L.Routing.errorControl(control).addTo(map);
function createButton(label, container) {
var btn = L.DomUtil.create('button', '', container);
btn.setAttribute('type', 'button');
btn.innerHTML = label;
return btn;
}
map.on('click', function(e) {
var container = L.DomUtil.create('div'),
startBtn = createButton('Start from this location', container),
destBtn = createButton('Go to this location', container);
var removeContainer = L.DomUtil.create('div'),
removeBtn = createButton('Remove waypoint',removeContainer);
L.popup()
.setContent(container)
.setLatLng(e.latlng)
.openOn(map);
L.DomEvent.on(startBtn, 'click', function() {
control.spliceWaypoints(0, 1, e.latlng);
map.closePopup();
});
L.DomEvent.on(destBtn, 'click', function() {
control.spliceWaypoints(control.getWaypoints().length - 1, 1, e.latlng);
map.closePopup();
});
});
// Submit post on submit
$('#mainForm').on('submit', function(event){
event.preventDefault();
console.log("form submitted!"); // sanity check
postData();
});
var successText;
function postData(){
console.log("postData is working!");// sanity check
var formData = $("#mainForm").serializeArray();
var routeArray =Array(),
routeArray = control.getWaypoints();
var json_obj = JSON.stringify(routeArray);
formData.push({name:'json_data',value:json_obj});
console.log("form data that is send")
console.log(formData);
$.post({
type: 'POST',
url: '/routes/add/',
data: formData,
});
}
I found a way to make it work for sizes bigger than 640px. I am unsure if this is the correct way to fix it, but it works for now.
in leaflet-routing-machine.js changed 640 to 1200 in this line and now the button works for maps that are bigger than 640px.
collapsible = collapsible || (collapsible === undefined && map.getSize().x <= 1200);