Instafeed and Masonry - masonry

I have this code below where I am trying to use Instafeed and Masonry together. Everything works fine until I click the "Load more" button. Then the Masonry layout breaks. It's probably because something is loading before the other or vice versa. I'm new to this so all help would be greatly appreciated.
I got the tip to use imagesLoaded instead of window.load and also to use appended method. But I don't understand how to incorporate that in to my code.
My code is in a script.js doc and outputs in the footer of the page after instafeed.js and masonry.
$(function () {
var loadButton = document.getElementById('load-more');
if(loadButton !== null) {
var userFeed = new Instafeed({
get: 'user',
userId: xxxxxxxxx,
accessToken: 'xxxxxxxxx',
limit: 6,
resolution: 'standard_resolution',
template: '<div class="col30 grid image-top-fill instapic"><img src="{{image}}" alt="Instagram" /> <p class="nomargin">{{caption}}</p></div>',
after: function() {
if (!this.hasNext()) {
loadButton.setAttribute('disabled', 'disabled');
Masonry.start();
}
}
});
loadButton.addEventListener('click', function() {
userFeed.next();
});
userFeed.run();
}
});
$(window).load(function(){
var container = document.querySelector('#instafeed');
var msnry = new Masonry( container, {
itemSelector : '.instapic',
isAnimated : true,
isFitWidth : false
});
});
Thanks in advance for your help! Let me know if there is anything more you need from me.
Cheers / Jeppe

You're correct in that Masonry is trying to work with elements before they're loaded. You can put .masonry('appended', $items) in the after event of Instafeed. Instafeed's developer posted this fix:
https://github.com/stevenschobert/instafeed.js/issues/118#issuecomment-44438003

Related

Masonry Overlap

I am noticing that my masonry page is creating overlap and unequal spacing. This isn't consistent and seems to happen sometimes, while at other times it works fine. In every scenario if I resize my window slightly, the mason() function kicks in and fixes it. I originally thought that it was an issue with having to wait for the images to load (around 30 at a time are loading), but I have already implemented imagesLoaded and see no difference. Can anyone point out my mistake?
<script>
function mason() {
var $container = $('#dealcontainer').masonry({
itemSelector: '.outerdeal',
columnWidth: '.outerdeal'
});
$container.imagesLoaded(function(){
$container.masonry();
});
}
function colorize()
{
$('.dealfilterli').click(function (event) {
if (event.target.type !== 'checkbox') {
$(':checkbox', this).trigger('click');
}
$("input[type='checkbox']").change(function (e) {
if ($(this).is(":checked")) {
$(this).closest('li').addClass("colorize");
} else {
$(this).closest('li').removeClass("colorize");
}
});
});
}
function InitInfiniteScroll(){
$('#dealcontainer').infinitescroll({
navSelector : "div.pagination",
nextSelector : "div.pagination li a",
itemSelector : "#deals div.outerdeal",
loading:{
finishedMsg: '',
img: 'http://www.example.com/img/icons/site/spinner.gif',
msgText: '',
speed: 'fast',
},
},function(newElements) {
var $newElems = $( newElements );
$('#dealcontainer').masonry( 'appended', $newElems );
mason();
});
}
$( document ).ready(function() {
InitInfiniteScroll();
colorize();
});
$(window).resize(function() {
InitInfiniteScroll();
mason();
}).resize();
</script>
I was having the exact same issue despite using imagesLoaded, and after a lot of trial and error I found that the problem can be solved with a setTimeout function. Here is an example from my project:
setTimeout(function() {
masonryContainer.imagesLoaded(function() {
masonryContainer.prepend(newPost);
masonryContainer.masonry('prepended', newPost);
});
}, 500);
The 500ms timeout is arbitrary, so I would play around with that on your page to find the lowest possible value that still fixes your issue. Hope that helps!
Cheers,
Jake
You should use:
$container.masonry('reloadItems');
on mason() function and everything will be replaced in the correct position.

Instafeed pagination and limit not working for chosen tag, yet same code works for other tags

