Hi, this is my first post here, so please be gentle. I am making my first Meteor web app (to be compiled to Android and iOS later), but struggle with this:
(TL;DR at the bottom)
What I want to achieve is the following:
To have a set of images presented in a slider inside a (fullscreen) modal, where the images are reactively fetched from a CollectionFS.
I have almost managed to do this in my app, however:
- The images are not shown when the modal opens, but will become visible if I resize the screen and/or magnify +/-.
- If an update to the collection happens when the modal is open, the the new image is not properly added to the slider, but instead shown beneath/on top of the slider.
In hope for anyone to help, I have carefully prepared a minimal example.
My test case is created as follows (currently on Meteor 1.4, but I had this problem since 1.2 or before):
$ meteor create slider-in-modal-test
$ cd slider-in-modal-test
$ meteor npm install
$ meteor --version
Meteor 1.4.2.3
# Get some demo pics:
$ cd /tmp/
$ wget placehold.it/400x300.png
$ wget placehold.it/401x301.png
$ wget placehold.it/402x302.png
# Add the packages for the test:
$ meteor add cfs:standard-packages
$ meteor add cfs:filesystem
$ meteor add udondan:slick
# Modal, both needed I think:
$ meteor add twbs:bootstrap
$ meteor add peppelg:bootstrap-3-modal
# Slick slider:
$ meteor add udondan:slick
Now, modify/create sources:
client/main.html
<head>
<title>slider-in-modal-test</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
<!-- {{> carouselDynamic}} --> <!-- if the slider carousel is shown before the modal, it won't render correctly inside the modal -->
<br/>
{{> showModal}}
</body>
<Template name="showModal">
<button type="button" id="example" class="btn btn-default" >Show modal</button>
</Template>
<template name="exampleModal">
<div id="myModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal example</h4>
</div>
<div class="modal-body">
<p>A modal example.</p>
{{> carouselDynamic}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</template>
<template name="carouselDynamic">
<h>Slick carousel dynamic</h>
<div id="carouselDyn">
{{#each images}}
{{> carouselItem}}
{{/each}}
</div>
</template>
<Template name="carouselItem">
<div class="item">
<div><img src="{{this.url}}" width="200px" /></div>
</div>
</Template>
client/main.js
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
Meteor.subscribe('images');
Template.showModal.events({
'click button#example'(event, instance){
Modal.show('exampleModal')
//$('#myModal').modal('show');
},
});
Template.carouselDynamic.helpers({
images: function () {
return Images.find(); // Where Images is an FS.Collection instance
}
});
// As per http://stackoverflow.com/questions/30140232/meteor-with-iron-router-cant-get-slick-carousel-working
Template.carouselItem.onRendered( function() {
Meteor.subscribe('images');
$('#carouselDyn').slick({
dots: true,
arrows: true
})
});
client/main.css
/* CSS declarations go here */
#carouselDyn {
border: 1px solid black;
width: 200px;
position: relative;
top: 10px;
left: 10px;
}
#carouselDyn div {
width: 200px;
}
.slick-prev:before, .slick-next:before {
color: silver;
}
common.js (in the root folder, outside client/):
Images = new FS.Collection("images", {
stores: [new FS.Store.FileSystem("images")]
});
server/main.js
import { Meteor } from 'meteor/meteor';
Meteor.startup(() => {
// code to run on server at startup
Images.allow({
'insert': function () { return true;},
'update': function () { return true;},
'download': function () {return true;},
});
});
Meteor.publish("images", function () {
return Images.find()
});
Then put two of the example images into the MongoDB (note: full path to the images seems to be required):
$ meteor # run in separate terminal
$ meteor shell
> var f = new FS.File();
> f.attachData('/tmp/400x300.png')
> Images.insert(f)
> var f = new FS.File();
> f.attachData('/tmp/401x301.png')
> Images.insert(f)
Now, with meteor running, go to localhost:3000 and press the “show modal” button. It presents the modal as expected, with slick initiated also.
But, if you — with the modal still open — add one image:
$ meteor shell
> var f = new FS.File();
> f.attachData('/tmp/402x302.png')
> Images.insert(f)
it will not be reactively added, but rather go beneath the slider.
Since I want to replace the click button with the first image in the collection, and make it clickable to present the modal with the slider, I need to find out how to:
- Add images to the collection reactively, and make the slider rerender correctly.
- Be able to let the client subscribe to the collection, use the first image, but still correctly render slider in the modal when it is opened (see comment in main.html)
- Make the slider and the modal “fullscreen”, and still render correctly. The modal is okay with this css:
.modal-dialog {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.modal-content {
height: auto;
/* min-height: 100%; */
border-radius: 0;
}
but how to I set the slider to full width without destroying it?
TL;DR: Want to use slider inside modal in Meteor with images from Collection, but it doesn’t work as expected.
Any help appreciated!