Masonry sometimes lays out in one column straight line - javascript

I have masonry initialized on some "tiles" that include an image. Most of the time I am not having issues but sometimes the tiles lay out in one column when there should be 3 columns. Do you have any idea what the issue might be?
On ready initialization:
$(document).ready(function() {
var $container = $('#news');
$container.masonry({
itemSelector: '.pageNewsItem',
transitionDuration: 0
});
$container.masonry( 'on', 'layoutComplete', function( msnryInstance, laidOutItems ) {debounced = true;} )
});
Dynamically append tiles:
var count = 0;
function placeNewsTiles(news){ //places news tiles
var length = (news.data.length > 20) ? 20 : news.data.length;
var elems ="";
for(var i = 0; i < length; i++){
elems += '<div class="pageNewsItem inactive" id="'+ count + i + '">\
<div class="outerTextWrap">\
<div class="textWrap">\
<a href="' + news.data[i]._url + '">\
<strong>' + news.data[i]._title + '</strong>\
</a>\
<span class="source">' + news.data[i]._source + '</span>\
</div>\
</div>\
<div class="imageWrap"></div>\
<div class="thumbsOverlay" style="display:none">\
<div class="thumbs">\
<div>\
\
\
</div>\
</div>\
<div class="title">\
<div>\
<a href="' + news.data[i]._url + '">\
<div class="theTitle">Read Article</div>\
</a>\
</div>\
</div>\
</div>\
</div>';
getTileImage({total: news.count, i:count + "" + i, url:news.data[i]._url});
}
elems = $(elems);
$('#news').append(elems).imagesLoaded(function(){
//for(var i = 0; i < length; i++) $('.pageNewsItem').removeClass('inactive'); //$('.pageNewsItem').show(1000);
$('#news').masonry( 'appended', elems);
});
newsPage = 0;
count++;
hoverTiles();
}
getTileImage function is called to conduct an ajax call to obtain the tile image. Masonry layout happens on complete:
var cnt = 0;
function getTileImage(args){
var _t = localStorage.getItem("token"),
url = args.url,
i = args.i;
$.ajax({
type: "GET",
url: apiHost+'/api/tileImg?url=' + url + '&token='+_t,
dataType: "json",
success: function(data) {
var img = (data && data.image.src) ? data.img.src : (data && data.image) ? data.image: "";
if(img.indexOf("spacer") > -1|| img.indexOf("blank") > -1 || img === ""){ $('.pageNewsItem#' + i).hide(); }
else $('.pageNewsItem#' + i).find('.imageWrap').append('<img src="' + img + '" />');
},
error: function(e) {
if (e.status == 404) {
//need to get a new token
getToken(getTileImage, url);
}
}, complete: function(){
cnt++;
if ((cnt ==20) || cnt == args.total) {
var $container = $('#news');
$container.imagesLoaded( function() {
$container.masonry( 'layout' );
$('.pageNewsItem').removeClass('inactive');
//$('.pageNewsItem').show();
});
cnt = 0;
}
/*$('#news').imagesLoaded( function() {
$('.pageNewsItem#' + i + ' .thumbs').height($('.pageNewsItem#' + i).outerHeight() - $('.pageNewsItem#' + i + ' .title').height() - 5);
//$('.pageNewsItem').show();
});*/
}
});//end ajax call
}
CSS:
.pageNewsItem {
width: 33.333%;
padding: 10px;
min-height: 150px;
opacity: 1;
transition: opacity 1s ease;
}
#news {
margin-right: 20px;
margin-top: 25px;
}

Try using the console and manually initialize masonry:
$('#news').masonry();
If it is not working, masonry might be already initialized and therefore it's not repositioning the elements. In that case you have to remove masonry from the div and reinitialize it:
$('#news').masonry('destroy');
$('#news').masonry();

Related

Blogspot json - load post content on click

