How to render by Vue instead of Jinja - python

<template id="task-template">
<h1>My Tasks</h1>
<tasks-app></tasks-app>
<ul class="list-group">
<li class="list-group-item" v-for="task in list">
{{task.body|e}}
</li>
</ul>
</template>
This above is my html. I want to render the code by Vue instead.
<script>
Vue.component('tasks-app', {
template: '#tasks-template',
data: function() {
return {
list: []
}
}
created: function() {
$.getJson('/api/tasks', function(data) {
this.list = data;
})
}
})
new Vue({
el: 'body',
});
</script>
The above is my Vue code, and Jinja raise an exception that 'task' is undefined, what I hope for is that the html code rendered by Vue instead of Jinja, I know it could be done in Laravel with this:
"#{{task.body}}"
Since I am new to Jinja, could anyone help me out?

The other option is to redefine the delimiters used by Vue.js. This is handy if you have a lot of existing template code and you wish to start adding Vue.js functionality to a Flask or Django project.
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
delimiters: ['[[',']]']
})
Then in your HTML you can mix your Jinja and Vue.js template tags:
<div id="app">
{{normaltemplatetag}}
[[ message ]]
</div>
Not sure when the "delimiters" property was added, but it is in version 2.0.

You need to define parts of your template as raw so that Jinja escapes that portion instead of trying to fill it up with its own context.
Here is how you need to do it:
<template id="task-template">
<h1>My Tasks</h1>
<tasks-app></tasks-app>
<ul class="list-group">
<li class="list-group-item" v-for="task in list">
{% raw %}{{task.body|e}}{% endraw %}
</li>
</ul>
</template>
Ref: http://jinja.pocoo.org/docs/dev/templates/#escaping

If you're using Flask, you can redefine the delimiters used by Jinja:
class CustomFlask(Flask):
jinja_options = Flask.jinja_options.copy()
jinja_options.update(dict(
variable_start_string='%%', # Default is '{{', I'm changing this because Vue.js uses '{{' / '}}'
variable_end_string='%%',
))
app = CustomFlask(__name__) # This replaces your existing "app = Flask(__name__)"

You can either change default VueJS or Jinja delimiters. I actually prefer to change VueJS delimiters like below:
new Vue({
el: '#app',
delimiters: ['${', '}']
})
Then you can use ${variable} instead of conflicting {{ var }}, see docs.
This matches with ES6 template string style, so it is preferable I would say. Keep in mind that you will have to do same when you crate new components.
Alternatively, you could just bypass Jinja template rendering altogether. Just move your index.html from templates directory to static directory (next to css, js files), then:
#app.route("/")
def start():
return app.send_static_file("index.html")
If you are doing all view logic in VueJS, this can work.

Use {{ '{{ vue }}' }}
I had the same problem, and also got it solved.

Configure Vue v2 class instance with the 'delimiters' option:
<div id='myapp'> !{ message } </div>
<script>
let myapp = new Vue({ delimiters: ['!{', '}'], ...});
</script>
Source: https://v2.vuejs.org/v2/api/#delimiters

You can use directives
<h3 v-text="message"></h3>
Or you can use delimiters
const app = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
message: 'a vue message'
},
});
In your html page
<h3>${ message }</h3>

you can use {% raw %} {% endraw %} in your html code

I know this is old post, and however #Nathan Wailes answer helped me. I further tried avoiding moustaches {{myVal}} and used v-text="myVar" for rendering text. And I did not need to override jinja delimiters. see example below:
<!--Vuetify-->
<v-btn class="ma-2" outlined color="indigo" v-text="connectToggleLabel"></v-btn>
<v-btn class="ma-2" outlined color="indigo"><span v-text="connectToggleLabel"/></v-btn>
<!-- basic -->
<input type="button" :value="connectToggleLabel"/>
Hope this help somebody

Related

How do I JSON parse a Django queryset?

