trying to understand why its not working.
I have something like this.
<div class="carousel slide" id="new-prospect-container">
<div class="carousel-inner">
{{#each model}}
<div class="item">
...
</div>
{{/each}}
</div>
</div>
But Botostrap's first class api means that we don't need to execute any JS methods and their widgets will work automatically. The problem is I suspect Bootstrap would have executed this prior to my {{model}} being filled up by an Ajax requests. So this Carousel won't work.
What's annoying is i already tried turning off their data-api - $(document).off('.data-api'); and manually call their carousel method - still won't work.
The carousel works with hard coded data - but once I try to populate the carousel div items from my Ember model, it just stops working.
Any idea?
Why does this exist - https://github.com/emberjs-addons/ember-bootstrap ? does it exist to exactly solve my issue here? (although there's no carousel)
1 - I hope that this jsfiddle solve your problem.
App.CarouselView = Ember.View.extend({
templateName: 'carousel',
classNames: ['carousel', 'slide'],
init: function() {
this._super.apply(this, arguments);
// disable the data api from boostrap
$(document).off('.data-api');
// at least one item must have the active class, so we set the first here, and the class will be added by class binding
var obj = this.get('content.firstObject');
Ember.set(obj, 'isActive', true);
},
previousSlide: function() {
this.$().carousel('prev');
},
nextSlide: function() {
this.$().carousel('next');
},
didInsertElement: function() {
this.$().carousel();
},
indicatorsView: Ember.CollectionView.extend({
tagName: 'ol',
classNames: ['carousel-indicators'],
contentBinding: 'parentView.content',
itemViewClass: Ember.View.extend({
click: function() {
var $elem = this.get("parentView.parentView").$();
$elem.carousel(this.get("contentIndex"));
},
template: Ember.Handlebars.compile(''),
classNameBindings: ['content.isActive:active']
})
}),
itemsView: Ember.CollectionView.extend({
classNames: ['carousel-inner'],
contentBinding: 'parentView.content',
itemViewClass: Ember.View.extend({
classNames: ['item'],
classNameBindings: ['content.isActive:active'],
template: Ember.Handlebars.compile('\
<img {{bindAttr src="view.content.image"}} alt=""/>\
<div class="carousel-caption">\
<h4>{{view.content.title}}</h4>\
<p>{{view.content.content}}</p>\
</div>')
})
})
});
2 - I don't know why the carousel isn't include in ember-boostrap.
So I have a solution for this, but it's not for the squeamish.
Bootstrap isn't specific enough about what elements it looks for in the case of the Carousel. When the carousel function goes to inventory what elements it's to manipulate, it chokes on the metamorph tags that Ember injects into the DOM. Basically, when it goes to see how many images there are, it will always find 2 more than there actually are.
I made changes to the underlying code of the carousel in the bootstrap library, here's what I did.
Line 337, change:
this.$items = this.$active.parent().children()
TO
this.$items = this.$active.parent().children('.item')
Line 379, change:
var $next = next || $active[type]()
TO
var $next = next || $active[type]('.item')
Line 401, change:
var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
TO
var $nextIndicator = $(that.$indicators.children('li')[that.getActiveIndex()])
This helps the carousel plugin ignore the metamorph tags.
Hope this helps.
I had the same issue and solved it by using the following method. Note that I'm using ember-cli but it's fairly easy to adapt.
This is the templates/components/photo-carousel.hbs file:
<div id="my-carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
{{#each photo in photos}}
<li data-target="#my-carousel" data-slide-to=""></li>
{{/each}}
</ol>
<div class="carousel-inner" role="listbox">
{{#each photo in photos}}
<div class="item">
<img {{bind-attr src="photo.completeUrl" title="photo.caption" alt="photo.caption"}} />
<div class="carousel-caption">
{{photo.caption}}
</div>
</div>
{{/each}}
</div>
<!-- removed right and left controls for clarity -->
</div>
This is the components/photo-carousel.js:
export default Ember.Component.extend({
didInsertElement: function () {
// Add the active classes (required by the carousel to work)
Ember.$('.carousel-inner div.item').first().addClass('active');
Ember.$('.carousel-indicators li').first().addClass('active');
// Set the values of data-slide-to attributes
Ember.$('.carousel-indicators li').each(function (index, li) {
Ember.$(li).attr('data-slide-to', index);
});
// Start the carousel
Ember.$('.carousel').carousel();
}
});
Note that setting the active classes manually will not be required with future versions of Ember since the each helper will provide the index of the current item.
Related
I'm using the Siema carousel on my site with Zepto. I'd like to be able to indicate what slide the user is currently on. How do I do this if there is only an onChange event available?
HTML
<section class="images">
<img/>
<img/>
</section>
<section class="indicators">
<span class="active"></span>
<span></span>
</section>
JS
$(document).ready(function() {
new Siema({
selector: '.images',
onChange: () => {
console.log("swiped");
// change active indicator?
},
});
});
I think I can help (I'm the author of Siema).
// extend a Siema class and add addDots() & updateDots() methods
const mySiemaWithDots = new SiemaWithDots({
// on init trigger method created above
onInit: function(){
this.addDots();
this.updateDots();
},
// on change trigger method created above
onChange: function(){
this.updateDots()
},
});
https://codepen.io/pawelgrzybek/pen/boQQWy
Have a lovely day 🥑
I am quite new to Meteor and Blaze so I am sorry if something is unclear here... But I want to implement this 'Product Quick View' https://codyhouse.co/gem/css-product-quick-view/ in my Meteor project.
The animation is working great when I am not using each statement. In each statement the data context change and when I click cd-trigger nothing happens. How can I access the code inside ParentTemplate.onRendered for this child Template? Is there some workaround to this problem?
<template name="ParentTemplate">
{{> Product}} // works properly
{{#each products}} // does not work
{{> Product}}
{{/each}}
</template>
<template name="Product">
<li class="cd-item">
<img src="img/item-1.jpg" alt="Item Preview">
Quick View
</li> <!-- cd-item -->
</template>
and the .js file
Template.ParentTemplate.onRendered( function () {
//open the quick view panel
$('.cd-trigger').on('click', function(event){
console.log('Hello!');
var selectedImage = $(this).parent('.cd-item').children('img'),
slectedImageUrl = selectedImage.attr('src');
/the code continues but it is very long/
This fixed the problem
Template.ParentTemplate.onRendered( function () {
this.autorun(() => {
if (this.subscriptionsReady()) {
//open the quick view panel
$('.cd-trigger').on('click', function(event){
console.log('Hello!');
var selectedImage = $(this).parent('.cd-item').children('img'),
slectedImageUrl = selectedImage.attr('src');
/the code continues but it is very long/
I'm attempting to reuse a custom Block Helper that I wrote to provide basic carousel functionality to some of my templates.
simple-carousel.html
<template name="SimpleCarousel">
<div class="simple-carousel {{class}}">
<div class="slides">
{{#each slides}}
{{> UI.contentBlock this}}
{{/each}}
</div>
{{#if showControls}}
{{> SimpleCarouselControls}}
{{/if}}
</div>
</template>
<template name="SimpleCarouselControls">
// control structure here
</template>
simple-carousel.js
var actions = {
back: function() {
// move slide back once
},
forward: function() {
// move slide forward once
}
};
var showSlide = function() {
// code to show the next slide
};
Template.SimpleCarousel.onRendered(function() {
// set up carousel logic here
});
Template.SimpleCarousel.events({
'click [data-sc-move="forward"]': function() {
actions.forward();
},
'click [data-sc-move="back"]': function() {
actions.back();
}
});
breaking_stories.html
<template name="BreakingStories">
{{#SimpleCarousel class="breaking-stories" showControls=false autoForward=8000 slides=breakingStories}}
{{> BreakingStorySlide}}
{{/SimpleCarousel}}
</template>
<template name="BreakingStorySlide">
<div class="breaking-story slide">
<div class=breaking-story-title">{{title}}</div>
</div>
</template>
breaking_stories.js
Template.BreakingStories.helpers({
breakingStories: function() {
return BreakingStories.find();
}
});
daily_summary.html
<template name="DailySummary">
{{#with thisDailySummary}}
{{#SimpleCarousel class="daily-summaries" showControls=true slides=items}}
{{> DailySummarySlide}}
{{/SimpleCarousel}}
{{/with}}
</template>
<template name="DailySummarySlide">
<div class="daily-summary slide">
<div class="daily-summary-title">{{title}}</div>
</div>
</template>
I've tried to simplify the code as there is a lot more HTML involved in the templates. Anyway, as you can see I've defined the #SimpleCarousel block helper and used it in two places: the breaking stories section, and the daily summaries section. These two templates happen to be on the same page (route), so they are near each other on the page. I need one of them to auto cycle through, in which I've provided the autoForward property to the helper, and the other one should just show controls.
Both templates render fine and show the correct data, but the problem lies in that instead of the breaking news template doing any automatic cycling, the other one does (and does it twice), as if they are sharing the same context.
My question is, can I use custom Block Helpers multiple times on the same route safely? I'm open to any suggestions on how to do this a better/different way.
Thanks to #JeremyK for pointing me in the right direction; it happened to be the exact code I left out which was the problem. Of course!
Here's what I had in the old version:
simple_carousel.js
var $slideContainer, $controls, $markers, $activeSlide, $nextSlide;
var actions = {
back: function() {
// move slide back
},
forward: function() {
// move slide forward
}
};
function showSlide() {
// show the "next" slide
}
Template.SimpleCarousel.onRendered(function() {
var data = this.data;
$slideContainer = this.$('.sc-slides');
// rest of this code is irrelevant
});
I had thought that the variables I had declared on the first line were independent of multiple instantiations of the templates I was using, but I was wrong. The first use of $slideContainer = this.$('.sc-slides'); worked fine, but $slideContainer and all the others are shared.
To fix this, I simply moved the local variables/actions into Template.SimpleCarousel.onRendered
Template.SimpleCarousel.onRendered(function() {
var $slideContainer, $markers, ...
this.actions = {
//...
};
});
Template.SimpleCarousel.events({
'click [data-sc-move="forward"]': function( event, template ) {
template.actions.forward();
}
//...
});
I've got a Marionette layout and for demo purposes the html looks like:
<header id="header-region" class="page-title"></header>
<section id="template-content" class="full-section">
<div id="error-messages" class="fade main-section"><!-- errors --></div>
<div id="content-region"> </div>
</section>
Its layout view's regions are:
regions: {
header: "#header-region",
content: "#content-region"
}
Up until now, I've had any given page's modal html inside the page's template html which would be contained in the content region.
I have an idea to now create a separate region for modals to be shown in.
Changing things to look like this:
Template:
<section id="template-content" class="full-section">
<div id="error-messages" class="fade main-section"><!-- errors --></div>
<div id="content-region"> </div>
<div id="modal-region"></div>
</section>
And the region:
regions: {
header: "#header-region",
content: "#content-region",
modal: "#modal-region"
}
So I'd like to be able to do something like this:
// Controller
define([], function(){
initialize: function(){},
showHeaderView: function(){
this.HeaderView = new HeaderView();
this.layout.header.show(this.HeaderView);
},
showContentView: function(){
// this.BodyView's template used to contain the modal html
this.BodyView = new BodyView();
this.layout.content.show(this.BodyView);
},
showModalView: function(){
this.ModalView = new ModalView();
this.layout.modal.show(this.ModalView);
}
});
This works and renders the modal properly but the modal's events are lost because they were originally set by this.BodyView.
The modal has a checkbox that on change runs a function that is on this.BodyView but I want to bind the events for this.ModalView from this.BodyView.
How can I accomplish that? I've tried making this.ModalView's el the same as this.BodyView's but that breaks things. I've tried to use delegateEvents as well but with no luck.
This screencast does exactly what you want: http://www.backbonerails.com/screencasts/building-dialogs-with-custom-regions
Code is here: https://github.com/brian-mann/sc01-dialogs
If you are having the HeaderView as ItemView(or CollectionView/CompositeView) in it, you can instantiate it with passing arguments like
new HeaderView({events:{
"click .x" : function(){} // your function in-line or reference
});
So same applies to ModalView.
I'm new to emberjs and I'm having a bit of trouble understanding how classNameBindings work.
Here's my current set up - http://jsfiddle.net/inquen/AXza5/
(this is how it should work: http://jsfiddle.net/inquen/N4WJS/)
The template
<script type="text/x-handlebars">
<div class="main-container">
<div class="doors">
{{#view StandClear.DoorView class="left-door"}}<div class="door-window"></div>{{/view}}
{{#view StandClear.DoorView class="right-door"}}<div class="door-window"></div>{{/view}}
</div>
<div class="door-closure-lamp"></div>
{{#view StandClear.DoorStateView}}
Toggle Doors
{{/view}}
</div>
</script>​
StandClear = Ember.Application.create();
The JavaScript
StandClear.doorController = Ember.Controller.create({
doorsOpen: true,
toggleDoors:function(e){
this.doorsOpen = (this.doorsOpen === false) ? true : false;
console.log(this.doorsOpen);
}
});
StandClear.DoorView = Ember.View.extend({
tagName: 'div',
classNames:['car-door'],
classNameBindings: 'StandClear.doorController.doorsOpen',
})
StandClear.DoorStateView = Ember.View.extend({
tagName: 'button',
classNames:['door-controller'],
click:function(e){
StandClear.doorController.toggleDoors();
}
});
The class name binding works when the page is loaded, but doesn't change when the value it is bound to changes.
I feel there are a number of structural issues with my code as well, I'd appreciate some feedback on this as well.