The following Instafeed code shows not 5 but 6 images, and the #load-more button is hidden, indicating hasNext() is false:
var tagged_cofiwear = new Instafeed({
target: 'instagram-tagged',
get: 'tagged',
tagName: 'cofiwear',
clientId: '8852afa8788546a199c37543b77b043c',
sortBy: 'most-recent',
limit: 5,
template: '<a target="_blank" href="{{link}}"><img src="{{image}}" /></a>',
after: function() {
if (!this.hasNext()) {
$('#load-more').hide();
}
}
});
tagged_cofiwear.run();
$('#load-more').on('click', function() {
tagged_cofiwear.next();
});
To try and troubleshoot, I found a jsfiddle with Instafeed pagination that works (http://jsfiddle.net/unuLyzx0/107/) and edited tagName: 'justanotherinvegas' to be tagName: 'cofiwear'.
Here is the result, which also shows the wrong number and the load more button doesn't work :(
http://jsfiddle.net/unuLyzx0/108/
Any tips?
Thanks!
In case it helps anyone else:
Turns out I needed to add the userId and accessToken for the user cofiwear, which happens to be the tag we want from all users.

How call a function when view is attached in Durandal?

I'm just started to develeop a web app with Durandal. I don't understand how call a function from a viewmodel and why if I find an element of my document it seems is not attached yet.
Example: viewmodel.js
define( ['libone', 'libtwo'], function () {
$('.carousel').libone({
expandbuttons: true,
keyboard: true,
mouse: true
});
});
It doesn't find the ID call carousel is why there's no view.hmtl content but index.html content.
Any ideas?
Thanks in advance
UPDATE
No errors but the view content is not returned.
view.html
<section>
<h2 data-bind="html:name"></h2>
<blockquote data-bind="html:descr"></blockquote>
<div class="carousel">
<div class="carousel-sections">
<div class="carousel-section"> ... some content ... </div>
</div>
</div>
<a id="carousel-scroll-prev" href="#"></a>
<a id="carousel-scroll-next" href="#"></a>
<section>
modelview.js
define( ['libone', 'libtwo'], function (libone, libtwo) {
var viewattached = function(view){
var view = $(view);
view.find('.carousel').libone({
expandbuttons: true,
keyboard: true,
mouse: true
});
};
var vm = {
attached: viewattached,
name: 'How about we start?',
descr: 'You have many choices to make and many roads to cross...'
};
return vm;
});
Only name, descr and scroll are shown but not carousel-section.
The rendering problem has been resolved using compositionComplete instead attached.
to gain access to the controls using jquery like you are requesting, you should use the views attached event
e.g.
define( ['libone', 'libtwo'], function (libone, libtwo) {
var viewattached = function(view){
var view = $(view);
view.find('.carousel').libone({
expandbuttons: true,
keyboard: true,
mouse: true
});
};
var vm = {
attached: viewattached
};
return vm;
});
The other one that may work will be the compsitionComplete..
compositionComplete works fine.But if you refresh the page ,composition complete skips the binding of element with the carousel and teh carousel doesnt work.
Any

select2 plugin works fine when not inside a jquery modal dialog

I am using select2 plugin inside a jquery dialog but in does not work. When dropping down, the focus moves to the input control but immediately get out from it,not allowing me to type anything.
This is the HTML:
<div id="asignar_servicio" title="Asignar servicios a usuarios">
<input type="hidden" class="bigdrop" id="a_per_id" />
</div>
And this is the javascript code:
$( "#asignar_servicio" ).dialog({
autoOpen: false,
height: 500,
width: 450,
modal: true,
buttons: {
"Cancelar": function () {
$('#asignar_servicio').dialog('close');
}
}
});
$("#a_per_id").select2({
placeholder: "Busque un funcionario",
width: 400,
minimumInputLength: 4,
ajax: {
url: "#Url.Action("Search", "Personal")",
dataType: 'json',
data: function (term, page) {
return {
q: term,
page_limit: 10,
};
},
results: function (data, page) {
return { results: data.results };
}
}
}).on("change", function (e) {
var texto = $('lista_personal_text').val().replace(/ /g, '');
if (texto != '')
texto += ',';
texto += e.added.text;
var ids = $('lista_personal_id').val().replace(/ /g, '');
if (ids != '')
ids += ',';
ids += e.added.id;
});
I have this same code in other page and it works.
Any help will be appreciated,
thanks
Jaime
jstuardo's link is good, but there's a lot to sift through on that page. Here's the code you need:
$.ui.dialog.prototype._allowInteraction = function(e) {
return !!$(e.target).closest('.ui-dialog, .ui-datepicker, .select2-drop').length;
};
Just add it next to wherever you are setting the select2 drop down.
An easy way:
$.ui.dialog.prototype._allowInteraction = function (e) {
return true;
};
add this after whereever you set select2
Or try this from:
Select2 doesn't work when embedded in a bootstrap modal
Remove tabindex="-1" from the modal div
I have found this workaround. https://github.com/ivaynberg/select2/issues/1246
Cheers
Jame
There's a new version of the fix for select2 4.0 from the github issue thread about this problem:
if ($.ui && $.ui.dialog && $.ui.dialog.prototype._allowInteraction) {
var ui_dialog_interaction = $.ui.dialog.prototype._allowInteraction;
$.ui.dialog.prototype._allowInteraction = function(e) {
if ($(e.target).closest('.select2-dropdown').length) return true;
return ui_dialog_interaction.apply(this, arguments);
};
}
Just run this before any modal dialogs that will have select2 in them are created.
JSFiddle of this fix in action
The best solution I found was just making the dialog not be a modal dialog by removing modal:true. Once you do this the page will function as desired.
After a while of battling with this I found another option that allows you to keep the dialog as a modal. If you modify the css for select2 to something like the following:
.select2-drop {
z-index: 1013;
}
.select2-results {
z-index: 999;
}
.select2-result {
z-index: 1010;
}
keep in mind that this works however if you open a lot of dialogs on the same page it will eventually exceed the z-index specified, however in my use case these numbers got the job done.
Not enough reputation to comment on a previous post, but I wanted to add this bit of code:
$('#dialogDiv').dialog({
title: "Create Dialog",
height: 410,
width: 530,
resizable: false,
draggable: false,
closeOnEscape: false,
//in order for select2 search to work "modal: true" cannot be present.
//modal: true,
position: "center",
open: function () { },
close: function () { $(this).dialog("distroy").remove(); }
});
$("#displaySelectTwo")select2();
Updating to the newer version of JQuery and Select2 is not an option in our application at this time. (using JQueryUI v1.8 and Select2 v1)
Add this after your select2() declaration.
$.ui.dialog.prototype._allowInteraction = function (e) {
return !!$(e.target).closest('.ui-dialog, .ui-datepicker, .select2-dropdown').length;
};
I've used the following fix with success:
$.fn.modal.Constructor.prototype.enforceFocus = function () {
var that = this;
$(document).on('focusin.modal', function (e) {
if ($(e.target).hasClass('select2-input')) {
return true;
}
if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
that.$element.focus();
}
});
}
I could fix this by removing the option: 'modal: true' from the dialog options.
It worked fine.
For anyone stumpling upon this with Select2 v4.0.12
I was using the Select2 option dropdownParent
i set the dropDownParent value, and still had the issue.
dropdownParent: $("#ReportFilterDialog")
What fixed it for me, was setting the value to, to select the outer layer of the modal dialog:
dropdownParent: $("#ReportFilterDialog").parent()

