"How to load map using leaflet in templates? " - leaflet

It works in ![django default admin site form] (https://imgur.com/IxwVldn) but not on .
i tried passing attributes on leafletwidget, load leaflet_tags . it's not working or as i am new, could't use them properly.
create.html
{% extends 'index.html' %}
{% load leaflet_tags %}
{% leaflet_js plugins="forms" %}
{% leaflet_css plugins="forms" %}
{% load static %}
{% block content %}
<form method="POST"> {% csrf_token %}
{{ form.as_p }}
<button type="submit" value="Save">Save</button>
</form>
{% endblock %}
view.py
class AdminForm(forms.ModelForm):
class Meta:
model = Outlet
fields = ['display_name', 'location']
widgets = {'location': LeafletWidget()}
models.py
location = geomodel.PointField()
want to load map on my create form

Leaflet has a greate documentation / Quick Start Guide at:
https://leafletjs.com/examples/quick-start/
or simply build upon this *.html snippet (it uses the openstreetmap tile server instead of the MapBox tile server):
{% extends 'index.html' %}
{% block content %}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""></script>
<div id="mapid" class="w-100 h-100">
<script>
var zoom = 10
var lat = 51.11
var lon = 9.85
var mymap = L.map('mapid').setView([ lat, lon, {{world_border.lon}}], zoom);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap',
//maxZoom: 15,
subdomains: ['a','b','c']
}).addTo(mymap);
var marker = L.marker([ lat, lon ]).addTo(mymap);
</script>
</div>
{% endblock %}
It should look like this
https://i.stack.imgur.com/gq8r4.png
As in the leaflet Quick Start Guide, you may also use mapbox tile server, looks nicer, but costs (if you exceed more than 25'000 hits per day) and you need to sign in and get a token. But it looks quite nice.
See https://leafletjs.com/examples/quick-start/example.html
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1,
accessToken: 'your.mapbox.access.token'
}).addTo(mymap);

Related

Leaflet marker popup not rendering

I have markers in a list, I am trying to read markers in the list from my database to show pop up information but it's not working. I am using jinja to print the list from python into html, i just get an internal server error message. I am using oracle and cgi-bin
var markers= L.markerClusterGroup({
});
{% for item in markers %}
var marker{{ item[0] }} = L.marker({{ item[3:] }});
var popup{{ item[0] }} = $('<div />');
popup{{ item[0] }}.html("<br>{{ item[1] }}<br>&pound{{ item[2] }<br<button>Run to this place</button>");
markers.addLayer(marker{{ item[0] }}.bindPopup(popup{{ item[0] }}[0]));
map.addLayer(markers)
{% endfor %}

Calling image is deprecated

I just noticed this in my logs (when visiting my homepage on www.sk8whls.com):
Calling "image" on template "macros/html.twig" from template "teasers/wheels.twig"
is deprecated since version 1.28 and won't be supported anymore in 2.0.
An image is called like this (in teasers/wheels.twig):
{{ html.image( image, 'thumbnail', fallback ) }}
My macro is as follows:
{% macro image(image, size, fallback, alt, title, class ) %}
{% set image = image %}
{% set size = size|default('') %}
{% set fallback = fallback|default(0) %}
{% if image and image.src %}
<img src="{{ image.src(size) }}" alt="{% if alt %}{{ alt }}{% else %}{{ image.alt }}{% endif %}" title="{{ title }}" class="{{ class }}" />
{% elseif fallback %}
<img src="{{ fallback }}" alt="fallback" title="" />
{% endif %}
{% endmacro %}
I'm not sure why it's deprecated and how I can keep it working when the support drops with v2.0.
As from the deprecated feature list :
As of Twig 2.0, macros imported in a file are not available in child
templates anymore (via an include call for instance). You need to
import macros explicitly in each file where you are using them.
Meaning you should also write {%- import 'macros/html.twig' as html -%} inside wheels.twig

Flask form routing

