So I have a button that is suppose to "Add" an "Item" to a list and update the list on the same page without refreshing it.
Adding the Item without redirecting worked. but the element is not refreshed properly
Here is my script:
<div id="list">
{% for item in items %}
{{ item.name }}
{% endfor %}
</div>
<button id="add" type="submit">+</button>
<script>
$('#add').click(function () {
$.get('/url/page/', function (data) {
$('#list').html(data);
});
});
</script>
views.py
def add_to_list(request, item_id, list_id):
item, created = List.objects.get_or_create(list_id=list_id,
item_id=item_id)
return HttpResponse(request)
I feel like I have to add something in the views? and maybe use json code?
You should append the result of your request to the div element. Try this:
$('#add').click(function () {
$.get('/url/page/', function (data) {
$('#list').append(data);
});
});
Assuming that data that you receive from GET request is not an object but just a string. If it is an object add data.name:
$('#list').append(data.name)
Hope it helps.
Related
I'm looking for a solution to manage a HTML tag type with a Reactive Var. I looked all the Blaze documentation but found nothing..
Simple example
I want to change a tag from div to form when a boolean ReactiveVar is updated.
Template.MyExample.onCreated(function() {
this.is_form = new ReactiveVar(false)
})
Template.MyExample.helpers({
getTag() {
return Template.instance().is_form.get() ? 'form' : 'div'
}
})
This obviously didn't work:
<Template name="MyExample">
<{{getTag}}>
</{{getTag}}>
</Template>
Nicer solution ?
The "best" way I found to get it was to create a tag template and list everycase a single time, but I didn't like that solution.
Template.MyExample.onCreated(function() {
this.is_form = new ReactiveVar(false)
})
Template.MyExample.helpers({
getTag() {
return Template.instance().is_form.get() ? 'form' : 'div'
}
})
Template.MyExample.events({
'click .switch'(e, instance) {
e.preventDefault()
instance.is_form.set(!instance.is_form.get())
}
})
Blaze Templates:
<Template name="MyExample">
<div>
Switch type
{{#MyTag tag=getTag}}
Parent tag is {{getTag}}
{{/MyTag}}
{{#MyTag tag="a" attributes=(object href="#" target="_blank")}}
Link
{{/MyTag}}
</div>
</Template>
<Template name="MyTag">
{{#if equals tag 'form'}}
<form {{attributes}}>
{{> Template.contentBlock }}
</form>
{{else if equals tag 'a'}}
<a {{attributes}}>
{{> Template.contentBlock }}
</a>
<!-- and more and more.... -->
{{else}}
<div {{attributes}}>
{{> Template.contentBlock }}
</div>
{{/if}}
</Template>
Helpers required:
Template.registerHelper('object', function({hash}) {
return hash;
})
Template.registerHelper('equals', function (a, b) {
return a === b
})
This is working but i'm wondering if it's to much for Meteor (and DOM updates). Does this solution works like an simple {{#if}}...{{/if}} or it's way heavier ?
The feature you request is basically not supported by Blaze. While static code generators can easily include dynamic tags, this is a very hard one at runtime where you have to deal with the DOM tree, whose element's tag-types are immutable by design.
I first thought of a workaround, that uses child swapping using jQuery in the onRendered of MyTag:
Template.MyTag.onRendered(function () {
const instance = this
instance.autorun(() => {
const data = Template.currentData()
const attributes = data.attributes || {}
const elementName = data.tag
const refTag = instance.$('.my-tag-ref')
const newTag = $(`<${elementName}>${refTag.html()}</${elementName}>`)
Object.keys(attributes).forEach(attKey => newTag.attr(attKey, attributes[ attKey ]))
newTag.addClass('my-tag-ref')
refTag.replaceWith(newTag)
})
})
But this is unfortunately not working, because the content bock looses it's reactivity and the jQuery instance of the current Template looses it's scope to the root element. I just add it here in case someone catches up on this and finds a solution that works.
Now there is still a solution that works using dynamic Templates:
<Template name="MyTag">
{{#Template.dynamic template=getTemplate data=getData}}
{{> Template.contentBlock }}
{{/Template.dynamic}}
</Template>
<template name="mytaga">
<a {{attributes}}>
{{> Template.contentBlock }}
</a>
</template>
<template name="mytagform">
<form {{attributes}}>
{{> Template.contentBlock }}
</form>
</template>
<template name="mytagdiv">
<div {{attributes}}>
{{> Template.contentBlock }}
</div>
</template>
As you can see the disadvantage is clearly that you have to define lots of new Templates. The advantage is, that you don't have to use so many if/else anymore and it pays out the more often you will have to include MyTag in your code.
The respective helpers look like the following:
Template.MyTag.helpers({
getTemplate() {
const instance = Template.instance()
console.log(instance.data)
return `mytag${instance.data.tag}`
},
getData () {
return Template.instance().data
}
})
This is working but i'm wondering if it's to much for Meteor (and DOM updates). Does this solution works like an simple {{#if}}...{{/if}} or it's way heavier ?
Blaze is overall slower than for example React or Vue. However, the rendering only updates if the reactive data updates, thus it is just as heavy as the amount of updates to be triggered.
I have events page and event detail page.
When I place <h1>{{ Eventinfo.EventTitle }}</h1> to display title, the DOM does not get updated with new title. However, when I use <h1 [innerHTML]="Eventinfo.EventTitle"></h1>, I do get the update title in H1 tag.
Why do string interpolation <h1>{{ Eventinfo.EventTitle }}</h1> does not work?
try console in this function and reply with whatever data you are getting in console
public getEventInfo(id)
{
this.apiService.getEventInfo(id).subscribe((data : any) => {
this.Eventinfo = data.events.results[0];
});
console.log(this.Eventinfo); //view data in console
}
In a simple forum app, I have a topic page which contains multiple posts. On each post there is Like widget divs like this:
<ul>
<li>
<p id="plike_count{{post.id}}"> {{ post.likes }}</p>
</li>
<li>
{% if user.is_authenticated %}
<span data-type=" post" title="Like"> {% csrf_token %}
<i class="thumbs-up" id="likep" name="{{ post.id}}"> </i>
{% endif %}
</li>
</ul>
And here is the ajax Like snippet that is supposed to capcher each Like and update the like counts:
$(function(){
$('#likep').click(function(){
$.ajax({
type: "POST",
url: "/forum/post/like/",
data: {
'post_id': $(this).attr('name'),
'csrfmiddlewaretoken': '{{csrf_token}}'
},
success: plikeSuccess,
dataType: 'html'
});
});
});
function plikeSuccess(data, textStatus, jqXHR)
{
$('#plike_count').html(data);
}
A very similar ajax code works fine when there is only one post/div to work with but I don't know how to generalize the code for multiple posts.
So the problem is how make an id corresponding to plike_count{{post.id}} in ajax?
I've tried $('#plike_count'.conc(post_id)).html(data); instead of $('#plike_count').html(data); but it did not work.
Use
$(function(){
$('#likep').click(function(){
var _self = this;
$.ajax({
type: "POST",
url: "/forum/post/like/",
data: {
'post_id': $(this).attr('name'),
'csrfmiddlewaretoken': '{{csrf_token}}'
},
success: function (data, textStatus, jqXHR)
{
$("#plike_count"+$(_self).attr('name')).html(data);
},
dataType: 'html'
});
});
});
You're looking for the wonders of the + operator, which concatenates strings:
"a" + b
The trick is to use the context from the original click event in your ajax callback.
We do this by creating a variable within the click handler which binds the context. Also note that we use the fact that all the jQuery ajax methods return a promise object.
Instead of passing a named function to the success option we instead call the .done method on the promise. Many would say that creating a named function in the global namespace for a jQuery callback is a huge antipattern.
Note that we also use a bit more structured html so that we treat the likes as a reusable module of code.
$('.like').on('click', function(e){
var $btn = $(this);
var promise = $.post({
url: $btn.attr('href'),
data: {
id: $btn.data('id'),
csrfmiddlewaretoken: '{{csrf_token}}'
},
dataType: 'html'
});
promise.done(function(jqXHR){
$btn.parents('.like-module')
.find('.like-counter')
.html(jqXHR.responseText());
});
e.preventDefault(); // prevent following link.
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="post">
<aside class="like-module">
<div class="like-counter">0</div>
<a href="/forum/post/like/" class="like" data-id="{{ post.id }}">like</div>
</aside>
</div>
<!-- more posts --!>
Added.
Also I belive a more RESTful design would be:
POST /forum/posts/:id/likes # to like a post
DELETE /forum/posts/:id/likes # to unlike a post
POST /forum/post/likes smells like a procedure and not something which acts on a resource.
I'm trying to launch a modal if my flask-wtf form validation fails. The code snippet below otherwise works as expected other than it launches the modal even when I load the form before submission (appears that form.errors initialises to False before form is submitted).
What do I need to change get the modal to show iff form is submitted and form validation is successful?
<script>
var formSuccess = {% if form.errors %}false{% else %}true{% endif %};
$(document).ready(function() {
if (formSuccess) {
$('.modal').modal('show');
}
});
</script>
I resolved this by passing a validation_success variable when checking
if form.validate_on_submit() within the calling routine. I then pick this value up using jija:
<script>
var formSuccess = {% if validation_success %}true{% else %}false{% endif %};
$(document).ready(function() {
if (formSuccess) {
$('.modal').appendTo("body").modal('show');
}
});
</script>
I have this template tags in my html code
{{ djangoVar}} //Django template tag
{$ angularVar $} //AngularJS template tag
How can I assign {{ djangoVar}} to {$ angularVar $} in my html?
Something like:
{% {$ angularVar $} = djangoVar %}
The angularVar must be assigned with javascript code. So, in your django template you can do something like
<script>
var django_variables = {};
django_variables.djangoVar = {{ djangoVar }};
</script>
So you declare a django_variables global variable. Then, in your angular controllers you can do:
function MyController($scope) {
$scope.angularVar = django_variables.djangoVar;
}
The important thing is to run the 1st snippet inside a normal django html template that the context will be passed and {{ djangoVar }} will get its value.