I have found into on how to change your quantity of items via AJAX on the cart page, and I have also found how to update the cart total via AJAX.
What I have not found is how to update the total line item price for each line item as you increase or decrease the quantity.
Here is the code I have thus far (not working) ...
jQuery.getJSON('/cart.js', function(cart) { $('#line-total-{{ item.id }}').html(Shopify.formatMoney(item.line_price).replace('$','£'))})
Any tips on what is wrong with my code?
Also this is within an onclick on a button if that helps.
Your code includes:
jQuery.getJSON('/cart.js', function(cart) {
$('#line-total-{{ item.id }}').html(Shopify.formatMoney(item.line_price).replace('$','£'))})
The above will not work, as the Liquid-based {{ item.id }} will get dropped once into the page, never to change afterwards. (Most likely, the above code was included in a place where there was no Liquid variable named item in scope, so the rendered Javascript would have simply read $('#line-total-')
You'll need to use the Javascript cart object that is being given to your function. For example:
jQuery.getJSON('/cart.js', function(cart) {
for(var i=0; i<cart.items.length; i++){
var item = cart.items[i];
var price_element = $('#line-total-' + item.id)
price_element.html(Shopify.formatMoney(item.line_price).replace('$','£'))})
}
})
Hope this helps!
You're getting "cart" back from /cart.js but you're not reading any of its data.
You will need to read through the cart object (which will be represented as a shopify "Cart" object) in your javascript. I see you're trying to get the "item.id" and "item.line_price", but there is not relationship to the item and the cart object. You also cannot use liquid at this point as this will already be rendered to the client...
You likely need to do something similar to:
jQuery.getJSON('/cart.js', function(cart) { cart.items.each($('#line-total-'+this.id).html(Shopify.formatMoney(this.line_price).replace('$','£')););});
Related
There is an issue I am facing in using pagination widget with ajax. What I am doing is, that I select category and then hit an ajax request to fetch the corresponding list by loading the data in the template and returning the html like this:
<f:if condition="{articles}">
<f:then>
<f:widget.paginate objects="{articles}" as="paginatedArticles" configuration="{itemsPerPage: numberOfRecords}">
<f:for each="{paginatedArticles}" as="article">
<h2>
<f:link.action action="show" arguments="{article : article}"> {article.title}</f:link.action>
</h2>
<p>
<f:format.html>{article.description}</f:format.html>
</p>
<hr/>
</f:for>
</f:widget.paginate>
</f:then>
<f:else>
No Records Found
</f:else>
And in my controller in my ajaxMethod I am simply doing
$this->view->assign('articles', $result); so it loads up the template with my result.
But now after rendering the ajax, if I use the pagination, the view breaks. There is no styling or header or anything.
This is how it shows up when I click the next on paginate widget: http://prntscr.com/kr8vg0
Just for completeness, here is the setup.txt which I have written that calls the ajax.
// PAGE object for Ajax call:
tt_content.list.20 = CASE
tt_content.list.20 {
key.field = list_type
}
ajax = PAGE
ajax {
typeNum = 1272
config {
disableAllHeaderCode = 1
disablePrefixComment = 1
additionalHeaders {
1526302502.header = Content-Type: text/html;charset=utf-8
}
}
10 = CONTENT
10 {
table = tt_content
select {
pidInList = this
orderBy = sorting
where = (list_type IN ("articleext_list"))
}
renderObj = < tt_content.list.20
}
}
Any help would be appreciated.
The typeNum that drives (should drive) XHR requests from widgets, is added from within the Fluid extension and does not require you to add a special PAGE object.
Even if you somehow made overrides that call your specific controller action it may not be treated correctly. Usually you would never refer to a content element instance but rather a straight Extbase request bootstrapping. Among other things, because rendering the content object adds wrappers.
So you should remove this and make sure you pass a QueryResult to the pagination widget. Then override the widget template if necessary. The rest should work without having to configure TS.
EDIT:
The pagination widget itself being used in a template that is rendered via XHR means it transfers the arguments you use to load the XHR - including the custom typeNum value. The widget then creates standard links that your click like normal - and they will be a link to the "inner content" of your XHR response because the URL contains a type number.
Here's where it gets bad: you cannot remove this typeNum once it is added. So you will have to instead cause the next/prev etc. links that are clicked, to cause a new XHR request that loads the content (how you do that very much depends on your JS application so can't guide you there).
My comment about ensuring a QueryResult is not relevant unless your pages don't change and you for example always see items 1-10.
But in order to solve this I would actually recommend that you do not use the pagination widget. The main reason being you're already in an XHR context that allows you to receive arguments for your controller action and manipulate the offset and limit parts of the query from within your controller action. That means you can generate your links not to the widget but to the controller action, and for example put a CSS class on the links that should trigger XHR requests vs. those that should reload the entire page (for example to show a detail view). You avoid having to override the pagination template and you control all parameters of all links.
In fact, I would favor a controller argument for offset above using the pagination widget regardless of XHR or not. There's a long list of technical reasons why that I won't list here but suffice it to say, trading a lot of "black box" for having to create a single argument is a very reasonable and predictable-result thing to do.
This is driving me crazy. I am building an ecommerce app, with the cart in Django-carton. When I add an item to the cart, I can get the item's id from the context into the store, and pass it into my Ajax call and to the view when a customer adds the item with a button click.
I want the customer to be able to delete and edit quantities in the cart using a button, and am now trying to create my delete and my edit quantity functions. I'm stuck because I don't understand how to pass the id the the view in Ajax. The id isn't in the item context object. I can get the id in the view by printing ids = request.session['CART'], but it does not have the current id. The items in context are limited to the following:
self.product = product
self.quantity = int(quantity)
self.price = Decimal(str(price))
The example in Django-carton's documentation has this example, which doesn't use Javascript:
views:
def remove(request):
cart = Cart(request.session)
product = Product.objects.get(id=request.GET.get('id'))
cart.remove(product)
return HttpResponse("Removed")
urls:
u`rl(r'^remove/$', 'remove', name='shopping-cart-remove'),`
In my view, I can get the ids of all of the objects in the cart with
cart = Cart(request.session)
ids = request.session['CART']
which gives me the following object:
{u'meal_pk': 15, u'price': u'5', u'quantity': 39}
But this doesn't actually seem helpful. This is my first encounter with sessions. I've been reading through the code here https://github.com/lazybird/django-carton/blob/master/carton/cart.py How can I edit or delete an item in my cart?
You can still call the remove view via AJAX quite easily with Javascript; unless otherwise specified, the view does not care if the request is submitted via AJAX. So, we can set that up easily w/ JQuery.
So, in a template showing the shopping cart, for example:
{% load carton_tags %}
{% get_cart as cart %}
<script type="text/javascript" src="path/to/jquery.js">/script>
{% for item in cart.items %}
<a onclick='AjaxRemove("{% url 'shopping-cart-remove' %}?id={{ item.product.id }}")'>Remove this item</a>
{% endfor %}
<script type="text/javascript">
function AjaxRemove(remove_url) {
$.ajax({
url: remove_url,
success: function(response) {alert(response);},
error: function() {alert("Couldn't remove item");}
})
</script>
will remove the item and give an alert if the AJAX request responds with success.
You can further customize the view response to respond differently to AJAX requests using request.is_ajax():
def remove(request):
cart = Cart(request.session)
product = Product.objects.get(id=request.GET.get('id'))
cart.remove(product)
if request.is_ajax():
# do something, respond differently
return HttpResponse("Removed (via AJAX)")
return HttpResponseRedirect(reverse('shopping-cart-show'))
i'm in the nth hour of trying the following: i'd like to add text/html snippets before the title of an event as displayed in the fullcalendar (i.e. inside of <div class="fc-event-title">). These snippets would be one of the following:
<span class="info">registration needed</span>
<span class="cancelled">course cancelled</span>
<span class="ok">held as planned</span>
blank value/no additional text
I tried to copy wp-fullcalendar.php into my theme's directory hoping to be able to edit the function but couldn't accomplish to overwrite the original file - anyplace i tried to put it.
I then tried working in the source file, for a test i did (line 199 in original wp-fullcalendar.php):
$title = 'LLL' . $post->post_title; which did nothing to the output in the calendar.
After a while i completely removed the function 'function ajax()' from wp-fullcalendar.php and the calendar still displays just fine. Seems to be the wrong place (which it is anyway as it's a source file, i know).
I was hoping to find a quick way to accomplish my task but as you can see i'm stuck.
Any help on the matter would be highly appreciated. Thank you,
Frank
Update:
i added a custom attribute 'Kurstyp' to each Event.
possible values for it are: empty string (ie no extra span), 'please register', 'event cancelled', 'held as planned'
i would like all non empty values to appear within <div class="fc-event-title">
best each wrapped in a span with an individual class for styling purposes
this is what i added to wp-fullcalendar.php:
add_action('wp_ajax_wpfc_custominfo',array('WP_FullCalendar','custominfo') );
add_action('wp_ajax_nopriv_wpfc_custominfo', array('WP_FullCalendar','custominfo') );
// and further down
function custominfo() {
if( !empty($_REQUEST['post_id']) ){
$return = get_post_meta($_REQUEST['post_id'], 'Kurstyp', true);
}
echo apply_filters('wpfc_custominfo', $return);
die();
}
// then, inside the event.render part within fullcalendar_args
if(event.post_id > 0) {
alert('event.title (1st): ' + event.title);
var custominfo = {action: 'wpfc_custominfo', post_id: event.post_id};
var extra = $.ajax({
url: WPFC.ajaxurl,
type: "POST",
data: custominfo
});
extra.done(function(addtxt) {
event.title = addtxt + event.title;
alert('event.title (2nd): ' + event.title);
});
}
alert('event.title (3rd): ' + event.title);
addtxt delivers the correct value but my 3rd alert fires before the 2nd one, so event.title remains unchanged
all of this takes place in the original source, i'd want to change this even if it worked
also, even if it worked: how to style the different messages accordingly?
might the attribute className of the Event Object be helpful and if so, how?
The Texts used would be german, tried to use english here for better reading.
Thanks for your help, Frank
I've been googling for hours but surprisingly I didn't find any topic on that subject.
I have the following Form
class propertyType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('city')
->add('district', 'entity', array('class'=>'FlatShanghaidefaultBundle:district',
'property'=>'name',
'query_builder' => function ($repository) {
$qb = $repository->createQueryBuilder('district');
$qb->add('where', 'city = :city');
$qb->setParameter('city', 1);
return $qb;
}
public function getName()
{
return 'property';
}
}
When the user choose a City in the form, I want the options of district to be dynamically updated and limited to that city. With Ajax or JS?
What would be the best practice? Do you know a tutorial on that topic?
If someone can put me on the right tracks, that would help a lot..
Thanks!
The query builder will not solve your problem, you can remove it altogether.
That query is run when the form gets built, once you have it on your browser you need to use javascript to populate the options.
You can have the options stored in a javascript variable, or pull them from the server as needed with ajax (you will need a controller to handle these ajax requests).
You will probably want to use some jquery plugin to handle the cascading logic between the select elements, there are a couple available:
I use this one, but it seems to be offline: http://devlicio.us/blogs/mike_nichols/archive/2008/05/25/jquery-cascade-cascading-values-from-forms.aspx
And there is this one, which I never used really: http://code.google.com/p/jquery-cascade/
There is also at least this Bundle I know of: https://github.com/genemu/GenemuFormBundle, which has ajax field types available for several jquery plugins. This may save you writing the ajax part to handle the data, as it comes built in (it's probably easier to implement the controller your self anyway). I haven't tried this one, and I don't know if it has cascading support.
Jbm is right about the query builder. And his approach is perfecly valid.
Another option could be to dispense the cascade select in favor of an autocomplete field.
Assuming that you save the countries, cities and districts as entities and have a relation between them, you do not even need to save what city/country has been selected because you can just call:
$district->getCity()->getCountry();
I have implemented a similar thing for country/city selection and will link here to the the main involved files.
First, create a custom form type to encapsulate all form stuff, it contains a hidden field to store the selected id and a text field to serve as input for the autocomplete logic:
https://github.com/roomthirteen/Room13GeoBundle/blob/master/Form/LocationFieldType.php
Then theme the form type:
https://github.com/roomthirteen/Room13GeoBundle/blob/master/Resources/views/Form/fields.html.twig
The url of the autocomplete source is passed as data attribute so no JS will be smutching the html code.
Last but not least, the JS functions have to be implemented:
https://github.com/roomthirteen/Room13GeoBundle/blob/master/Resources/public/jquery.ui.location-autocomplete.js
The result can be seen in the image below, see that for clarity the country name will be displayed in braces behind the city name:
--
I favor this solution much more that using cascade selects because the actual value can be selected in one step.
cheers
I'm doing this myself on a form.
I change a field (a product) and the units in which the quantity can be measured are updated.
I am using a macro with parameters to adapt it more easily.
The macro :
{% macro javascript_filter_unit(event, selector) %}
<script>
$(function(){
$('#usersection')
.on('{{ event }}', '{{ selector }}', function(e){
e.preventDefault();
if (!$(this).val()) return;
$.ajax({
$parent: $(this).closest('.child_collection'),
url: $(this).attr('data-url'),
type: "get",
dataType: "json",
data: {'id' : $(this).val(), 'repo': $(this).attr('data-repo'), parameter: $(this).attr('data-parameter')},
success: function (result) {
if (result['success'])
{
var units = result['units'];
this.$parent.find('.unit').eq(0).html(units);
}
}
});
})
});
</script>
{% endmacro %}
The ajax returns an array : array('success' => $value, 'units' => $html). You use the $html code and put it in place of the select you want to change.
Of course the javascript code of the ajax call need to be modfied to match your fields.
You call the macro like you would normally do:
{% import ':Model/Macros:_macros.html.twig' as macros %}
{{ macros.javascript_filter_unit('change', '.unitTrigger') }}
So I have two arguments : the event, often a change of a select. and a selector, the one whose change triggers the ajax call.
I hope that helps.
Well, I have been looking everywhere for hours and hours and it seems like there's so many ways to do this, since I have never used Ajax before and have little knowledge of havascript, its become too hard for me.
I have the loop on my front page (index) or wordpress and I want to have a filter, a dropdown menu with different categories, that when clicked, the only posts showing in that same screen are the ones from that category. I need the loop to be refreshed with ajax, so the whole page is still left intact while you use the filter.
this is what i have on my Index file:
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.2.6")</script>
<script type="text/javascript">
$(function(){
$('#main_cat').change(function(){
var $mainCat=$('#main_cat').val();
$("#sub_cat").empty();
// call ajax
$.ajax({
url:"<?php bloginfo('wpurl'); ?>/wp-admin/admin-ajax.php",
type:'POST',
data:'action=my_special_ajax_call&main_catid=' + $mainCat,
success:function(results)
{
// alert(results);
$('#sub_cat *').fadeOut(500);
$('#sub_cat + p').fadeOut(500);
$("#sub_cat").append(results);
$('#sub_cat').load('http://localhost:8888/public_html/wp-content/themes/twentyten-child/templateloop.php');
$('#sub_cat + p').fadeIn(1);
}
});
}
);
});
The dropdown with the categories goes like this:
<?php
wp_dropdown_categories('show_count=0&selected=-1&hierarchical=1&depth=1&hide_empty=0&exclude=1&show_option_none=Main Categories&name=main_cat');
?>
So, the dropdown works, and it's supposed to ajax load a wp template file with a query filtering only one category (grabbed from the wp_dropdown_categories). And the loading works fine if I have a dummy text in the templateloop.php file, but when I have the wp query, nothing happens. the #sub_cat div, which is where the loop is located and was supposed to be switched by the template file just dissapears with all the post listing and im left only with the top half of the page (until where the #sub_cat div used to be).
There has been so much trial and error, ive tried with the query call in the template file, in the index file, in the functions, i never seem to get any result.
on my functions.php file ive got this:
function implement_ajax() {
if(isset($_POST['main_catid']))
{
echo '<?php $paged = (get_query_var("paged")) ? get_query_var("paged") : 1; query_posts("cat='.$_GET['maincatid'].'&paged=$paged"); ?>';
die();
} // end if
}
add_action('wp_ajax_my_special_ajax_call', 'implement_ajax');
add_action('wp_ajax_nopriv_my_special_ajax_call', 'implement_ajax');//for users that are not logged in.
and the query line i used to use before all this, in the index file is:
<?php $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts("cat=1,2,3,4,5&paged=$paged"); ?>
i've tried using the wp_query but it's just going nowhere, i really need guidance. Any help is appreciated. thank you.
That is more complicated than it needs to be. You shouldn't need additional queries or AJAX at all. If you theme is using the post_class() function as it should be, your posts all have classes associated with your categories. These classes are the category name prepended with 'category-'-- 'category-uncategorized', for example. All you really need to do is show and hide posts based on those classes.
I haven't written anything specifically for your circumstance but I have done this with some very large search results-- sometimes 400 or more per page-- and it works quite well. Here is the idea: Use jQuery to watch your select menu. You want change. When the select changes, parse the information to work out the category (I don't know off hand what information wp_dropdown_categories() includes in its markup.), show() the selected category and hide() everything else.