Handlebars.js misses JSON data

I've got template file loaded by Require.js via this:
main-app.js
define([
'backboneLoader',
'handlebars',
'text!templates/main.html',
'text!appdata.json'
],
function(
Backbone,
Handlebars,
MainTemplate,
AppData
) {
"use strict";
return Backbone.View.extend({
initialize : function() {
this.render();
},
render : function() {
var template = Handlebars.compile(MainTemplate);
var output = template(AppData);
this.$el.append(output);
console.log("appData:\n" + AppData);
console.log("MainTemplate:\n" + MainTemplate);
console.log("Output:\n" + output);
//smth extra
return this;
}
});
}
);
MainTemplate (main.html)
<ul>
<li><b>Version:</b> {{version}}</li>
<li><b>Author:</b> {{author}}</li>
</ul>
AppData (appdata.json)
{version: "0.0.1", author: "John Doe"}
And output:
<ul>
<li><b>Version:</b></li>
<li><b>Author:</b></li>
</ul>
While expected output:
<ul>
<li><b>Version:</b> 0.0.1</li>
<li><b>Author:</b> John Doe</li>
</ul>
Any ideas what am I doing wrong? Thank you!
UPD:
Problem solved. Here is updated main-app.js:
define([
'backboneLoader',
'handlebars',
'text!templates/main.html!strip',
'text!appdata.json'
],
function(
Backbone,
Handlebars,
mainTemplate,
appData
) {
"use strict";
return Backbone.View.extend({
initialize : function() {
this.render();
},
render : function() {
var template = Handlebars.compile(mainTemplate);
var output = template(eval("(" + appData + ")")); //Object is expected by template(), not JSON.
this.$el.append(output);
console.log("appData:\n" + appData);
console.log("template:\n" + mainTemplate);
console.log("Output:\n" + output);
//smth extra
return this;
}
});
}
);
The problem is AppData is a string of JSON, not an actual Object. Simply change from:
var output = template(AppData);
to
var output = template(JSON.parse(AppData));
You may need to include json2.js to add JSON support for older browsers (<=IE7).
Here is a jsFiddle repro of your template function, the template transformations seems working, the problem is probably located in the text! function in require.js code, try to debug the text! function.
Try also to add the !strip function when loading the template: 'text!templates/main.html!strip',
The documentation suggests it :For HTML/XML/SVG files, there is another option. You can pass !strip, which strips XML declarations so that external SVG and XML documents can be added to a document without worry.

Resources