$.ajax({
url: 'https://mailliw88.blogspot.com/feeds/posts/default?start-index=1&max-results=2&alt=json-in-script',
type: 'get',
dataType: "jsonp",
success: function(data) {
var entry = data.feed.entry;
for (var i = 0; i < entry.length; i++) {
postTitle = entry[i].title.$t;
postTitleLink = entry[i].title.$t.replace(/\s+/g, '-').toLowerCase();
items = '<div class="items"><h2>' + postTitle + '</h2></div>';
document.getElementById('showlists').innerHTML += items;
postContent = entry[i].content.$t;
content = '<div class="contentWrap"><div id="close">CLOSE</div><h1>' + postTitle + '</h1><div>' + postContent + '</div></div>';
document.getElementById('showlists').innerHTML += content;
}
}
});
h1 {margin:0}
.contentWrap {border:1px solid red;
padding:5px}
#close {color:red;text-align:right}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='showlists'>
</div>
How to load post content only when clicking the title?
I can use .toggle in jquery but I need to load and "unload" content, not just showing and hiding it. I hope i'm making sense.
My skill is limited to css only, thank you for your help.
You can use display:none to <div class="contentWrap"> and on click of a tag you can show the content using closest() and next().And on click of close again use "display", "none" to hide that content div .
Demo Code :
$.ajax({
url: 'https://mailliw88.blogspot.com/feeds/posts/default?start-index=1&max-results=2&alt=json-in-script',
type: 'get',
dataType: "jsonp",
success: function(data) {
var entry = data.feed.entry;
for (var i = 0; i < entry.length; i++) {
postTitle = entry[i].title.$t;
postTitleLink = entry[i].title.$t.replace(/\s+/g, '-').toLowerCase();
items = '<div class="items"><h2>' + postTitle + '</h2></div>';
document.getElementById('showlists').innerHTML += items;
postContent = entry[i].content.$t;
//added display none and added class = close
content = '<div style="display:none"class="contentWrap"><div class="close">CLOSE</div><h1>' + postTitle + '</h1><div>' + postContent + '</div></div>';
document.getElementById('showlists').innerHTML += content;
}
}
});
//on click of a tag show content
$(document).on("click","a",function(){
//a->closest div->next content->show
$(this).closest(".items").next(".contentWrap").css("display", "block");
})
//onclick of close -> hide again
$(document).on("click",".close",function(){
$(this).closest(".contentWrap").css("display", "none");
})
h1 {margin:0}
.contentWrap {border:1px solid red;
padding:5px}
.close {color:red;text-align:right}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='showlists'>
</div>
Update 1 :
You can assign i value some custom attribute and then use same index value to access post content.In below code snippets i have not send again request to server to load json on click of a instead i have use some variable to store content of data.feed.entry in some variable and then use this to add content .
Demo Code :
var datas = "";
$.ajax({
url: 'https://mailliw88.blogspot.com/feeds/posts/default?start-index=1&max-results=2&alt=json-in-script',
type: 'get',
dataType: "jsonp",
success: function(data) {
//adding entry content in datas to use later
datas = data.feed.entry;
var entry = data.feed.entry;
for (var i = 0; i < entry.length; i++) {
postTitle = entry[i].title.$t;
postTitleLink = entry[i].title.$t.replace(/\s+/g, '-').toLowerCase();
//passing index no i.e : " i " in custom attribute
items = '<div class="items"><h2><a data-val=' + i + ' href="#' + postTitleLink + '">' + postTitle + '</a></h2></div>';
document.getElementById('showlists').innerHTML += items;
}
}
});
$(document).on("click", "a", function() {
$(".contentWrap").remove(); //remove previous div
var ids = $(this).attr('data-val');
console.log(ids)
//getting data that index position got from a tag
postTitle = datas[ids].title.$t;
postTitleLink = datas[ids].title.$t.replace(/\s+/g, '-').toLowerCase();
postContent = datas[ids].content.$t;
content = '<div class="contentWrap"><div class="close">CLOSE</div><h1>' + postTitle + '</h1><div>' + postContent + '</div></div>';
document.getElementById('showlists').innerHTML += content;
})
h1 {margin:0}
.contentWrap {border:1px solid red;
padding:5px}
.close {color:red;text-align:right}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="showlists"></div>

Javascript append keep adding elements