I'm struggling with a Flask App that gives me Bad Request on a form submission. I've been through the little bit of documentation from Flask and a number of SO pages. I'm sure there's something simple I'm missing.
In a nutshell, I've developed a template to receive the form called 'placeindex.html'. The form 'name' data all matches. If I change the name of 'placeindex.html' to 'index.html' it works fine, even though I'm pointing to the 'placeindex.html' file. Code below (view):
#app.route('/add_place', methods=['GET', 'POST'])
def add_place():
username = session['username']
placename = request.form['place']
address = request.form['address']
city = request.form['city']
state = request.form['state']
zipcode = request.form['zipcode']
alias = request.form['alias']
searchword = request.args.get('key', '')
print(searchword)
Place(session['username']).new_place(placename, address, city, state, zipcode, alias, username)
return render_template('placeindex.html')
placeindex.html:
{% extends "layout.html" %}
{% block place %}
<h2>Home</h2>
{% if session.username %}
<h3>Add new 'placeindex'</h3>
<form action="{{ url_for('add_place') }}" method="post">
<dl>
<dt>Name:</dt>
<dd><input type="text" size="30" name="place"></dd>
<dt>Address:</dt>
<dd><input type="text" size="30" name="address"></dd>
<dt>City:</dt>
<dd><input type="text" size="30" name="city"></dd>
<dt>State:</dt>
<dd><input type="text" size="2" name="state"></dd>
<dt>Zip Code:</dt>
<dd><input type="text" size="10" name="zipcode"></dd>
<dt>Nickname:</dt>
<dd><input type="text" size="30" name="alias"></dd>
</dl>
<input type="submit" value="Save">
</form>
{% endif %}
<br>
<h3>My Places</h3>
{% include "display_posts.html" %}
{% endblock %}
I've stripped out all the validation code to try to figure this out.
layout.html (in case it helps):
<!doctype html>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<div class="page">
<div class="metanav">
{% if session.username %}
Logged in as {{ session.username }}
{% endif %}
Home
{% if not session.username %}
Register
Login
{% else %}
Profile
Logout
Places
Trips
Delegates
{% endif %}
</div>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block body %}{% endblock %}
{% block post %}{% endblock %}
{% block place %}{% endblock %}
{% block trip %}{% endblock %}
</div>
Once I open the 'index.html' version of the file and send form data, it refreshes to the correct file, but I can't go there directly without the BAD REQUEST page.
Thanks
The issue is that you are accessing request.form without checking if request.form is populated. form contains arguments in the body of the HTTP request ... and GET requests don't have a body.
As discussed in Form sending error, Flask - when Flask is asked for a form variable that doesn't exist it throws an error ... just like an ordinary Python dictionary does.
The solution in your case is to wrap all of your data-processing code inside of a conditional:
if request.method == "POST":
# code accessing request.form here
So the general structure is:
#app.route('/add_place', methods=['GET', 'POST'])
def add_place():
if request.method == "POST":
username = session['username']
placename = request.form['place']
# ... snip ...
# Note that this is not under the `if`
# so we'll *always* return this template's HTML.
return render_template('placeindex.html')

Is it possible to add facebook icons on the blog page of a Shopify site, inside of the blog loop?

I want a user to be able to like an individual article on the blog page of a Shopify site. I have added my social media icons inside of the blog loop.
blog.liquid
{% for article in blog.articles %}<!-- START ENTRY {{ forloop.index }} -->
<div id="post{{ article.id }}">
{{ article.content | strip_html | truncate: 40 }} <br/> Read More
{% assign description = article.title | escape | replace:' ','%20' %}
{% assign link = article.url %}
{% include 'social' %}
</div>
{% endfor %}
social.liquid Snippet
<div class="social-plugins">
<span class="twitter">
Tweet
<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
</span>
<span class="facebook">
<iframe src="//www.facebook.com/plugins/like.php?href={{shop.url}}{{link}}&send=false&layout=button_count&width=100&show_faces=false&action=like&colorscheme=light&font&height=21" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px; height:21px;" allowTransparency="true"</iframe>
</span>
<span class="pinterest">
Pin It
</span>
</div>
The like button works if I just put in {{shop.url}}{{blog.url}} but not when I add {{shop.url}}{{link}}. {{link}} is assigned based on the page.
In my shop - I do this by using:
{{ shop.url }}{{ article.url }}
That will return the article's URL to be inserted in the facebook/twitter/pinterest iframe.
Note: Be sure to check that the code is being rendered on the blog.liquid page. I do this in my equivalent social.liquid

Symfony 2 custom form field type: how to add javascript and css only once?

