I am working on opencart. I dont want my users to buy multiple products they can buy only 1 product with 1 customer id, so for this i want my add to cart button to help me. I want this button to be disabled (read only) if add to cart process is performed successfully.
HTML:
<button type="button" id="button-cart" data-loading-text="<?php echo $text_loading; ?>" class="btn btn-primary btn-lg btn-block"><?php echo $button_cart; ?></button>
Jquery:
<script type="text/javascript"><!--
$('#button-cart').on('click', function() {
$.ajax({
url: 'index.php?route=checkout/cart/add',
type: 'post',
data: $('#product input[type=\'text\'], #product input[type=\'hidden\'], #product input[type=\'radio\']:checked, #product input[type=\'checkbox\']:checked, #product select, #product textarea'),
dataType: 'json',
beforeSend: function() {
$('#button-cart').button('loading');
},
complete: function() {
$('#button-cart').button('reset');
},
success: function(json) {
$('.alert, .text-danger').remove();
$('.form-group').removeClass('has-error');
if (json['error']) {
if (json['error']['option']) {
for (i in json['error']['option']) {
var element = $('#input-option' + i.replace('_', '-'));
if (element.parent().hasClass('input-group')) {
element.parent().after('<div class="text-danger">' + json['error']['option'][i] + '</div>');
} else {
element.after('<div class="text-danger">' + json['error']['option'][i] + '</div>');
}
}
}
if (json['error']['recurring']) {
$('select[name=\'recurring_id\']').after('<div class="text-danger">' + json['error']['recurring'] + '</div>');
}
// Highlight any found errors
$('.text-danger').parent().addClass('has-error');
}
if (json['success']) {
$('.breadcrumb').after('<div class="alert alert-success">' + json['success'] + '<button type="button" class="close" data-dismiss="alert">×</button></div>');
$('#cart > button').html('<i class="fa fa-shopping-cart"></i> ' + json['total']);
$('html, body').animate({ scrollTop: 0 }, 'slow');
$('#cart > ul').load('index.php?route=common/cart/info ul li');
}
}
});
});//--></script>
I know this will do the trick
$(this).attr('disabled', true);
But iam not finding the best position for it. I want the button to be disabled if the validation is all done and product is entered in cart area
jQuery.attr()
Get the value of an attribute for the first element in the set of matched elements.
whereas,
jQuery.prop()
Get the value of a property for the first element in the set of matched elements.
Before jQuery 1.6 , the attr() method sometimes took property values into account when retrieving some attributes, which caused in inconsistent behavior. And thus, the prop() method was introduced. As of jQuery 1.6. , the .prop() method provides a way to explicitly retrieve property values, while .attr() retrieves attributes.
According to your code you are highlighting error by $('.text-danger').parent().addClass('has-error');. So
you can use prop('disabled', true) instead of $(this).attr('disabled', true); and add it to just after $('.text-danger').parent().addClass('has-error');
$('.text-danger').parent().addClass('has-error');
$(this).prop('disabled', true)
I see that you are relying on the response from your service call to validate success or error.
In that case it will be better to disable the button as soon as your service is called, and wait for response.
After response if your validation is successful, then no worries, else re-enable button and notify user the error and ask to make changes if required.
So the code could be like this,
$('#button-cart').on('click', function() {
var _button_ref = this;
$(_button_ref).attr('disabled', true);
$.ajax({
url: 'index.php?route=checkout/cart/add',
type: 'post',
data: $('#product input[type=\'text\'], #product input[type=\'hidden\'], #product input[type=\'radio\']:checked, #product input[type=\'checkbox\']:checked, #product select, #product textarea'),
dataType: 'json',
beforeSend: function() {
$('#button-cart').button('loading');
},
complete: function() {
$('#button-cart').button('reset');
},
success: function(json) {
$('.alert, .text-danger').remove();
$('.form-group').removeClass('has-error');
if (json['error']) {
// your logic
$(_button_ref).attr('disabled', 'false');
}
if (json['success']) {
// your logic
}
}
});
Also, it will be better if you have error call back function, to handle if service fails.
Related
Need an help to solve the issue, got stuck and invested a lots of time.
What I am doing here,
I am submitting form using post traditional method but before the submitting the form, I am using the above jquery ajax code to do some operation and it's working fine.
Using this code when some one click on button, I want to show loader but it do not show because of using async:false in jquery ajax. It shows the loader after completing the ajax success.
In this case it seems for there is nothing happening and no loader works just after click of button.
Html code for showing loader is like this
<button type="submit" id="submit" class="btn btn-primary add_campaign_handler_button" name="submit">
<i class="fa fa-spinner fa-spin" id="url_button_loader" style="display:none;"></i>
Save Settings
</button>
jQuery:
$("#submit").click(function() {
$('#url_button_loader').css('display', 'inline-block');
var submit_flag = "yes";
var where_to_appear_for_db = "";
/* create custom post url */
var post_name = $("#custom_post_slug").val();
if (post_name != "") {
var data = {
data: post_name
};
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
'action': 'create_custom_post_url',
'data': data
},
beforeSend: function() {
$('#url_button_loader').css('display', 'inline-block');
},
async: false,
success: function(response) {
if (response == "exists") {
Swal.fire({
type: 'error',
title: 'Oops...',
text: wpmlBackObj.smart_link_exists
});
$("#retargeting_url").val("");
submit_flag = "no";
$('html,body').animate({
scrollTop: 0
});
return;
}
$("#tooltip_error").hide();
$("#campaign_post_id_hidden").val(response);
get_retargeting_url(response, "");
}
});
if (submit_flag == "yes") {
return true;
} else {
$('#url_button_loader').css('display', 'none');
return false;
}
});
});
Using this code when some one click on button, I want to show loader but it do not show because of using async:false in jquery ajax. It shows the loader after completing the ajax success.
This is why async: false is deprecated.
It locks up the UI completely.
If you want to do anything while the request is being made, don't use async: false.
Instead: Always prevent the default behaviour, and then (if desired) retrigger it once the async operation is complete.
For the past few days I have been trying to populate the Google Tag Manager datalayer on the OpenCart product page when the button "Add to Cart" is clicked.
I understand that I need to use the push method, but I can't figure out where to nest it since I have no HTML button just a JavaScript function.
The function:
<script type="text/javascript"><!--
$('#button-cart').on('click', function() {
$.ajax({
url: 'index.php?route=checkout/cart/add',
type: 'post',
data: $('#product input[type=\'text\'], #product input[type=\'hidden\'], #product input[type=\'radio\']:checked, #product input[type=\'checkbox\']:checked, #product select, #product textarea'),
dataType: 'json',
beforeSend: function() {
$('#button-cart').button('loading');
},
complete: function() {
$('#button-cart').button('reset');
},
success: function(json) {
$('.alert, .text-danger').remove();
$('.form-group').removeClass('has-error');
if (json['error']) {
if (json['error']['option']) {
for (i in json['error']['option']) {
var element = $('#input-option' + i.replace('_', '-'));
if (element.parent().hasClass('input-group')) {
element.parent().after('<div class="text-danger">' + json['error']['option'][i] + '</div>');
} else {
element.after('<div class="text-danger">' + json['error']['option'][i] + '</div>');
}
}
}
if (json['error']['recurring']) {
$('select[name=\'recurring_id\']').after('<div class="text-danger">' + json['error']['recurring'] + '</div>');
}
// Highlight any found errors
$('.text-danger').parent().addClass('has-error');
}
if (json['success']) {
$('.breadcrumb').after('<div class="alert alert-success">' + json['success'] + '<button type="button" class="close" data-dismiss="alert">×</button></div>');
$('#cart > button').html('<i class="fa fa-shopping-cart"></i> ' + json['total']);
$('html, body').animate({ scrollTop: 0 }, 'slow');
$('#cart > ul').load('index.php?route=common/cart/info ul li');
}
},
error: function(xhr, ajaxOptions, thrownError) {
alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
}
});
});
I turned the internet up side down but found no solution to this. Any help is appreciated.
In the code from your question you have already initialized the click handler for the "Add to cart" button. Put your dataLayer logic inside the click handler.
$('#button-cart').on('click', function() {
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event': 'button-add-to-cart-click'
});
// other code
});
HTML:
<a class="mr-2 mb-2 btn btn-outline-primary btn-sm" onclick="edit_init(this)" href="#4CE10703YB"><i class="ti-info"></i></a>
jQuery:
function edit_init(anchor){
$("#edModal").html("");
ref = anchor.href.substr(anchor.href.lastIndexOf('/') + 1);
ref = ref.replace(/^#/, "");
$.post("modal.php",{ajax_get_edModal:1,ajax_modal_for:ref},function(data){
$("#edModal").html(data);
});
}
So everything is working fine, but now I want to change the html() inside that anchor tag to something like "loading.." and disable it during the duration of the ajax request.
You can apply below changes to your function, in order to achieve your task.
function edit_init(anchor){
$prevHtml = $(anchor).html();
$href = $(anchor).attr('href');
$(anchor).removeAttr('href');
$(anchor).html('Loading....');
$(anchor).attr('disabled',true);
$("#edModal").html("");
ref = anchor.href.substr(anchor.href.lastIndexOf('/') + 1);
ref = ref.replace(/^#/, "");
$.post("modal.php",{ajax_get_edModal:1,ajax_modal_for:ref},function(data){
$("#edModal").html(data);
$(anchor).html($prevHtml);
$(anchor).removeAttr('disabled');
$(anchor).attr('href',$href);
});
}
Use beforeSend to do something while ajax request, for example:
$.ajax({
type: 'post',
url: 'example.php',
data: form.serialize(),
beforeSend: function() {
$('.yourTag').html('loading...');
},
success: function(data) {
$('.yourTag').html(data);
},
error: function() {
$('.yourTag').html('error');
}
});
Could someone please explain this console error and how I can fix it?
Uncaught Error: cannot call methods on button prior to initialization; attempted to call method 'loading'
This is the page where it's occurring, when clicking the add to cart button & viewing the console in chrome developer tools:
http://tinyurl.com/pqb7wyr
Cart Button:
<button type="button" id="button-cart" data-loading-text="Loading..." class="btn btn-outline-inverse">Add to Cart</button>
Javascript:
<script type="text/javascript"><!--
$('#button-cart').on('click', function() {
$.ajax({
url: 'index.php?route=checkout/cart/add',
type: 'post',
data: $('#product input[type=\'text\'], #product input[type=\'hidden\'], #product input[type=\'radio\']:checked, #product input[type=\'checkbox\']:checked, #product select, #product textarea'),
dataType: 'json',
beforeSend: function() {
$('#button-cart').button('loading');
},
complete: function() {
$('#button-cart').button('reset');
},
success: function(json) {
$('.alert, .text-danger').remove();
$('.form-group').removeClass('has-error');
if (json['error']) {
if (json['error']['option']) {
for (i in json['error']['option']) {
var element = $('#input-option' + i.replace('_', '-'));
if (element.parent().hasClass('input-group')) {
element.parent().after('<div class="text-danger">' + json['error']['option'][i] + '</div>');
} else {
element.after('<div class="text-danger">' + json['error']['option'][i] + '</div>');
}
}
}
if (json['error']['recurring']) {
$('select[name=\'recurring_id\']').after('<div class="text-danger">' + json['error']['recurring'] + '</div>');
}
// Highlight any found errors
$('.text-danger').parent().addClass('has-error');
}
if (json['success']) {
$('#notification').html('<div class="alert alert-success">' + json['success'] + '<button type="button" class="close" data-dismiss="alert">×</button></div>');
$('#cart-total').html(json['total']);
$('html, body').animate({ scrollTop: 0 }, 'slow');
$('#cart > ul').load('index.php?route=common/cart/info ul li');
}
}
});
});
//--></script>
I've read that I should reorder scripts to load boostrap js after all jquery and jquery plugins js to resolve the error, but this didn't fix it.
For me it was fixed by placing jquery-ui.min.js file before bootstrap.js
Just click ctrl+u on page you receive error and check in <head> part if jquery-ui file is called after bootstrap.js
This may be the cause of error.
Placing jquery-ui before calling bootstrap.js will fix the issue.
Try initializing #button-cart as a button before the beforeSend event fires
$('#button-cart').button().on('click', function() {
get a problem with after success ajax and load the div.
Here's the code:
<script>
$('.delete').click(function(e){
e.preventDefault();
var id = $(this).attr('id');
if (confirm('Delete this user?') == true) {
$.ajax({
type: "POST",
data: {_method: "DELETE"},
url: 'manage-staff-roles/' + id, //resource
beforeSend: function(){
$('.loader-wrap').removeClass('hiding hide');
},
success: function() {
$('.loader-wrap').addClass('hiding hide');
$('#table').load(location.href + " #table");
Messenger().post({
message: 'Success.',
type: 'success',
showCloseButton: true
});
}
});
}
else
{
return;
}
});
</script>
Here is my html:
<div id="table">
#foreach($staffroles as $staffrole)
{{ $staffrole->id }}
{{ $staffrole->name }}
<a class="edit" id="staffroles/{{ $staffrole->id }}/edit" href="manage-staff-roles/{{ $staffrole->id }}/edit">
Edit </a>
|
<a class="delete btn" id="{{ $staffrole->id }}" >
Delete </a>
#endforeach
</div>
after the ajax success and do all the function perfectly (including reload the specific div). But the problem is my div that contain a delete button is become unusable but the edit button is working).
You need to add click handler using .on() for dynamically created buttons. Modify your delete button click handler as shown below
$(document).on('click','.delete',function(e){
e.preventDefault();
var id = $(this).attr('id');
if (confirm('Delete this user?') == true) {
$.ajax({
type: "POST",
data: {_method: "DELETE"},
url: 'manage-staff-roles/' + id, //resource
beforeSend: function(){
$('.loader-wrap').removeClass('hiding hide');
},
success: function() {
$('.loader-wrap').addClass('hiding hide');
$('#table').load(location.href + " #table");
Messenger().post({
message: 'Success.',
type: 'success',
showCloseButton: true
});
}
});
}
else
{
return;
}
});
The problem is that the .load method of jQuery, will add new html and this will override any event handlers that were added previously, you will need to re-add the event handlers for button (in case it is overriden by .load) so as to continue being re-usable.
Another alternative is to add the event handlers (for button) on parent element and delegate (via jQuery.on method with selector)
Hope this helps, comment for further info if needed