I am trying to append list[i].name and list[i].email once every time sponsorListTree li is being clicked. I can append the document.getElementById("name").appendChild(div_group); but the problem occurs when i click the div a few times, the same data will add up instead of displaying the result only once
$.ajax({
url: 'test.php',
method: 'GET',
success: function(data){
var list = data;
for (i = 0; i < list.length; i++) {
$('#sponsorListTree li').attr('id', function(i) {
return 'sponsorListTree'+(i+1);
});
$('#sponsorListTree').append('<li class="button"><tbody><tr><td><span id="information" class="details"><br/><br/> '+ 'Email: ' + list[i].email + '</br></br> '+ 'Contact No: ' + list[i].contact.phone + ' </br></br> '+ 'Joined date: ' + list[i].date + ' </br> </br>'+ 'InvestedAmount: ' + list[i].account.investedAmount + '</span></td></tr></tbody><table></li>');
}
$("#sponsorListTree li").click(function() {
var name = $(this)[0].innerHTML;
var details = $(this).find('span')[0].innerHTML
var div_name = document.createElement('div');
var div_details = document.createElement('div');
div_name.innerHTML = name;
div_details.innerHTML = details;
div_name.className ="nameDetail";
div_details.className ="detail";
var div_group = document.createElement('div');
div_group.append(div_name);
div_group.append(div_details);
document.getElementById("name").append(div_group);
});
$(".button").click(function() {
$("span").toggleClass("details");
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul style=" overflow-x: auto; width: 400%; height: 600px;">
<li>
<a id="root" href="#"></a>
<ul id ="sponsorListTree">
</ul>
</li>
</ul>
<div id = "name" class="control-label"></div>

jQuery not changing the image source attribute on dynamically created image

I am dynamically creating elements on click on my page:
<img
src="/imagecache/large/{{ $issue->first()->image }}"
onclick="magazineDetail(
'{{ $issue->first()->magazine->id }}',
'{{ $issue->first()->magazine->name }}',
'{{ $issue->first()->magazine->summary ?: '' }}',
'{{ $issue->first()->magazine->image ?: '' }}',
'{{ $issue->first()->image }}'
)"
>
I call this script with the click:
function magazineDetail(id, name, summary, issueImage, magazineImage){
images = [];
nextImage = 0;
loadedImages = [];
$('#magazine-detail')[0].innerHTML = '<section id="magazine-detail" class="magazine-detail"><div class="large-6 medium-6 small-12 columns"><div class="magazine-hero"><img id="image" src="/imagecache/cover/' + magazineImage + '" alt="' + name + '" /><div class="magazine-preview-nav"><div class="right-arrow" id="forward"><img src="/img/right-arrow-black.svg" /><p>Neste utgivelse</p></div><div class="left-arrow" id="back"><img src="/img/left-arrow-black.svg" /><p>Forrige utgivelse</p></div></div></div></div><div class="large-6 medium-6 small-12 columns"><div class="row"><div class="small-6 columns magazine-title"><h1 id="name"></h1></div></div><p id="summary"></p><img id="issueImage" src="" alt="" /><p></p><button class="button primary expand">Kjøp abonnement - 1 måned gratis</button><button class="button secondary expand">Bla igjennom arkivet</button></div></section>';
$('#image').attr({"src" : '/imagecache/cover/' + magazineImage, "alt" : name});
$('#name').text(name);
$('#summary').text(summary);
if (issueImage != '') {
$('#issueImage').html('<img src="/imagecache/medium/"' + issueImage + ' alt="' + name + '">');
}
$('html, body').animate({
scrollTop: $("#magazine-detail").offset().top + 1500
}, 1700);
$.getJSON("issue/images",
{ id: id },
function(result){
if (result.length < 2){
$('.magazine-preview-nav').hide();
} else {
$('.magazine-preview-nav').show();
}
$.each(result, function(i, value){
images.push(value);
});
function imagePreload() {
preload();
};
});
console.log(images);
}
There I have <div class="magazine-hero"><img id="image" src="/imagecache/cover/' + magazineImage + '" alt="' + name + '" /> that I am creating in $('#magazine-detail')[0].innerHTML.
Then I have a function that should change the src of that element with the id="image" that is being created on click.
This is the script that takes care of that:
$(document).ready(function () {
imagesIndex = 0;
nextImage = 0;
loadedImages = new Array();
function preload() {
console.log('entered');
for (i = 0; i < 2; i++) {
if (nextImage < images.length) {
var img = new Image();
img.src = '/imagecache/cover/' + images[nextImage];
loadedImages[nextImage] = img;
++nextImage;
}
}
}
$('#magazine-detail').on('click','#forward', function() {
imagesIndex++;
preload();
if (imagesIndex > (loadedImages.length - 1)) {
imagesIndex = loadedImages.length - 1;
}
console.log(loadedImages.length);
console.log(loadedImages[imagesIndex].src);
$('#image').attr({"src" : loadedImages[imagesIndex].src, "alt" : name});
});
$('#magazine-detail').on('click','#forward', function() {
imagesIndex--;
if (imagesIndex < 0) {
imagesIndex = 0;
}
$('#image').attr({"src" : loadedImages[imagesIndex].src, "alt" : name});
});
});
On inspecting the console.logs I see that the new images are being created with the preload function, and that the correct image src is being passed to:
$('#image').attr({"src" : loadedImages[imagesIndex].src, "alt" : name});
But the image on page is not being changed. I should also maybe mention that everything worked fine when I wasn't creating those elements after the page has loaded but had them hiddden.
It seems that there is a minor bug in the $(document).ready(function(){ }); .
The code has 2 click events for same button #forward. Probably one should be assigned to #back button.

.replacewith not working when called a second time

I have the following markup:
<fieldset>
<legend>Headline Events...</legend>
<div style="width:100%; margin-top:10px;">
<div style="width:100%; float:none;" class="clear-fix">
<div style="width:400px; float:left; margin-bottom:8px;">
<div style="width:150px; float:left; text-align:right; padding-top:7px;">
Team Filter:
</div>
<div style="width:250px; float:left;">
<input id="teamFilter" style="width: 100%" />
</div>
</div>
<div style="width:400px; float:left; margin-bottom:8px;">
<div style="width:150px; float:left; text-align:right; padding-top:7px;">
Type Filter:
</div>
<div style="width:250px; float:left;">
<input id="typeFilter" style="width: 100%" />
</div>
</div>
</div>
</div>
<div id="diaryTable" name="diaryTable" class="clear-fix">
Getting latest Headlines...
</div>
</fieldset>
I also have the following scripts
<script>
function teamFilterChange(e) {
//alert(this.value());
setCookie('c_team', this.value(), 90);
$c1 = getCookie('c_team');
$c2 = getCookie('c_type');
var param = "true|" + $c1 + "|" + $c2;
outputHLDiaryEntries(param);
}
function typeFilterChange(e) {
//alert(this.value());
setCookie('c_type', this.value(), 90);
$c1 = getCookie('c_team');
$c2 = getCookie('c_type');
var param = "true|" + $c1 + "|" + $c2;
outputHLDiaryEntries(param);
}
// This optional function html-encodes messages for display in the page.
function htmlEncode(value) {
var encodedValue = $('<div />').text(value).html();
return encodedValue;
}
function outputHLDiaryEntries(param) {
var url = "Home/DiaryEntries/";
var data = "id=" + param;
$.post(url, data, function (json) {
var n = json.length;
alert(n + ' ' + json);
if(n == 0){
//json is 0 length this happens when there were no errors and there were no results
$('#diaryTable').replaceWith("<span style='color:#e00;'><strong>Sorry: </strong> There are no headline events found. Check your filters.</span>");
} else {
//json has a length so it may be results or an error message
//if jsom[0].dID is undefined then this mean that json contains the error message from an exception
if (typeof json[0].dID != 'undefined') {
//json[0].dDI has a value so we
//output the json formatted results
var out = "";
var i;
var a = "N" //used to change the class for Normal and Alternate rows
for (i = 0; i < json.length; i++) {
out += '<div class="dOuter' + a + '">';
out += '<div class="dInner">' + json[i].dDate + '</div>';
out += '<div class="dInner">' + json[i].dRef + '</div>';
out += '<div class="dInner">' + json[i].dTeam + '</div>';
out += '<div class="dInner">' + json[i].dCreatedBy + '</div>';
out += '<div class="dType ' + json[i].dType + '">' + json[i].dType + '</div>';
out += '<div class="dServer">' + json[i].dServer + '</div>';
out += '<div class="dComment">' + htmlEncode(json[i].dComment) + '</div></div>';
//toggle for normal - alternate rows
if (a == "N") {
a = "A";
} else {
a = "N";
}
}
//output our formated data to the diaryTable div
$('#diaryTable').replaceWith(out);
} else {
//error so output json string
$('#diaryTable').replaceWith(json);
}
}
}, 'json');
}
$(document).ready(function () {
//Set User Preferences
//First check cookies and if null or empty set to default values
var $c1 = getCookie('c_team');
if ($c1 == "") {
//team cookie does not exists or has expired
setCookie('c_team', 'ALL', 90);
$c1 = "ALL";
}
var $c2 = getCookie('c_type');
if ($c2 == "") {
//type cookie does not exists or has expired
setCookie('c_type', "ALL", 90);
$c2 = "ALL";
}
// create DropDownList from input HTML element
//teamFilter
$("#teamFilter").kendoDropDownList({
dataTextField: "SupportTeamText",
dataValueField: "SupportTeamValue",
dataSource: {
transport: {
read: {
dataType: "json",
url: "Home/SupportTeams?i=1",
}
}
}
});
var teamFilter = $("#teamFilter").data("kendoDropDownList");
teamFilter.bind("change", teamFilterChange);
teamFilter.value($c1);
//typeFilter
$("#typeFilter").kendoDropDownList({
dataTextField: "dTypeText",
dataValueField: "dTypeValue",
dataSource: {
transport: {
read: {
dataType: "json",
url: "Home/DiaryTypes?i=1",
}
}
}
});
var typeFilter = $("#typeFilter").data("kendoDropDownList");
typeFilter.bind("change", typeFilterChange);
typeFilter.value($c2);
// Save the reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// Invoke the function to be called back from the server
// when changes are detected
// Create a function that the hub can call back to display new diary HiLights.
dHub.client.addNewDiaryHiLiteToPage = function (name, message) {
// Add the message to the page.
$('#discussion').append('<li><strong>' + htmlEncode(name)
+ '</strong>: ' + htmlEncode(message) + '</li>');
};
// Start the SignalR client-side listener
$.connection.hub.start().done(function () {
// Do here any initialization work you may need
var param = "true|" + $c1 + "|" + $c2;
outputHLDiaryEntries(param)
});
});
</script>
On initial page load the outputHLDiaryEntries function is called when the signalR hub is started. If I then change any of the dropdownlists this calls the outputHLDiaryEntries but the $('#diaryTable').replaceWith(); does not work. If I refresh the page the correct data is displayed.
UPDATE!
Based on A.Wolff's comments I fixed the issue by wrapping the content I needed with the same element I was replacing... by adding the following line at the beginning of the outputHLDiartEntries function...
var outStart = '<div id="diaryTable" name="diaryTable" class="clear-fix">';
var outEnd = '</div>';
and then changing each of the replaceWith so that they included the wrappers e.g.
$('#diaryTable').replaceWith(outStart + out + outEnd);
replaceWith() replaces element itself, so then on any next call to $('#diaryTable') will return empty matched set.
You best bet is to replace element's content instead, e.g:
$('#diaryTable').html("<span>New content</span>");
I had the same problem with replaceWith() not working when called a second time.
This answer helped me figure out what I was doing wrong.
The change I made was assigning the same id to the new table I was creating.
Then when I would call my update function again, it would create a new table, assign it the same id, grab the previous table by the id, and replace it.
let newTable = document.createElement('table');
newTable.id = "sameId";
//do the work to create the table here
let oldTable = document.getElementById('sameId');
oldTable.replaceWith(newTable);

Masonry why arranging in single column overlapping

I am using the appended function to append elements to an already initialized masonry instance, but all of my tiles are being laid out in a single column and many are overlapping. Can you see what I am doing wrong?
function placeNewsTiles(news){ //places news tiles
var length = (news.data.length > 20) ? 20 : news.data.length;
var $container = $('#news');
var elems ="";
for(var i = 0; i < length; i++){
elems += '<div class="pageNewsItem" id="'+ count + i + '">\
<div class="textWrap">\
<a href="' + news.data[i]._url + '">\
<strong>' + news.data[i]._title + '</strong>\
</a>\
<span class="source">' + news.data[i]._source + '</span>\
</div>\
<div class="imageWrap"></div>\
<div class="thumbsOverlay" style="display:none">\
<div class="thumbs">\
<div>\
<img src="../images/Thumbs-Up-2.png" />\
<img src="../images/Thumbs-Down-2.png" />\
</div>\
</div>\
</div>\
</div>';
getTileImage({total: news.count, i:count + "" + i, url:news.data[i]._url});
}
elems = $(elems);
$('#news').append(elems).imagesLoaded(function(){
$('#news').masonry( 'appended', elems, true );
});
newsPage = 0;
count++;
hoverTiles();
}
$(document).ready(function() {
newClock();
readyLogin();
var $container = $('#news');
//$container.imagesLoaded( function() {
$container.masonry({itemSelector: '.pageNewsItem'});
//});
obtainSearchQuery();
});
On this line, try triggering layout once items are appended:
$('#news').masonry( 'appended', elems, true ).masonry('layout');
I've seen examples with and without the extra .masonry() call, but it might work.

Categories

Resources