I want to use javascript in custom Symfony 2 form field type extension. So, I have Twig extension template like this:
{% block some_widget %}
<input ... />
<script src="some.js"></script>
<link href="some.css" />
{% endblock %}
But I want to have these script and link tags only once in my HTML, ideally in head tag, without modifing base template. I tried to extend Twig blocks, but I have no access to action template blocks inside form template. Or maybe something like this:
{# widget tempate #}
{% block some_widget %}
<input ... />
{{ use_javascript('some.js') }}
{{ use_css('some.css') }}
{% endblock %}
{# main action template #}
...
<head>
{{ dump_javascripts() }}
{{ dump_css() }}
</head>
...
How to do this with Symfony 2 Forms + Twig?
P.S. Sorry for my bad english.
I had to write a self contained form widget that requires javascript, I was able to achieve what you are trying to do through the event_dispatcher listening on the kernel.response to append the javascript at the end of the Symfony\Component\HttpFoundation\Response. Here's a snippet of my form type :
<?php
namespace AcmeBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
class AcmeFileType extends AbstractType{
private $twig;
private $dispatcher;
public function __construct(\Twig_Environment $twig, EventDispatcherInterface $dispatcher){
$this->twig = $twig;
$this->dispatcher = $dispatcher;
}
public function buildView(FormView $view, FormInterface $form, array $options){
$javascriptContent = $this->twig->render('AcmeBundle:Form:AcmeFileType.js.twig', array());
$this->dispatcher->addListener('kernel.response', function($event) use ($javascriptContent) {
$response = $event->getResponse();
$content = $response->getContent();
// finding position of </body> tag to add content before the end of the tag
$pos = strripos($content, '</body>');
$content = substr($content, 0, $pos).$javascriptContent.substr($content, $pos);
$response->setContent($content);
$event->setResponse($response);
});
}
...
When you define your form type in your services.yml it looks like this :
acme.form.acme_file_type:
class: AcmeBundle\Form\AcmeFileType
arguments:
- #twig
- #event_dispatcher
tags:
- { name: form.type, alias: acmefile }
So now, everytime you build a form with acmefile the javascript will be appended to the <body>. This solution does not prevent the javascript from being present multiple time though, but you should easily be able to improve this to suit your needs.
You can also play around with the $response object to modify the headers instead if you wish.
The best way is to provide the separate template with css & scripts loading.
With the comments in readme so only thing developer will must do is to
{% block stylesheets %}
{{ parent() }}
include "#MyBestBundle/Resources/view/styles.html.twig"
{% endblock %}
or try to intercept the form rendering with DI and add the assets. But it more difficult to do , if possible to implement.
My way of doing was by creating a custom twig extension where I add JS to a buffer and during form rendering and later dump it at the of my layout.
Something like this:
<?php
namespace AppBundle\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class WysiwygExtension extends AbstractExtension
{
/**
* #var array
*
* A pool of elements IDs for Wysiwyg binding.
*/
private $wysiwygElements = [];
/**
* {#inheritdoc}
*/
public function getFunctions()
{
return array(
new TwigFunction('addWysiwygBinding', [$this, 'addWysiwygBinding']),
new TwigFunction('popWysiwygBindings', [$this, 'popWysiwygBindings']),
);
}
public function addWysiwygBinding(string $id): void
{
$this->wysiwyglements[] = $id;
}
public function popWysiwygBindings(): array
{
$elements = array_unique($this->wysiwygElements);
$this->wysiwygElements = [];
return $elements;
}
}
Then form-fields.html.twig:
...
{% block wysiwyg_widget %}
{% apply spaceless %}
{{ form_widget(form) }}
{% do addWysiwygBinding(id) %}
{% endapply %}
{% endblock %}
...
Then layout.html.twig:
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
...
{% set ids = popWysiwygBindings() %}
{% if ids is not empty %}
{% javascripts
'bundles/admin/plugins/wysiwyg_1.js'
'bundles/admin/plugins/wysiwyg_2.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endif %}
{% for id in ids %}
{{ include('_wysiwyg.html.twig', { id: id }) }}
{% endfor %}
</body>
</html>
This is how I use it. Hope it's what you're looking for.
base.html.twig
<head>
{% block stylesheets %}
css...
{% endblock %}
</head>
foo.html.twig
{% extends '::base.html.twig' %}
{% block stylesheets %}
{{ parent() }}
css that you need in foo.html.twig
{% endblock %}
I found some 'dirty' method used by many peoples in other situations.
We check the loading of script on client side. In case we have a zlkladr.js file, that have a global object 'zlkladr'
{% block our_widget %}
{% spaceless %}
...
<script>
// We must load the script only once, even if many widgets on form
if ( !window.zlkladr ) {
document.write('<script src="{{ asset('bundles/kladr/js/zlkladr.js') }}"></sc'+'ript>');
}
</script>
{% endspaceless %}
{% endblock %}