I am learning backbone and am not aware much in backbone.I need to do image slider using backbone.Though I can do using jquery like this
The link is the demo as per my requirement.There are in total 3 images.When you click on the last image then 1st two images disappears and new 2 images appear.
Can anybody please guide me how to do similarly using backbone.
This is my code using jquery
<img id="image-1" src="http://lorempixel.com/150/100/abstract">
<img id="image-2" src="http://lorempixel.com/150/100/food">
<img id="arrow" src="http://placehold.it/50x100">
$('#arrow').click(function() {
$('#image-1').attr('src', 'http://lorempixel.com/150/100/city');
$('#image-2').attr('src', 'http://lorempixel.com/150/100/sports');
});
Any help will be upvoted
What you are looking for are Backbone Views.
I personally really like the TodoMVC example, which is complete introduction to Backbone and its different components.
What you will need to do is to first wrap your content into a identifiable div, something like:
<div id="slideshow">
<ul class="images">
<li><img src="http://lorempixel.com/150/100/abstract" /><li>
<li><img src="http://lorempixel.com/150/100/food" /><li>
</ul>
<a class="next" href="#">Next</a>
</div>
Note that:
I only use an ID for the wrapper, not inside of it. It's preferable since backbone views have nice mechanism to work only with its own content (look at events and selector).
I wrap images inside a <ul>. Again, only in the purpose of making the structure more meaningful and querying easier.
Then, your view code should look like:
var MySuperView = Backbone.View.extend({
events: {
"click .next": "next"
},
interval: 1000,
initialize: function() {
// this is like a constructor
var _this = this;
setTimeout(function() {
_this.next(); // calling next() every `interval` ms
}, _this.interval);
},
next: function() {
// here goes your logic
return false;
}
});
And finally, to bind the view to the matching element:
var view = new MySuperView();
view.setElement(document.getElementById("slideshow"));
And voilĂ :)
Related
edit: For new viewers of the question, my title is misleading. The solution to this problem had nothing to do with event bubbling/capturing as was my assumption at the time of posting.
I have a mobile navigation menu that contains 3 <li> elements which, when clicked, toggleSlide() a dropdown menu. The jQuery code for each of them is largely the same:
const coreSlider = function() {
const aContainer = document.querySelector('#dropdown-A');
const aLinks = document.querySelector('#A-links');
const dontOpen = document.querySelector('.mob-prev-def');
$(aContainer).on('click', function() {
$(aLinks).slideToggle(200);
});
$(dontOpen).on('click', function(e) {
e.preventDefault();
});
}
...
Above is an example of the jQuery code on 1 of these dropdown containers, and behaves exactly as I want it to (toggles the drop-down menu on click, but does not redirect to the href value inside the <li> inside the container. However, I still want the links that appear on click to direct them to the relevant part of my website.
There are 2 more containers with jQuery code exactly like this, but for whatever reason the e.preventDefault() part of the code on them doesn't work as intended, and redirects on click. I figure that event bubbling/ capturing has something to do with it, but I'm not sure how exactly it is functioning in this example. To that end, what's going on here and how can I fix it to ensure all containers behave as I want? Here's my HTML:
<ul id="nav-links">
<li id="dropdown-A">
...
<div id="A-links">
...
...
...
</div>
</li>
<li id="dropdown-D">
...
<div id="D-links">
...
...
...
...
</div>
</li>
<li id="dropdown-E">
...
<div id="E-links">
...
...
</div>
</li>
<li id="gallery">Gallery</li>
</ul>
Edit: thanks to user Stone3m, I managed to add in a solution:
const prevDef = function() {
const dontOpen = $('.mob-pref-dev');
$(dontOpen).on('click', function(e) {
e.preventDefault();
});
}
prevDef();
The issue here is that you are using querySelector, which only selects one occurrence.
You should be using querySelectorAll with a forEach loop for every occurrence.
A quick and simple method would be to:
document.querySelectorAll('.mob-prev-def').forEach(item => {
item.addEventListener('click', function(e) {
e.preventDefault()
})
})
Sorry, I prefer vanilla JavaScript, but you could figure it out in jQuery now (I hope!)
I created a on click function to create a new section and place it under the previous section, then calls in content from another file and scrolls to it. I can get it working but the problem lies when I bring in the content the JS does not recognize the new section and does not adjust it with scrolloverFlow. Here is the code that I'm using to make this happen. I know I'm supposed to destroy and rebuild it but I can't get it to rebuild to adjust the new height in the newly created section. Any help would be great.
HTML:
<div id="fullpage">
<div class="section" id="section0">Sec0</div>
<div class="section" id="section1">Sec1
<ul>
<li><span id="addSection">Add Section</span></li>
</ul>
</div>
<div class="section"></div>
</div>
JS:
$(document).ready(function(){
function fullPageInit() {
$('#fullpage').fullpage({
navigation: true,
navigationPosition: 'right',
scrollOverflow: true,
});
};
fullPageInit();
$(document).on('click', '#addSection', function(){
if($('#section2').length) {
$('#section2').remove();
}
$('#section1').after('<div class="section" id="section2">New Content goes here</div>');
$('#section2').load('content.php);
$.fn.fullpage.reBuild();
var activeSec = $('.fp-section.active').index();
$.fn.fullpage.destroy('all');
$('.section').eq(activeSec).addClass('active');
$('#section2').fadeIn('fast', function(){
setTimeout(function(){
fullPageInit();
$.fn.fullpage.moveSectionDown();
}, 0);
});
});
});
Thanks for commenting, that's what helped me get started. But I cant seem to figure out how to get the scrollOverflow working on the new section being created.
Use the reBuild function for it just after adding the section.
$.fn.fullpage.reBuild();
As detailed in the docs:
Updates the DOM structure to fit the new window size or its contents. Ideal to use in combination with AJAX calls or external changes in the DOM structure of the site, specially when using scrollOverflow:true.
Updated
You probably need to use the fullPageInitafter the fadeIn took takes place.
$('#section2').fadeIn("normal", function() {
fullPageInit();
$.fn.fullpage.moveSectionDown();
});
I'm using a jQuery grid slider plugin that I'd like to run again after DOM manipulation.
I suspect my issue is similar to this - Any way to rerun a jQuery plugin after DOM modification? - but my attempts aren't work.
Here's the setup:
When the page loads, the grid plugin js and the options js run against an unordered list, like such:
<div class="panel">
<div class="g-container">
<div class="g-slider">
<div class="tiles">
<ul>
<li><img src="Images/image-01.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/image-03.jpg"><div><h1>electronics</h1></div></li>
<li><img src="Images/image-02.jpg"><div><h1>medical</h1></div></li>
<li><img src="Images/image-11.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/image-02.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/image-09.jpg"><div><h1>medical</h1></div></li>
<li><img src="Images/image-11.jpg"><div><h1>electronics</h1></div></li>
</ul>
</div>
</div>
</div>
</div>
...and create the grid slider. Here's an example of what it looks like: http://1.s3.envato.com/files/27300390/index.html
This all works fine.
(Long story short) I have a large list of categories that are all grouped together that I've placed in a div holder, like so:
<div id="listing-holder">
<ul>
<li><img src="Images/car-01.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/car-01.jpg"><div><h1>electronics</h1></div></li>
...
</ul>
</div>
These categories are dynamically created and in one large (hidden off the page) group. So there may be, say, 20 categories, and 100 items (in my example, the images). The items may appear in more than one category, though I only want to show one at a time.
Elsewhere on the page are some navigation links. When one of these links is clicked, the items in #listing-holder are copied into .tiles ul. Then it's name is checked against the header tags in .tiles ul, removing any items that do not match. Then, I want the plugin to run again so that the pagination and slider work as before the change, but with new paging (if it's more or less). Like so:
$("#left-menu").delegate("a", "click", function(e) {
var itemClicked;
itemClicked = $(this).text();
$('.g-container .g-slider .tiles').html('');
$('.g-container .g-slider .tiles').html($('#listing-holder').html());
$(".g-container .g-slider .tiles h1:not(:contains(" + itemClicked + "))").closest('li').remove();
init(); // this isn't working the way I expected it to
});
Here's the (pertinent information from the) options js:
$(document).ready(
function() {
var $panel = $(".panel");
var $container = $panel.find(".g-container");
... // more variables
$(".g-container").gridSlider({
num_cols:5,
num_rows:3,
... // more settings
});
$submitButton.click(function() {
$container.undoChanges()
.setGridSize($gridCol.val(),$gridRow.val())
.setNoCategory($categories.filter(":checked").val() == "no")
... // more settings
.updateChanges(); // this is in the grid.js
setPanelWidth();
});
$resetButton.click(function() {
init();
$submitButton.trigger("click");
});
var init = function() {
$gridCol.val(5);
$gridRow.val(3);
... // more settings
}
var setPanelWidth = function() {
var width = $container.find(">div").outerWidth();
if (width < panelWidth) {
width = panelWidth;
}
$panel.css({width:width, marginLeft:-width/2});
... // more settings
}
init();
}
);
I've tried calling the init function, which does call it, but nothing seems to happen. I placed alerts at the beginning and end of the grid.js (which is minified), and they both fired, so it seems like it's going through.
I thought I'd have to use something like this:
(function( $ ){
$.fn.myPlugin = (function(){
{
// do something...
}
});
})(jQuery);
...but since I was able to call init from the options.js, I didn't go that route (but I'm willing to re-visit this, as I may have implented it incorrectly).
I've been at this for about a week, and I suspect I'm approaching this wrong, and could use some direction.
I think I could resolve the issue by creating all of the categories, then using something like getScript() to run afterwards. I think that would work. The issue is that there may potentially be several dozen categories, with items that may appear in several.
I figured (working with the hand dealt) that if I have just one list and pick from that list what I need depending on a click, that would be the route to go. I can do that successfully. It's just hooking it up to the slider that's not working.
Let me know if I need to provide further details.
Thanks.
Stephen
I am not familiar with the grid-slider plugin. But have you tried completely destroying the container DOM and then re-creating and inserting it. Then call the .gridSlider function again on the newly created DOM?
I'm making a toy app, trying to learn about these libraries and was hoping to understand how I would present a "tab" interface. I'd like to have a few buttons (or links, whatever is most common) on top. When one selected, it looks selected and the main content on the page changes to present what's on that tab.
My learning app is very simple at the moment:
<body>
<div class="content"></div>
</body>
And a backbone view:
var ContentView = Backbone.View.extend({
el: $('.content'),
// ..
So far, I've looked into using <% tag in the html to make a partial, making the ContentView somehow responsible for rendering different stuff in there. The other idea I've had but don't quite know how to pursue is several Backbone views taking turns being in charge of changing the one div.
Would sure appreciate some advice about the canonical approach here, including how to present the tabs buttons and how to cleanly separate view logic for the different tabs.
Follow a 'separation of concerns' model. You've got a main content view, which handles tab navigation. Anytime someone clicks on a tab, that main content view should tell the view that the tab belongs to that it is now active. Then that sub-view handles things from there. Here's some example code:
Let's say this is the HTML:
<div id="tabContainer" class='tabs'>
<div class='tab' id="content1Tab"></div>
<div class='tab' id="content2Tab"></div>
<div class='tab' id="content3Tab"></div>
</div>
<div id="contentContainer">
</div>
This might be the javascript.
ContentView = new (Backbone.View.extend({}
events: {
'click .tab': 'openTab'
},
el: $("#tabContainer"),
tabViews: {},
openTab: function (e) {
var el = $(e.currentTarget);
$("#contentContainer").children().detach();
if(!this.tabViews[el.attr('id')]) {
this.tabViews[el.attr('id')] = this.createTabViewForEl(el);
}
this.tabViews[el.attr('id')].render($("#contentContainer"));
},
createTabViewForEl: function (el) {
var tab;
switch(el.attr('id')) {
case "content1Tab":
tab = new FirstContentTab();
break;
/* etc */
}
return tab;
}
))();
FirstContentTab = Backbone.View.extend({
render: function (targetEl) {
this.setElement($("#someContentEl"));
this.$el.appendTo(targetEl);
}
/** stuff like loading in content for tab, or making a monkey dance when it opens **/
});
There are more elegant ways of doing this, like referencing the module that the tab belongs to, then using requirejs or some other module loader to load in that module and give it the tab in question. But, either way, don't let that one main view do too much. Otherwise you'll end up with something that's way more complicated than it needs to be.
I have a menu that is animated to slide across the page when triggered by clicking on an image of an arrow. I'd like to switch the arrow to a different image source once the menu's animation has completed, and then return back to the original file when the menu has been closed.
Best way to do this?
Thank you!
HTML:
<div id="slider">
<div id="trigger_right">
<img class="arrow_small" src="images/left_small.png" alt="slide menu out" />
</div>
<div class="trans" id="overlay"></div>
<div id="content">
<p>This is content</p>
</div>
</div>
Javascript:
$(function() {
$('#trigger_right').toggle(function (){
$('#slider').animate({'width':'100%'}, 1500);
$('.arrow_small').attr('src','images/right_small.png');
}, function() {
$('#slider').animate({'width':'30px'}, 1500);
$('.arrow_small').attr('src','images/left_small.png');
});
});
jQuery's .animate has a callback that is called when the animate is finished so you can use that to change the images at the appropriate time:
$(function() {
$('#trigger_right').toggle(function () {
$('#slider').animate({'width':'100%'}, 1500, function() {
$('.arrow_small').attr('src','images/right_small.png');
});
}, function() {
$('#slider').animate({'width':'30px'}, 1500, function() {
$('.arrow_small').attr('src','images/left_small.png');
});
});
});
The above assumes that you only have one .arrow_small element of course. Using a class for the arrow and a sprite sheet for the images would be better but that would only require changing the $('.arrow_small').attr() parts to $('.arrow_small').toggleClass() calls as Rob suggests.
If I understand correctly, you only want the images to change after the menu animation has completed.
One way, perhaps not the best, would be to make the JavaScript that changes the src attribute occur after a set period of time using setTimeout(). Instead of:
$('.arrow_small').attr('src','images/right_small.png');
You would have:
setTimeout("toggleImages()", 1500);
function toggleImages(){
// some code to toggle them
}
I haven't tested this, but give it a try. Hope it helps!
I would suggest you set the images up in CSS as classes and then do something like:
.toggleClass("right-small left-small");