Masonry doesn't work properly with Meteor - meteor

I have created a test project with Meteor which uses Masonry. I added the package mrt:jquery-masonry(or isotope:isotope), and it works well at the beginning. However, the problem comes now.
Basically, I want to implement the feature that when user clicks the button, the page will be added one more div. Below is my code:
main.html
<body>
<div class="container">
{{> masonryContent}}
</div>
<script>
(function($){
var $container = $('.masonry-container');
$container.masonry({
columnWidth: 300,
gutterWidth: 50,
itemSelector: '.masonry-item'
})
}(jQuery));
</script>
</body>
style.css
.masonry-item {
width: 300px;
}
masonry-content.html
<template name="masonryContent">
<div class="masonry-container">
<div class="masonry-item">
<p>blabla...</p>
<p>
Button
</p>
</div>
<div class="masonry-item">
<p>test...</p>
</div>
<div class="masonry-item">
<p>another test...</p>
</div>
{{#if showItem}}
<div class="masonry-item">
<p>new added item...</p>
</div>
{{/if}}
</div>
</template>
masonry-content.js
Template.masonryContent.events({
"click #click-me": function(e) {
e.preventDefault();
Session.set('show_me', true);
}
});
Template.masonryContent.helpers({
showItem: function() {
return !!Session.get('show_me');
}
});
The problem is when I click the button, the new div was created; however, it wasn't placed by following Masonry rules. The new created item just overlapped to the first item, but I expect it performs the way to append to the last item.
I would appreciate if anyone could help me on this.
Thanks in advance!

As meteor does partial rendering the element needs to be there in the DOM for masonry to work. So there are two ways of getting over the problem
1) Hide or unhide the element when the button click happens
Or
2) re-render the DOM
You can use the chrome dev tools to see what DOM elements are touched/refreshed (Green color).

There is a typo in masonry in the template name insertion.
Check the package state, many mrt packages are not well supported anymore.

Related

dropzone-meteor howto fire events

i'm new to Meteor and and i want to learn something about it. therefore i want to build a page were i can upload images via meteor-dropzone.
the upload is working with meteor-uploads.
now i want to get events, like 'addedfile' or 'drop' from the dropzone to fire some new functions.
HTML Page Profile2:
<template name="profile2">
<div class="ibox-content">
{{> dropzone url='http://localhost:3000/uploads' maxFilesize=5 addRemoveLinks=true acceptedFiles='image/*,jpg,jpeg,png' id='dropzoneDiv'}}
</div>
</template name="profile2">
In The JS File for Profile2 i wrote this:
Template.dropzone.events({
'addedfile #dropzoneDiv': function(e, template){
e.preventDefault();
console.log("Hello");
}
});
But i don't see something in the console.log output.
I'm sure i'm doing something wrong. But i have no i idea where the problem or the wrong understanding is.
Can somebody help me please.
Thanks.
Michael
after try and error. i found the solution. Maybe someone can explain it to me. because i don't understand it completely, why it's working now but so different to the normal Meteor event version.
Dropzone.options.dropzoneDiv = {
init: function() {
this.on("addedfile", function(file) { alert("Added file."); });
}
};
The Template like that:
<!-- Page heading -->
{{> pageHeading title='File upload' category='Forms' }}
<div class="wrapper wrapper-content animated fadeIn">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>Dropzone Area</h5>
{{>iboxTools}}
</div>
<div class="ibox-content">
<!-- For more info about dropzone plugin see this: https://github.com/devonbarrett/meteor-dropzone/ -->
{{> dropzone url='/uploads' id='dropzoneDiv'}}
</div>
</div>
</div>
</div>
</div>
</template>
Try the dropped event:
'dropped #dropzoneDiv' (e, template) => {
e.preventDefault();
console.log(e.originalEvent.dataTransfer.files); // this will contain the list of files that were dropped
}

FullpageJs and Meteor : Capture event from template

