ActionLink executing multiple times - asp.net-mvc-3

I have an ajax action link which is appending a partial to a div.
$('#hypNewCriteria').click(newClick);
...
var newClick = (function ()
{
console.log('newClick');
$.ajax(this.href, {
success: function (result)
{
...
}
}
On the first page load and on every partial that is returned I am (probably unnecessarily), am executing via a document.ready
$('#hypNewCriteria').click(newClick);
... subsequent clicks on the actionlink; the number of partial views returned increases by 1 each time. After 7 clicks, it returns 8 partials. I expect only 1 partial to append.
I suspect the .click(newClick) event is appending. Is there a way to set just one click event or clear the event before I set another?

You can use jQuery's unbind() method to unbind events.
http://api.jquery.com/unbind/
I would also look into the live() jQuery method. This binds an event to all current and future elements that are added to a page, useful for pages that load partials or add items that require events to be added all the time.

Try .one():
$('#hypNewCriteria').one('click', newClick);

Related

Ajaxinate Endless scolling has stopped product Quick View from working

I am using Shopify "Streamline Theme" with quick product view and I recently added infinite scroll to products on each collection using Ajaxinate.js.
When I open a collection page it loads with some products which is supposed to do, The products already there work fine with quick view and quick add to cart and also.
The Infinite scroll works fine and it loads new product fine but the problem is raised when the new products loaded through AJAX call doesn't have work with the quick view function.
I have tried to create a callback function to activate the quick view with no success, using the theme initialisation code with no success.
function callBack(){
theme.init();
theme.initQuickShop();
};
document.addEventListener("DOMContentLoaded", function() {
var endlessClick = new Ajaxinate({
method: "scroll",
loadingText: 'Loading...',
callback: callBack
});
});
Edit -------
My problem, is that when the page is loaded only the initial loaded products quickview elements are loaded in the DOM. When the scroll more button is clicked, the newly loaded products are loaded without their respective quickview elements. Hence why the quickview does't work for them. The theme.js file comes with this initialisation code:
theme.reinitProductGridItem = function($scope) {
if (AOS) {
AOS.refreshHard();
}
if (theme.settings.currenciesEnabled) {
theme.currencySwitcher.ajaxrefresh();
}
// Reload quick shop buttons
theme.initQuickShop(true);
// Refresh reviews app
if (window.SPR) {
SPR.initDomEls();SPR.loadBadges();
}
// Re-register product templates in quick view modals.
// Will not double-register.
sections.register('product-template', theme.Product, $scope);
// Re-hook up collapsible box triggers
theme.collapsibles.init();
};
I have tried to integrate this into a callback but no success, the quickview modal doesn't seem to load for the newly loaded products:
function callBack(){
ReloadSmartWishlist();
var $container = $('#CollectionSection');
theme.reinitProductGridItem($container);
// I have tried the following init qith no success:
// theme.init();
// theme.initQuickShop(true);
// theme.initQuickShop();
// sections.register('product-template', theme.Product, $container);
// AOS.refreshHard();
};
document.addEventListener("DOMContentLoaded", function() {
var endlessClick = new Ajaxinate({
method: "click",
loadingText: 'Loading...',
offset: 0,
callback: callBack
});
});
I am missing something but what? :/
Note for other things like loading products images with the callback and the wishlist app, it works as intended...
When you load elements via AJAX and if the events are not attached to a parent element that is not removed from the DOM, those elements will not have an attached event to them.
The term used here is event delegation.
Here is an example of non-delegated event:
document.querySelectorAll('a').addEventListener('click', function(){
// Do something
})
Since you are attaching the event to the existing "a" elements if you add new 'a' via AJAX those elements will not have the event since Javascript already attached all the events and it will not reattach them if you don't specifically recall them again.
Here is an example of a delegated event:
document.querySelector('body').addEventListener('click', function(target){
let target = event.target;
if (target.tagName === 'A'){
// Do something here
}
})
Where we attach the event to the body tag ( where it's a better idea to attach it to a closer none-modified parent element of the ajax items ) and once we click we check if our target tag is an "a" and do something then.
So long story short, you will need to delegate the quick cart link so that it works after you load the items via AJAX.
Drip is correct you need to delegate your event, but for people like me it's hard to completely understand how to do that.
I'm not sure how your quickview is structured, but if you open it with a .click function and can use jquery use the [.on() function][1].
For example: I use a quickview that opens on a button click. My button is attached to my product-grid-item.liquid with this bit of code:
<div class="quick-view-button">
<a class="quick-view" data-handle="{{ product.handle }}" href="javascript:void(0);">Quick View</a>
</div>
My quickview function originally looked like this:
function quickView() {
$(".quick-view").click(function () {
//all of the quickview code
What happens is exactly like you described. The event listeners only loaded on the first product load but nothing after an AJAX load.
Using jquery's .on() binds the event listener to the element meaning when it's loaded in later it'll still have the event. Here's an example of what my code looks like after using .on()
function quickView() {
$('body').on('click','.quick-view',function(){
I really hope this helps you or someone else with this problem.
[1]: http://api.jquery.com/on/

jQuery unable select element from getJSON

I'm using the .each method with the .getJSON method to print out objects in a JSON file. This works fine, however I am unable to add a click function to an element that has been printed out. I am trying to bind a function to the div with 'click' ID.
var loadData = function () {
$.getJSON("profiles2.json", function (data) {
var html = [];
html.push("<div id='click'>Click here</div>");
$.each(data.profiles, function (firstIndex, firstLevel) {
html.push("<h2>" + firstLevel.profileGroup + "</h2>");
});
$("#data").html(html.join(''));
});
};
$(document).ready(function () {
loadData();
$("#click").click(function () {
console.log('clicked');
});
});
$.getJSON() (like other Ajax methods) is asynchronous, so it returns immediately before the results have come back. So your loadData() method also returns immediately and you then try to bind a handler to an element not yet added.
Move the .click(...) binding into the callback of $.getJSON(), after adding the element(s), and it will work.
Alternatively, use a delegated event handler:
$("#data").on("click", "#click", function() {
console.log('clicked');
});
...which actually binds the handler to the parent element that does exist at the time. When a click occurs it then tests whether it was on an element that matched the selector in the second parameter.
And as an aside, don't bind click handlers to divs unless you don't care about people who are physically unable to (or simply choose not to) use a mouse or other pointing device. Use anchor elements (styled as you see fit) so that they're "click"-accessible via the keyboard and the mouse.
$.getJSON is an asynchronous call and probably hasn't finished by the time you are trying to bind to the element that it injects into your DOM. Put your binding inside the $.getJSON call after you append the element to the page at the bottom.

Loading a hidden div into an AJAX jQuery UI tab (future DOM element)

I have been trying to manipulate content that is loaded into jQuery UI tabs via AJAX.
As you can imagine, these elements are "future" DOM elements and aren't manipulated by normal $(".someClass")functions.
I've read using .live() for event handling is now deprecated using jQuery 1.7+ and is replaced by the new .on() method.
My issue is that the div I want to hide, when it loads in an AJAX tab, must be manipulated after the initial DOM load and is not bound to a click event at first.
My functions, which are currently wrapped in $() are below.
I think I have the syntax correct for links that use a click handler, but I'm not sure of the correct way to ".hide()" my "hiddenStory" div at load.
I also think that the functions themselves shouldn't be wrapped in an overall $()?
Any help or advice would be greatly appreciated.
$(function(){
// this .hiddenStory div below is what I want to hide on AJAX load
// need syntax and/or new methods for writing this function
$(".hiddenStory").hide();
// this is a function that allows me to toggle a "read more/read less" area
// on the "hiddenStory" div
$(".showMoreOrLess").on('click', (function() {
if (this.className.indexOf('clicked') != -1 ) {
$(this).removeClass('clicked');
$(this).prev().slideUp(500);
$(this).html("Read More" + "<span class='moreUiIcon'></span>");
}
else {
$(this).addClass('clicked');
$(this).prev().slideDown(500);
$(this).html("See Less" + "<span class='lessUiIcon'></span>");
}
}));
});
// prevents default link behavior
// on BBQ history stated tab panes with
// "showMoreOrLess" links
$('.showMoreOrLess').click(function (event)
{
event.preventDefault();
// here you can also do all sort of things
});
// /prevents default behavior on "showMoreOrLess" links
Could you set the display: none via CSS and override it when you wanted to show the element's content? Another option, if you have to do it this way would be to add the `$(".hiddenStory").hide() in the callback from the AJAX load that is populating the element. For example:
$(".hiddenStory").load("http://myurl.com", function(){
$(".hiddenStory").hide();
}
);
If you aren't using the .load method, you should have some sort of call back to tie into (e.g. success if using $.ajax...)

how to fake a click on a dynamic element?

On a static element, to fake a click, I use
$(selector).click();
But how can I do the same thing on a dynamic element (resulted from an ajax call)?
The same...:
$(selector).click();
Why didn't you try it first?
P.S. it is not called fake a click, it's called trigger the click event.
$(selector).trigger('click'); == $(selector).click();
Update
You need to bind that element a callback to the event in order it to work:
$(selector).click(function(){...});
$(selector).click();
If you want it to have the the click callback you assigned to the static elements automaticlly, you should use on\ delegate (or live but it's deprecated) when you attach the click callback.
$('body').on('click', 'selector', function(){...})
instead if body use the closest static element the holds that selector elements.
See my DEMO
within your ajax success function try your code:
$(selector).click();
Basing this on your previous question : How can I select a list of DOM objects render from an AJAX call?
$(document).ready(function(){
var listItems = $('#myList li a');
var containers = $('#myContainer > div');
listItems.click(function(e){//do someting
});
etc...
If the elements you are trying to attach a click handler to are supposed to be inside any of the two variables above then you WILL have to update those variables after the elements are inserted into the DOM, as it is right now only elements that exists during first page load will be inside those variables.
That is the only reason I can think of why something like :
$(document).on('click', listItems, function(e) {//do something
});
will not work!
Don't know if I understand (I'm french sorry...)
But try :
$(selector).live('click',function(){}); // deprecated it seems
Demo of gdoron with live() : http://jsfiddle.net/Rx2h7/1/
use on() method of jquery,
staticElement.on('click', selector, function(){})
on method generates click event on dynamically created element by attaching it to the static element present in the DOM .
For further reference check this out -- https://api.jquery.com/on/

jQuery: Wait for entire page--including ajax--to load?

I'm using some jQuery tabs that load their content via ajax. I'm using $(document).ready() in conjunction with the following code:
// Hide loading animation, show content container
$("#content").show();
$("#loading").hide();
The purpose is to wait until the page is fully loaded, then show the content and hide the loading animation.
However, $(document).ready() only waits for the main page to load, not the external ajax content.
Is there something I can do wait until the ajax is loaded too?
Thanks in advance.
Depending on your ajax library, there is usually an option for supplying a callback which is called when the underlying ajax (get post..) operation is complete. You could use that callback to do your initialization rather than within .ready()....
First, if you wish to show animation while you're loading, use ajaxStart and ajaxStop. It does it auto-painlessly. Here's an example:
// Note! This uses jquery-ui to do the dialog...
jQuery(document).ready(function() {
var body = jQuery("body");
body.append('<div id="ajaxBusy"><div style="text-align:center" ><p>Communicating with server...<br \/>Please wait for this operation to finish.<br \/><img src="\/js\/jquery.smallhbar.indicator.gif" \/><\/p><\/div><\/div>');
jQuery('#ajaxBusy').css({
display:"none",
margin:"0px",
width:"260px",
height:"170px",
padding:"5px",
textAlign:'center'
});
jQuery("#ajaxBusy").dialog({
autoOpen: false,
bgiframe: true,
closeOnEscape: false,
//modal: true,
title: 'Shipping Department'});
jQuery(document).ajaxStart(function() {
jQuery('#ajaxBusy').dialog('open');
});
jQuery(document).ajaxStop(function() {
jQuery('#ajaxBusy').dialog('close');
});
});
With this code in my jQuery.ready section, a pretty dialog automatically flashes when ajax operations are occurring.
Finally, if you need to show content afterwards, you need to put your show() method within the success function of your ajax call. If you have multiple ajax calls happening, you'll need to use some variables as flags to signal when everything is done (clunky).
Do you have one or more than one ajax call happening?

Resources