So I'm trying to parse each object in my Django queryset, and deal with the data through JavaScript. Below is my code (simplified) :
views.py (using Django Paginator, but the basic idea is the same.)
def main_page(request):
all_contents = Contents.objects.all()
paginator_contents = Paginator(contents,10)
page = request.GET.get('page')
all_contents_paginated = paginator_contents.get_page(page)
context = {
'contents' : contents,
'all_contents_paginated' : all_contents_paginated
}
return render(request, 'main/home.html', context)
template
{% for c in all_contents_paginated %}
<div class="text-m">
{{c.author}}
</div>
<div class="text-s" onclick="DetailModal('{{c}}')">
{{c.body}}
</div>
{% endfor %}
<script>
function DetailModal(c) {
}
</script>
Now obviously, the '{{c}}' cannot be parsed into JSON since it's string. I want to parse it into JSON in function DetailModal() and display the data in a separate modal element or do any other stuff with each data. But I can't figure out how to parse each object in the Django queryset.
Any ideas? Thanks.
you just modify your script to parse your item:
<script>
function DetailModal(c) {
const obj = JSON.parse(c);
console.log(obj.author);
console.log(obj.body);
}
</script>

Problem with updating an already updated html dom with Flask

I have a flask dropzone to upload files.
Once an upload is done I want to print a log text on the html site
It works so far, the only problem is - the div tag doesn't update the log text after the second upload. The website stays with the text from the first upload.
index.html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script>
$(function(){
window.setInterval(function() {
loadNewLogger()
}, 500)
function loadNewLogger(){
$.ajax({
url:"/write_log",
type: "POST",
datatype: "json",
success: function(data){
$(logger).replaceWith(data)
}
});
}
});
</script>
<body>
<div style="color:rgb(0, 0, 0);text-align:center">
CDR PIPELINE </div>
{{ dropzone.create(action='upload') }}
{{ dropzone.load_js() }}
{{ dropzone.config() }}
<div id="logger">
{{ logger }}
</div>
</body>
</html>
logger.html (otherwise I would render index.html twice)
<div id="logger">
{{ logger }}
</div>
excerpt from flask_app.py:
#app.route('/',methods=['POST','GET'])
def upload():
if request.method == 'POST':
f = request.files.get('file')
f.save(os.path.join(app.config['UPLOADED_PATH'],f.filename))
upload.logger = ""
es.main()
upload.logger = es.main.result
return upload.logger
return render_template('index.html')
#app.route('/write_log',methods=['POST'])
def log():
logger = upload.logger
return jsonify('', render_template('logger.html', logger=logger))
Why is it updating the text from upload.logger only once?
First of all, instead of JQuery AJAX, I would recommend using PHP. For example, when you upload files from index.html you can redirect to upload.php, and you can display the message using "echo"
But even if you aren't comfortable with that, don't get too much into Python or JQuery. Your problem can very easily be solved with plain JavaScript:
Here is your html element in logger.html:
<div id="logger"></div>
In flask app.py:
document.getElementById("logger").innerHTML="Your message to be displayed"
I would also recommend you to remove setinterval in index.html as people don't like dynamically reloading blocks

How do I display a different HTML attribute value in a Django template based on whether a mobile device is used?

I'm using Django and Python 3.7. I want to change the href in a template depending on whether a certain condition is satisfied (the user is viewing the page on a mobile device). If the user is using a regular device, the URL would be
{{ articlestat.article.path }}
Otherwise the path would be the above, except wiht the "www." replaced by "mobile.". What's the right way to do this? I have the below
{% if request.user_agent.is_mobile %}
<td align="center">Read Article</td>
{% else %}
<td align="center">Read Article</td>
{% endif %}
but it seems a little lengthy and I'm thinking there's a more concise way in Django to write all of the above.
I do not have a Django way of going about this at first glance but I do have a quick Javascript solution that you can have much more control over.
function redirect(btn, url) {
btn.on('click', function () {
window.location.href = url; // A string
})
}
var btn = <your btn>; // Use JQuery to get element as an ID
var url = <redirect url>;
redirect(btn, url);

