I'm using Rails 4, Bootstrap and Masonry. I have the following code working for jQuery Masonry to arrange my divs, in application.js:
$(function(){
$('#pins').masonry({
itemSelector: '.box',
isFitWidth: true
});
});
var masonryUpdate = function() {
setTimeout(function() {
$('#pins').masonry();
}, 200);
}
$(document).on('click', masonryUpdate);
$(document).ajaxComplete(masonryUpdate);
It works otherwise, but when I try to delete an item with AJAX, Masonry doesn't update. Here is my destroy.js:
$('.deleting').bind('ajax:success', function() {
$(this).closest('.poista').fadeOut();
});
How could I force Masonry to reload, after the code example above? For some reason .ajaxComplete(masonryUpdate) is not triggered?
From the jQuery Documentation on ajaxComplete it seems as though it doesn't perform a function call on a given argument but instead calls a handler function when the Ajax requests complete.
handler
Type: Function( Event event, jqXHR jqXHR, PlainObject ajaxOptions )
The function to be invoked.
Your best bet would be to use an anonymous function to call masonryUpdate.
$(document).ajaxComplete(function(event, xhr, settings) {
masonryUpdate();
};
Edit
It might be better to cache your masonry spec in a variable.
var mas = $('#pins').masonry({
itemSelector: '.box',
isFitWidth: true
});
Then you can call masonry on that variable
var masonryUpdate = function() {
setTimeout(function() {
mas.masonry('reload');
}, 200);
}
Related
I have an issue with my masonry code.
It works fine on pageload, but the items that are inside the masonry can be filtered, I am doing this using ajax and I'm replacing the entire div with elements to show the filtered items.
After this happens, the masonry code is not applied again and it falls apart.
How can I make sure the masonry stays applied even when content changes after pageload?
In my footer I have the following code:
<script type="text/javascript">
$(document).ready(function() {
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
});
</script>
Then in my custom.js I have the following:
$( document ).ready(function() {
/* Ajax code voor aanbiedingen */
$("#branche").on('change', function() {
var option = $('#branche > option').filter(':selected');
if(option.val() == 'default'){
$.post("includes/ledenall.php", {
filter: option.val()
}, function(result){
$("#content1").html(result);
});
}else{
$.post("includes/leden.php?option=" + option.val(), {
filter: option.val()
}, function(result){
$("#content1").html(result);
});
}
});
});
Which returns my php file, but this time without the masonry being applied.
What can I do about this?
You can try reapplying your isotope library after changing the DOM:
/* Ajax code voor aanbiedingen */
$("#branche").on('change', function() {
var option = $('#branche > option').filter(':selected');
if(option.val() == 'default'){
$.post("includes/ledenall.php", {
filter: option.val()
}, function(result){
$("#content1").html(result);
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
});
}else{
$.post("includes/leden.php?option=" + option.val(), {
filter: option.val()
}, function(result){
$("#content1").html(result);
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
});
}
});
I don't know if .gridlist is totally replaced in your updated DOM. If not, you may need to somehow "remove" the old isotope instance, but something like this is what you need to do.
Add your code to a function
function func() {
$('.gridlist').isotope({
itemSelector: '.masonryitem',
layoutMode: 'masonry',
});
}
Then you can call the function and apply your isotope at any point you want
I am using a function pinterest_it() to adjust a view with masonry.js and I'm using another function recipeLoader() to show a loading icon until the page completely loads, then display content. This works on page refresh, but when I load content using ajax, my $( window ).load(...) function never fires.
How can make the function call after everything completely loads (not .ready)
function pinterest_it() {
$(".loader").show(); # shows loading icon
$("#recipe-index").css("opacity", 0); # makes content invisible
if ( $(document).innerWidth() < 991 ) {
gutter = 0
} else {
gutter = 16
}
var $grid = $('.grid').imagesLoaded( function() {
var $blah = $('.grid').masonry({
itemSelector: '.grid-item',
columnWidth: function( containerWidth ) {
return $('.grid-sizer').width();
},
percentPosition: true,
gutterWidth: gutter
});
}, fixGrid())
recipeLoader(); # see below
}
function recipeLoader() {
console.log("recipe loader")
$(window).load(function() { # doesn't fire after Ajax completes!
console.log("loaded")
$(".loader").hide(); # hides loading icon
$("#recipe-index").animate({
opacity: 1 # shows content
}, 400);
});
}
# one of the Ajax function that calls pinterest_it()
$(".togglebutton input").click(function () {
console.log($(this).serialize());
$.get(this.action, $('#recipes_search').serialize(), function() {
pinterest_it();
}, 'script')
});
I've tried $(x).ready(...) with no luck, as well as ajaxComplete(). Perhaps there is some way to use $(x).load(...) with a specific element rather than window to allow the function to fire? I've tried calling it on $("#recipe-index") but that didn't work either.
$(window).load doesn't fire on success/completion of an Ajax request. Move that bit to its own function:
function handlePageRefresh () {
console.log("loaded")
$(".loader").hide(); # hides loading icon
$("#recipe-index").animate({
opacity: 1 # shows content
}, 400);
}
And then call it in $(window).load & the Ajax success callback
$(window).load(function() { # doesn't fire after Ajax completes!
handlePageRefresh()
});
# one of the Ajax function that calls pinterest_it()
$(".togglebutton input").click(function () {
console.log($(this).serialize());
$.get(this.action, $('#recipes_search').serialize(), function() {
handlePageRefresh()
pinterest_it();
}, 'script')
});
I have managed to implement the smoothState.js plugin on my website and it works nicely, but my other very simple jQuery plugin will not work, wich starts with:
$(document).ready()
I need to refresh the page in order for it to work again.
I've read the smoothState documentation and it says I should wrap your plugin initializations in a function that we call on both $.fn.ready() and onAfter — but I'm farely new to programming, so I'm asking for your help.
How can I make my jQuery plugins work with smoothState?
You need to wrap scripts that are initiated with $(document).ready() in a function, and then call that function when you need it.
For example, let’s say this is your current script:
$(document).ready(function() {
$('.btn--homepage').click(function(e) {
e.preventDefault();
var goTo = $(this).attr('href');
$('#page').addClass('is-exiting');
$(this).addClass('exit-btn');
setTimeout(function() {
window.location = goTo;
}, 260);
});
});
It’ll work fine when the page loads as it’s wrapped in $(document).ready(function()), but as the page won’t be reloading when using Smoothstate, we need a way to call the snippet both when the page originally loads and when smoothstate loads content. To do this we’ll turn the above snippet in to a function like this:
(function($) {
$.fn.onPageLoad = function() {
$('.btn--homepage').click(function(e) {
e.preventDefault();
var goTo = $(this).attr('href');
$('#page').addClass('is-exiting');
$(this).addClass('exit-btn');
setTimeout(function() {
window.location = goTo;
}, 260);
});
};
}(jQuery));
As you can see, we’ve swapped $(document).ready(function()) with the function wrapper, everything else stays the same.
So now we’ve got a function all we need to do is call it when the page loads and in Smoothstate.
To call it when a page loads all we need to do is this:
$(document).ready(function() {
$('body').onPageLoad();
});
And to trigger it in Smoothstate we need to call it in the InAfter callback like this:
onAfter: function($container) {
$container.onPageLoad();
}
And here's an example Smoothstate script showing where to put the onAfter callback:
$(function() {
var $page = $('#main');
var options = {
prefetch : true,
pageCacheSize: 4,
forms: 'form',
scroll: false,
onStart: {
duration: 1200,
render: function($container) {
$container.addClass('is-exiting');
smoothState.restartCSSAnimations();
}
},
onReady: {
duration: 0,
render: function($container, $newContent) {
$container.removeClass('is-exiting');
$container.html($newContent);
$('html, body').scrollTop(0);
}
},
onAfter: function($container) {
$container.onPageLoad();
}
};
var smoothState = $('#main').smoothState(options).data('smoothState');
});
Happy to provide further assistance if needed.
This could be kind of complex cause there is a lot of ravioli code involved. I'm just looking for possible causes of this behavior.
Im using Jquery Isotope, it works correctly. The only thing that is not working is a function that I call when the document is ready, why could that be? :
$( document ).ready(function(){
$('.grid').isotope({
itemSelector: '.element-item',
layoutMode: 'packery',
packery: {
gutter: 10
}
});
var isotopeFilter = function(f){
console.log(f);
$(".grid").isotope({filter: f});
}
isotopeFilter('.xp'); // Doesn't Work!!
$("#filter-basket").on("click", function(){
isotopeFilter('.basket'); // Works correctly
});
$("#filter-all").on("click", function(){
$(".grid").isotope({ filter: '.xp' }); // Works correctly
});
$("#filter-ghacking").on("click", function(){
$(".grid").isotope({ filter: '.ghacking' }); // Works correctly
});
})
The reason I need to call that function at document load is because I want to set a default filtering.
Here I have a widget and I want to call a function once #slider.slider();. what is the code?
$( "#slider" ).slider({
//initial function here.
alert("A");
value: 50,
slide: function(event, ui) {
displaySlideValue();
}
});
Why not just do
$('#slider').slider({ ... }).each(function() { /* your code here */ });
Alternatively you could wrap the .slider() call in your own mini-extension:
$.fn.sliderWithInit = function(params, init) {
return this.slider(params).each(init);
});
then you could say
$('#slider').sliderWithInit({ /* params */ }, function() { /* init code */ });
Obviously "slider" could be made generic:
$.wrapWithInit = function(widgetName) {
$.fn[widgetName + 'WithInit'] = function(params, init) {
return this[widgetName](params).each(init);
});
});
Then you can do it for "dialog" for example:
$.wrapWithInit('dialog');
$('#dialog').dialogWithInit({ /* dialog params */ }, function() { /* init code */ });
As #mikerobi points out, it's not 100% clear when you want your initialization function to be called. Most widgets have an "onFoo" type callback that's called when the widget is activated (whatever that means for the given widget). If you just want to initialize on the first call, you could just make the callback be a closure that keeps track of whether it's ever done the initialization work. If it detects it's already done it, it would just return.