I want to implement a ajax 'like' button which should increase the like count and not refresh the whole page. I am new to ajax so please help.
urls.py:
(r'^like/(\d+)/$',like),
Below is my views code for like:
def like(request,feedno):
feed=Feed.objects.get(pk=feedno)
t=request.META['REMOTE_ADDR']
feed.add_vote(t,+1)
vote, created = Vote.objects.get_or_create(
feed=feed,
ip=t,
)
feed.likecount+=1
feed.save()
if 'HTTP_REFERER' in request.META:
return HttpResponseRedirect(request.META['HTTP_REFERER'])
return HttpResponseRedirect('/')
Below is my html(like div):
<div class="like_abuse_box">
<p>Likes:<b>{{vote.feed_set.count}}</b> ||
<a class="like" href="/like/{{feed.id}}/">Like</a> |
<a class="abuse" href="/abuse/{{feed.id}}/">Abuse</a> || </p>
</div>
What code should I include to only refresh that particular div and updated like count be shown without the whole page getting reloaded. Need Help. Thanks.
Haven't tested it athough something like that should work. Edit: tested and works, now for multiple elements on a webapage
Javascript
$("a.like").click(function(){
var curr_elem = $(this) ;
$.get($(this).attr('href'), function(data){
var my_div = $(curr_elem).parent().find("b");
my_div.text(my_div.text()*1+1);
});
return false; // prevent loading URL from href
});
Django view
You can add if request is Ajax with:
if request.is_ajax():
First thing: put an id on the html element where the content to be injected.
<div class="like_abuse_box">
<p>Likes:<b id="like_count">{{vote.feed_set.count}}</b> ||
<a class="like" href="/like/{{feed.id}}/">Like</a> |
<a class="abuse" href="/abuse/{{feed.id}}/">Abuse</a> || </p>
</div>
second, in your view you need to return the latest like count. You can't just locally update the count, since there is a chance that someone else may have updated the like count as well.
Lastly. in your page include the jquery
$("a.like").bind("click", function(){
var link = $(this).attr("href");
$.get(link, function(data) {
$(this).parent("div").children('b#like_count').html(data);
});
});
I am not quite certain about the parent child selector, to navigate from hyper linked clicked to its corresponding like count. You may have to play around with JQuery selector to get it right.
ALso, if you are using POST for your view, replace $.get with $.post
Related
Using Ajax and Django, my data get lost when sent back to my template and I can't retrieve them.
Here is my code and the logic :
Following the dependent dropdown lists tutorial offered by ["Simple is Better Than Complex"][1]
I have implemented an Ajax request.
Here is the html code:
<p class="multiple-choice" id="mandate-city" data-url="{% url 'officials:ajax_load_mandate_city' %}">Local Mandate: {{ form.mandate_city }}</p>
The ajax request is fired from this script:
<script>
$("#id_departments").change(function (){
var url = $("#mandate-city").attr("data-url");
var departmentId = $(this).val();
$.ajax({
url: url,
data: {
'department': departmentId
},
success: function (data){
$("#id_mandate_city").html(data);
console.log(data);
}
});
});
</script>
After check with console.log, the data are collected by the script. Then, they reach the view.
Here is my view:
def load_mandate_city(request):
department_id = request.GET.get('department')
mandate_city = MandateCity.objects.filter(department_id=department_id).order_by("department")
return render(request, "officials/mandate_city_list.html", {mandate_city: mandate_city})
With a print, I have checked, and the data are treated as planned.
Then the data are sent back through the url:
path('ajax/load_mandate_city/', views.load_mandate_city, name="ajax_load_mandate_city")
They seem not to reach the template:
{% for mandate in mandate_city %}
<option value="{{ mandate.pk}}">{{ mandate.get_mandate_display }}</option>
{% endfor %}
And I could not track them in my script. :-/
Can somebody let me know where the bug is ?
Thanks.
[1]: https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html
did you try to return the information in a json object and then render it with client side js? in general when you use ajax (or fetch) you wanna use the information returned so it's better to return it as a data type,
if you do want to return the html response you should probably not use ajax but rather a form
When I am making an AJAX request to update some values the data or model is changing. But the updated model is not reflecting immediately. It is reflecting only after clicking refresh. I want to only modify a view of a div in the page. I have tried many things but not successful. Can anyone suggest me the way to solve the issue?
The git repo:
https://github.com/SyamPhanindraChavva/trell-app-front-end
templates/note.hbs
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<p><a class="dropdown-item" {{action 'updateNote' "doing" note.id}}>DOING</a></p>
<p><a class="dropdown-item"{{action 'updateNote' "done" note.id}}>DONE</a></p>
<p><a class="dropdown-item"{{action 'deleteNote' note.id}}>DELETE</a></p>
</div>
controllers/notes.js
status2:Ember.inject.service('work-status'),
actions: {
updateNote(upstatus,id){
let status1 = Ember.get(this,'status2');
status1.makeputrequest(upstatus,id);
this.toggleProperty('parameter');
}
}
services/work-status.js
makeputrequest(status1,id1)
{
$.when($.ajax ({
// get(this,'layout.referrer.owner.router').transitionTo('notes');
type: 'PUT',
url:'http://localhost:3000/notes/'+id1,
data: {note:{status:status1}},
})).then(function(result){
console.log(result);
}).catch(function(err){
console.log("you have error")
});
},
The thing I am trying to make is whenever I change the status of a record the corresponding record in the UI must also go to the corresponding table or container in UI.
Because you're using ajax calls directly in ember, you'll be responsible for setting the new properties once it's complete.
In services/work-status.js, you'll want to return the promises generated by the ajax calls.
In controllers/notes.js, chain .then to the returned promise and call and set the new property.
EG - controllers/notes.js
updateNote(upstatus,id){
let status1 = Ember.get(this,'status2');
status1.makeputrequest(upstatus,id).then((){
this.get('model').findBy('id',id).set('status',upstatus);
});
},
With that said, this isn't the correct route to take. You're mixing ember-data with plain ajax calls which is making the logic of your codebase more difficult than necessary.
If you modify your action to take the entire note as an argument, change the status, and just save the model, you wouldn't need to use the service.
// templates/note.hbs
<p><a class="dropdown-item" {{action 'updateNote' note "doing"}}>DOING</a></p>
// controllers/note.js
updateNote(note,upstatus) {
note.set('status',upstatus)
note.save();
}
Ajax is only meant if you are not trying to change something on the records. However, if you would like to change a value of your records you should be using ember-data
My Ember.js app is set up roughly like this:
Router:
App.Router.map ->
#resource('site', { path: '/' }, ->
#resource('dashboard')
#resource('account')
#resource('pages', { path: '/:page_slug'}))
Routes:
App.ApplicationRoute = Ember.Route.extend
model: ->
return App.Site.find(1)
App.PagesRoute = Ember.Route.extend
model: (params)->
return App.Page.find(params.page_slug)
EDIT:
Controller (JS not Coffee):
App.PagesController = Ember.ObjectController.extend({
needs: 'ApplicationController',
...
});
I have an ApplicationController and a PagesController. When I'm on a page, I want to call an action to delete the current page. If I place it in the PagesController it works kind of ok, but a navigation menu with a list of pages in the ApplicationView doesn't get updated until I refresh the page. So... I assume I need to place the action in the ApplicationController and add needs: ['ApplicationController'] to my PagesController.
However, when I do that, everything in my Pages template disappears.
I have an {{outlet}} in my Application template and another on in the Site template which ultimately displays the Pages template. Yeah, complicated, I know and there's probably a better way to do it, so any suggestions would be greatly appreciated. Oh and BTW, I'm a real Ember.js newb, so examples need to be spelled out explicitly. (Drawing them with pretty colors in crayon would actually be ideal.)
Thanks in advance for any help.
Here's the refresh issue. In the root resource site I'm loading in one Site model which the Rails backend returns using the url being sent in. Eventually, this app will be used with multiple domains, and each domain will be served it's own website (roughly based on the WP-Multisite concept). Then in the pages route, I'm loading one page of the site based on its slug attribute. That's all working fine. So, now I want to allow the user to be able to add and remove pages as they want.
So, the issue is this. When I delete a page at the PagesController level, the page deletes just fine, but the ApplicationController doesn't get notified. Namely, my nav menu:
<ul class="left">
{{#each page in page}}
<li>{{#link-to 'pages' page.slug}}{{page.menu_name}}{{/link-to}}</li>
{{/each}}
<li id="add-page-button"><a data-tooltip title="Click here to add a new page to your site." href="#" data-reveal-id="addPageModal" data-reveal>+</a></li>
</ul>
doesn't get notified that a page is missing and so it doesn't update the nav menu by removing that page from the list. Adding works fine, the nav list is updated when a new page is added, but I'm doing that at the ApplicationController level like so:
addNewPage: ->
# Get the site
site = #get('model')
# Get all the pages associated with the site
pages = site.get('page')
title = this.get('newTitle')
if (!title.trim())
return
slug = this.get('newSlug')
if (!slug.trim())
return
menu_name = this.get('newMenuName')
if (!menu_name.trim())
return
# Create a new page passing in our title, slug and menu_name
pages.create({title: title, slug: slug, menu_name: menu_name})
# Save the pages
pages.save()
if (pages.isError)
console.log(pages.errors)
else
#set('newTitle', '')
#set('newSlug', '')
#set('newMenuName', '')
$('#addPageModal').foundation('reveal', 'close')
And this is my deletePage code on the PagesController (sorry, I've got a mix of JS and CoffeeScript):
deletePage: function (slug) {
var page = this.get('model');
this.get('ApplicationController').deletePage(page);
this.toggleProperty('isEditingTitle');
this.toggleProperty('isShowingDeleteConfirmation');
this.transitionToRoute('site.index');
}
When I try this, Ember rather helpfully lets me know I need to add needs but again, when I do that, my Pages template is blank.
Oh yes, I have even tried setting the target attribute on the button calling the deletePage action.
I realize what I need to do is somehow access the Site model in my PagesController, but how should I go about that.
This post has taken on epic proportions. Sorry about that. Thanks again for any help.
needs doesn't do anything on the route, if you want to access a controller from a route you can just use this.controllerFor('application')
Additionally when using needs in a controller definition it should be like this needs: 'application' or needs: ['foo', 'application']...
Okay, all, I figured it out. For posterity's sake (and others who go looking for this). Here's how to delete an object in a model that has a belongsTo association.
ApplicationController:
deletePage: function () {
# First we find the Site which all pages belongTo
# Just ignore the hard-coded '1' it's something I have to do to get it to work
site = App.Site.find(1);
# Then we get the current model, i.e., the 'page' we're on and about to delete
page = this.get('model');
# Then, we get all 'pages'
pages = site.get('page');
# We remove the object from the page which updates the navigation menu
pages.removeObject(page);
# We delete the record and save the 'pages' model
page.deleteRecord();
pages.save();
}
Pages template:
{{#if isShowingDeleteConfirmation}}
<div class="large-7 large-offset-5">
<label class="inline left">Are you sure? (Can't be undone)</label>
<button {{action 'deletePage'}} class='button tiny alert'>Yes</button>
<button {{action 'cancelDeletePage'}} class='button tiny'>Cancel</button>
</div>
{{else}}
<div class="large-2 right">
<button {{action 'showDeleteConfirmation'}} class='button tiny alert'>Delete Page</button>
</div>
{{/if}}
I can show you the attributes and logic behind the if...else statement if you need me to.
Basically, the user clicks on the 'Delete' button, showing the other buttons 'yes' and 'cancel'. Once 'yes' is clicked, the deletePage action gets called.
I found very little documentation on the deleteRecord method and basically had to piece this all together myself. Perhaps there's a better way and this can be refactored. Just let me know in the comments.
I am working on using Paypal payments advanced embedded / hosted checkout pages in my django site. I display an iframe for the paypal payment page, I submit the request, and it posts back to my site.
The view that handles the paypal response uses
response = redirect("shop_complete")
return response
but this makes my whole response page pop up in the iframe. I could just use a template that would look all right in that spot, but I would like to update the cart and the payment step at the same time. Is there anyway to make that response redirect the whole browser instead of just the frame?
So, my solution wound up being to add an intermediary page that consist entirely of a script to redirect the top level of the browser. I got this script from
JavaScript post request like a form submit
<body>
<script type="text/javascript">
function post_to_url(path, params, method) {
method = method || "post"; // Set method to post by default if not specified.
// The rest of this code assumes you are not using a library.
// It can be made less wordy if you use one.
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
form.setAttribute("target", "_top" )
for(var key in params) {
if(params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
};
window.onload = post_to_url('{% url "shop_paypal_redirect" %}',
{csrfmiddlewaretoken: '{{ csrf_token }}',
result: '{{ result }}'});
</script>
</body>
I have a view which returns a chained object of 3 models
def test(request):
output=itertools.chain(
model1.objects.all(),
model2.objects.all(),
model3.objects.all()
)
return render_to_response('test.html', {'output':output})
In the html, I added an anchor and a jQuery script, which should replace the #output with new values just from model1
<html>
<head>...</head>
<body>
<script>
$(document).ready(function() {
$("#switch").click(function() {
$.ajax({
url: $(this).attr("href"),
success: function(result) {
//whatever I put here is not triggered
}
});
});
});
</script>
<a id="switch" href="?model=1">switch to model 1</a>
<div id="output">
{% for item in output %}
<div id="{{item}}">
{{item}}
</div>
{% endfor %}
</div>
</body>
</html>
I tried to put the div#output into a separate template output.html and modified the views.py like so:
def test(request, template='test.html'):
if request.GET.get('model'):
output=model1.objects.all()
else:
output=itertools.chain(
model1.objects.all(),
model2.objects.all(),
model3.objects.all()
)
if request.is_ajax(): template='output.html'
return render_to_response(template, {'output':output})
But everytime I click the link, the whole page is refreshed (with the new values from model1).
Opera returns just the output.html
Been struggling with this for more than 3 days, Im new into Ajax and this is getting very confusing for me.
I hope someone can shed some light!
First, make sure that your view works and that you're getting the expected HTML output when accessing the url directly (you might also want to comment out if request.is_ajax() temporarily).
Then, try replacing the content of the #output div using jQuery.html() method in your ajax call. Here is an example with some animation:
$.ajax({
...
success: function( returnedData ) {
$("#output").css("color", "red").fadeOut(500, function() {
$("#output").html(returnedData);
$(this).css("color", "green").fadeIn(500);
});
}
Also, try monitoring your ajax call using Firebug/Chrome Developer Tools - both tools will allow you to quickly determine the issue.
Thanks to Daniel Rosman for the heads-up I had to prevent the default action of the a#switch. It works like butter now!
Here is the initial question: how to access jQuery.ajax() get parameters in Django views