I'm struggling with fullpage.js in Meteor.
When I add a button inside a template, the Template.templatename.events function does not fire on event.
For example:
Template HTML (messages.html)
<template name="messages">
<ul>
{{#each mess}}
<li>{{ messContent}}</li>
{{/each}}
<button class="addMessage">Add Message!</button>
</ul>
</template>
Template JavaScript (messages.js)
Template.messages.helpers({
mess: function(){
return Messages.find();
}
});
Template.messages.events({
'click .addMessage' : function(event){
console.log("clicked")
}
})
Main HTML
<head>
<title>fulltest</title>
</head>
<body>
{{> full}}
</body>
<template name="full">
<div id="fullpage">
<div class="section active">
<h1>First slide</h1>
{{> messages}}
</div>
<div class="section">
<h1>Second slide</h1>
</div>
</div>
</template>
My fullpage initialisation:
Template.full.rendered = function(){
$('#fullpage').fullpage();
}
If I remove the fullpage initialisation then the click event gets logged. Still new at Meteor, I didn't manage to grasp what's going wrong here.
All help much appreciated,
Joris
Use delegation or use verticalCentered:false and scrollOverflow:false.
From the fullPage.js FAQs:
My javascript/jQuery events don't work anymore when using fullPage.js
Short answer: if you are using options such as verticalCentered:true or overflowScroll:true in fullPage.js initialization, then you will have to treat your selectors as dynamic elements and use delegation. (by using things such as on from jQuery). Another option is to add your code in the afterRender callback of fullpage.js
Explanation: if you are using options such as verticalCentered:true or overflowScroll:true of fullPage.js, your content will be wrapped inside other elements changing its position in the DOM structure of the site. This way, your content would be consider as "dynamically added content" and most plugins need the content to be originally on the site to perform their tasks. Using the afterRender callback to initialize your plugins, fullPage.js makes sure to initialize them only when fullPage.js has stopped changing the DOM structure of the site.

How do i get an onload function on the body for a specific template using meteor.js?

I'm trying to get the following behavior for a certain template:
<body onload="someInitFunction();">
Let's say i have the following markup (i'm using mrt router, not iron-router, for {{renderPage}}):
// Main Template
<head>
<title>meteorite-knowviz</title>
</head>
<body>
{{> header}}
<div class="container-fluid">
<div class="row">
{{renderPage}}
</div>
</div>
{{> footer}}
</body>
That renderPage is the secondTemplate:
<template name="secondTemplate">
{{#if currentUser}}
<div class="col-md-2">
<div class="list-group">
<a class="list-group-item" href="{{render thirdTemplate please...}}">Third Template</a>
<a class="list-group-item" href="{{render fourthTemplate please...}}">Fourth Template</a>
</div>
</div>
// In this case let's say thirdTemplate gets rendered
{{render the choice taken above please...}}
{{/if}}
</template>
And within this template, depending on which link was clicked on, (in this case the third) there will finally be a thirdTemplate, which will show a data visualization with some help by a javascript framework, which will be in need of a <body onload="initFunction();">in order to display the data:
<template name="thirdTemplate">
<div class="col-md-5">
<h2>THIS!! section needs a "<body onload="initFunction();"> in order to work" ></h2>
</div>
<div class="col-sm-5">
<h2>Some other related content here</h2>
</div>
</template>
To sum up i have three questions:
1a. How could i get the third template to get a <body onload="initFunction();">
2a. In which way can i render different templates within the secondTemplate?
2b. Can i use a {{renderPage}} within this template even though this template is the renderedPage in the main template or should i do it in some other way?
In order to get the <body onload="initFunction();"> i had to do the following:
First add the following function to a .js file in the client folder:
Template.thirdTemplate.rendered = function() { // Template.thirdTemplate.created - also worked.
$('body').attr({
onload: 'init();'
});
}
This however got me an error saying that initFunction is not defined. In an standard html page my could work just fine, but in meteor i had to change my function from:
function initFunction(){
//what ever i wished to do
}
To:
init = function() {
//what ever i wished to do
}
Regarding the rendering of pages, iron-routing is the way to go since the router add on is not under development any more.
1a. How could i get the third template to get a <body
onload="initFunction();">
You probably want to call initFunction when the third template has been rendered, so just put your call to it in the rendered callback.
Template['thirsTemplate'].rendered = function(){
initFunction()
}
2a. In which way can i render different templates within the
secondTemplate?
2b. Can i use a {{renderPage}} within this template even though this
template is the renderedPage in the main template or should i do it in
some other way?
Listen for clicks on the links, and when one happen you manually render the desired template (possible with Meteor.render, if you need reactivity) and add it to the right node in the document. See this question.
It may be possibly to achieve with router (I don't know that package).
I think that what you want to use is the created callback, that will be called each time your template is created, and not the rendered callback, that would be called each time a change has caused the template to re-render.
Template.thirdTemplate.created = function(){
initFunction()
}
See the documentation for templates for other types of callbacks: http://docs.meteor.com/#templates_api

Using Angular Masonry in AngularJS?

I have a layout like this. I am using passsy extension for angular masonry.
<masonry column-width="200">
<div class="masonry-brick" ng-repeat="data in comments">
<div ng-switch on="data.type">
<div ng-switch-when="hoots">
<article class="hoot_main">
//content goes here
//hoot_main is the main class for this div layout
</article>
</div>
</div>
</div>
<div ng-switch on="data.type">
<div ng-switch-when="article">
<article class="hoot_main">
//content goes here
//hoot_main is the main class for this div layout
</article>
</div>
</div>
<div ng-switch on="data.type">
<div ng-switch-when="story">
<article class="hoot_main">
//content goes here
//hoot_main is the main class for this div layout
</article>
</div>
</div>
</div>
</masonry>
Browser is getting hanged whenever I use it. Debugging script with tools says element.masonry is not a function.
Any help would be appreciated!
Hmm, at the moment I work from my laptop at home and I can't get passy's version running too and can not put my finger on the issue. But this is what I can offer you for now:
I made a very simple directive based on things I've read somewhere:
app.directive('masonry', function() {
return {
restrict: 'AC',
controller: function($scope) {
return $scope.$watch(function(e) {
$scope.masonry.reloadItems();
return $scope.masonry.layout();
});
},
link: function(scope, elem, attrs) {
var container=elem[0];
var options='';
return scope.masonry = new Masonry(container,options);
}
};
As you can see it does not have a any options by now. When i'm at work on monday i will have a look at my sources on a proper dual screen display and provide you with a better version.
My wife is starting to giving me the looks and I need to put the laptop away now. :-\
You can see in this plunker that it kinda works now. Maybe this can help you. In the meantime can you add some of your json data to your question? Have a nice weekend for now!
In order to get Passy's angularjs directive working you must include all the files as listed per the index file
I had this error, fixed it by including the original Masonry code. I was also thinking this was a pure angular port.

CSS that operates like a boolean AND for multiple complex selectors?

I'm writing a Stylish user style sheet, and am trying to see if something is possible. I am customizing a page that has a structure like this:
<div class="main">
<div class="someExtraLayers">
<div class="page">
1
</div>
</div>
<div class="someOtherLayers">
<div class="post">
blah blah
</div>
<div class="post">
foo foo
</div>
<div class="post">
bar bar
</div>
</div>
</div>
Where 'someExtraLayers' and 'someOtherLayers' indicate a few levels of divs inside divs. I'm not fully replicating the page's structure here for brevity's sake.
I have this in my user CSS:
div.post:nth-child(1) {
display:block !important;
}
Essentially, I'm making visible the first post element, and this does most of what I want to do. The thing I want to add is that I only want to make that element visible if the content of the page class is 1. If it's not 1, then I don't want to display the first post element.
CSS doesn't seem to offer conditionals, or boolean ANDs, that work this way. But I'm still new-ish to CSS, so I might be missing something. If I have to use a Greasemonkey script instead, I'll do that, but I was hoping there's some CSS trickery that will let me accomplish this.
Stylish cannot do this because Stylish just injects CSS and CSS does not have a selector for text content.
To do what you want, you will have to install Greasemonkey (Firefox) or Tampermonkey (Chrome) and then a userscript can set that visibility.
Assuming that div contains only 1, then something like this complete GM/TM script will do what you want. It uses the awesome power of jQuery selectors.
You can also see a live demo of the code at jsFiddle. :
// ==UserScript==
// #name _Show the first post on page 1
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #grant GM_addStyle
// ==/UserScript==
var pageHasOne = $("div.main:has(div.page:contains(1))");
pageHasOne.each ( function () {
var jThis = $(this); //-- this is a special var inside an .each()
var pageDiv = jThis.find ("div.page:contains(1)");
if ($.trim (pageDiv.text() ) == "1") {
//--- Show the first post div. !important is not needed here.
jThis.find ("div.post:first").css ("display", "block");
}
} );
Given the logic that jQuery javascript must use, we can see part of the reason why CSS doesn't attempt to provide selectors for this. It's beyond mission scope for CSS, but the kind of thing that javascript was made for.
Also note that this is for a static page. If the page uses AJAX for its content, the logic becomes a bit more involved.
CSS can not access HTML content.
To solve the problem, you will also need to add a class so CSS can "see" it:
HTML:
<div class="main one">
<div class="someExtraLayers">
<div class="page">
1
</div>
</div>
<div class="someOtherLayers">
<div class="post">
blah blah
</div>
<div class="post">
foo foo
</div>
<div class="post">
bar bar
</div>
</div>
</div>
CSS:
.one .post:nth-child(1) {
display:block !important;
}

Resources