How to use json.dumps() to render python object in Flask app?

Hi all: I'm using Flask to develop a simple web app. I have a python function that return a collection of objects that I then want to render inside a template (i.e {{ object1.value }}) in a html page. I was thinking about creating a dictionary containing the object values that would then be passed on to the page as a jsonify string through a GET request.
The Flask app looks like this:
#app.route('/')
def hello():
python_func(object1,object2,object3...)
data = json.dumps({object1.key: object1.value, object2.key: object2.value ...})
if request.is_xhr:
return jsonify(data=data)
if request.method == "GET":
return render_template('main.html',data=data)
if __name__ == '__main__':
app.run()
The html page looks like this:
<div class ="dice">
<div class ="dice-1">
<div class="card" id ="card1" >
<p>{{ data }}</p>
</div>
</div>
And script with an event button. When button is clicked the object values are updated:
<script>
$(function() {
$('#roll-button').click(function() {
$.get('/', function(data){
document.getElementById("card1").innerHTML = data.data;
})
});
});
</script>
This seems to work to pass the object values to the template. I can see a string object with all the object keys and values when I update the page.
My problem is that I don't know how to use the string inside the template. I am confused about the documentation (https://docs.python.org/3.4/library/json.html) on the subject about decoding json.
Hence this question: how can parse the string containing all the object values to render inside the template to ideally look like this: {{ object1.value }}, {{ object2.value }}, {{ object3.other_attribute }} etc...
Can I create a python dictionary from the json string for me to use in the template?
Thank you for your help!
Cam
Don't pass JSON to your template, pass a dictionary. If you want non-dynamic rendering of data in HTML go with Jinja and flask's built in stuff.
from flask import render_template
#api.route('/foo', methods=['GET'])
def foo():
my_dictionary = {'a':'b', 'foo':'baz'}
return render_template('foo.html', my_data=my_dictionary)
Then in your html template
<!DOCTYPE html>
<html lang="en-ca">
<body>
{% for key in my_data %}
<h1>{{key}}</h1>
<h1>{{my_data.key}}</h1>
{% endfor %}
</body>
</html>
If you want to make the data available as a javascript object on the client side for live updating you will have to make an ajax call and do some templating on the front-end. If you don't mind page reloads just stick with flask's templating engine.

django and dropzone how to post form

I have gone through django and dropzone. I have implemented drag and drop feature of dropzone in django.
My template look like:
<form id="add-multiple" class="dropzone" action="{% url "name_add" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
</form>
<button id="submit-all" type="submit" value="Submit" form="add-multiple">
Submit all files
</button>
<script src="{% static 'js/dropzone.js' %}"></script>
<script type="text/javascript">
Dropzone.options.myDropzone = {
// Prevents Dropzone from uploading dropped files immediately
autoProcessQueue : false,
paramName: "files",
init : function() {
var submitButton = document.querySelector("#submit-all")
myDropzone = this;
submitButton.addEventListener("click", function() {
myDropzone.processQueue();
// Tell Dropzone to process all queued files.
});
// You might want to show the submit button only when
// files are dropped here:
this.on("addedfile", function() {
// Show submit button here and/or inform user to click it.
});
}
};
</script>
Here, I am getting the css and uploading perfectly, but when I submit the form, it doesn't call the {% url "name_add" %} url. I mean, the form is not posted and it doesn't call that url.
I followed this tutorial https://amatellanes.wordpress.com/2013/11/05/dropzonejs-django-how-to-build-a-file-upload-form/ to achieve this.
First thing, my form is not being posted or it says it is not calling the url in form action. Second there is not any use of my form that I have created in forms.py to upload a file. In the tutorial also there is no use of form. Why is that and without form how form can be submitted because view requires form.
Can anyone help me?
in:
Dropzone.options.myDropzone = {
....
actually myDropzone is the camelized version of the HTML element's ID.
so the form id must be my_dropzone instead of add-multiple:
<form id="my_dropzone" class="dropzone" action...

Categories