twitter bootstrap dynamic carousel - ajax

I'd like to use bootstrap's carousel to dynamically scroll through content (for example, search results). So, I don't know how many pages of content there will be, and I don't want to fetch a subsequent page unless the user clicks on the next button.
I looked at this question: Carousel with dynamic content, but I don't think the answer applies because it appears to suggest loading all content (images in that case) from a DB server side and returns everything as static content.
My best guess is to intercept the click event on the button press, make the ajax call for the next page of search results, dynamically update the page when the ajax call returns, then generate a slide event for the carousel. But none of this is really discussed or documented on the bootstrap pages. Any ideas welcome.

If you (or anyone else) is still looking for a solution on this, I will share the solution I discovered for loading content via AJAX into the Bootstrap Carousel..
The solution turned out to be a little tricky since there is no way to easily determine the current slide of the carousel. With some data attributes I was able to handle the .slid event (as you suggested) and then load content from another url using jQuery $.load()..
$('#myCarousel').carousel({
interval:false // remove interval for manual sliding
});
// when the carousel slides, load the ajax content
$('#myCarousel').on('slid', function (e) {
// get index of currently active item
var idx = $('#myCarousel .item.active').index();
var url = $('.item.active').data('url');
// ajax load from data-url
$('.item').html("wait...");
$('.item').load(url,function(result){
$('#myCarousel').carousel(idx);
});
});
// load first slide
$('[data-slide-number=0]').load($('[data-slide-number=0]').data('url'),function(result){
$('#myCarousel').carousel(0);
});
Demo on Bootply

I combined #Zim's answer with Bootstrap 4. I hope it will help someone.
First, load just the path of the images:
<div id="carousel" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item" data-url="/image/1.png"></div>
<div class="carousel-item" data-url="/image/2.png"></div>
<div class="carousel-item" data-url="/image/3.png"></div>
</div>
</div>
Then in JavaScript:
$('document').ready(function () {
const loadCarouselImage = function ($el) {
let url = $el.data('url');
$el.html(function () {
let $img = $('<img />', {
'src': url
});
$img.addClass('d-block w-100');
return $img;
});
);
const init = function () {
let $firstCarousel = $('#carousel .carousel-item:first');
loadCarouselImage($firstCarousel);
$firstCarousel.addClass('active');
$('#productsCarousel').carousel({
interval: 5000
});
};
$('#carousel').on('slid.bs.carousel', function () {
loadCarouselImage($('#carousel .carousel-item.active'));
});
init();
});

Related

Bootstrap popover and loading content with ajax and django

I know it has been given some answers but I will go for it :). As the title says i want to add popover bootstrap but with ajax loaded content. my html, but i want a Loading message to appear first and then the content.
<p class='entry' data-adjaxload = '/calendar/entry/1'>Title1</p>
<p class='entry' data-adjaxload = '/calendar/entry/2'>Title2</p>
<p class='entry' data-adjaxload = '/calendar/entry/3'>Title3</p>
my django view is the following
def entry_details(request, entry_id):
entry = get_object_or_404(Entry, pk=entry_id)
args = dict(entry=entry, user=request.user)
if request.is_ajax():
return render_to_response('mycal/ajax/entry_details.html', args)
else:
entry_form = EntryForm(instance=entry)
args.update(entry_form=entry_form)
return render_to_response('mycal/entry_details.html', args)
Pretty simple. I am using the same view to either load html content via ajax in the popover, or a details page via normal get request
the ajax details page:
<div class="entry">
<p>{{entry.title}}</p>
<p>{{entry.date}}</p>
<p>{{entry.customer}}</p>
</div>
and the script
$(document).ready(function(){
$('p.entry').each(function (){
var i = $(this);
$(i).bind('mouseenter', function(){
i.popover({
html:True,
title:i.html(),
content:'Loading'
}).popover('show');
$.ajax({
url:i.data('ajaxload'),
dataType:'html',
success:function (data){
i.popover({content:data}).popover('show');
}
});
});
$(i).bind('mouseleave', function(){
i.popover('hide');
});
});
});
But whilst it does run tha ajx and fetches the html, it won't load them onto the popover. How can I change that?
Just fiddled what you are looking for with popover content being updated dynamically using echo/json.
Just roll over the p element and wait for the 3 second delay.
If as you say, the data is being loaded properly then the only change needed is:
var popover = i.data('popover');
popover.options.content = data.text;
i.popover('show');

How to use AngularJS to lazy load content in a collapsible panel

I am building an application that uses the Bootstrap Collapse component to render a sequence of panels, all of which will initially be in the collapsed state.
Since the page may contain many such panels and each of them may contain a large amount of content, it seems appropriate to populate these panels on demand, by executing an AJAX call when the user expands any panel.
The dynamic content of the page (including the markup for the panels) is rendered using AngularJS, and I assume it's possible to configure Angular to bind to an event on the panel elements, that results in their content being lazy loaded when they expand.
Unfortunately, after looking at the AngularJS docs and the available tutorials, I can't see how best to tackle this. Can anyone throw any light on it?
Thanks in advance,
Tim
This is way old, but the question might still come up now and then. I now find this to be the most suitable solution without polluting your controllers:
(myDirective loading its content via AJAX right after its creation.)
<accordion>
<accordion-group
heading=""
ng-repeat="foo in bar"
ng-init="status = {load: false}"
ng-click="status.load = true">
<myDirective ng-if="status.load"></myDirective>
</accordion-group>
</accordion>
each element created by ng-repeat gets its own $scope, so clicking ab accordion-group will result in only the respective directive being loaded.
edit:
depending on latency and the size of the data that's to be lazy loaded, you might consider using ng-mouseover instead of ng-click. That way loading starts some 100ms before the user opens the accordion which can reduce 'sluggishness' of your UI. Obviously there's the downside of occasionally loading content of groups that are never actually clicked.
#Tim Coulter, I've created something following the idea of #Stewie.
It can definitely be improved, but I guess it's a good starting point.
I've created a small directive to bind the click event of the accordion's panel. When the click event is fired, I passed the panel template via the panel-template= attribute and it updates the main-template which is used inside the panel.
It makes reference to 2 html files (panel1.html and panel2.html) that contains the content of the each panel.
I would recommend to create a service to fetch these files via AJAX - just the way you wanted.
On the code below I created a service called dataService for this purpose and you should bind it to the click event - so files are loaded on demand when the user clicks on it.
Note the the mainTemplate is a common panel to all accordions, so when it changes the all the accordions will have the same content, BUT I am assuming you want to display only one panel at time, right ?!
Anyway as I said before the logic can be improved to fix these little 'gotchas', but I believe the core functionality is there to start with. :)
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
<script>
var myApp = angular.module('myApp', []);
myApp.controller('AccordionDemoCtrl', ['$scope', 'dataService', function ($scope, dataService) {
$scope.oneAtATime = true;
$scope.mainTemplate = '';
$scope.groups = [
{
id: "001",
title: "Dynamic Group Header - 1",
content: "Dynamic Group Body - 1",
template: "panel1.html"
},
{
id: "002",
title: "Dynamic Group Header - 2",
content: "Dynamic Group Body - 2",
template: "panel2.html"
}
];
}]);
myApp.factory('dataService', [ '$http', function($http){
return {
getData: function() {
return // you AJAX content data here;
}
}
}]);
myApp.directive('accordionToggle', [function () {
return {
restrict: 'C',
scope: {
mainTemplate: '=',
panelTemplate: '#'
},
link: function (scope, element, iAttrs) {
element.bind('click', function(e){
scope.mainTemplate = scope.panelTemplate;
scope.$apply();
});
}
};
}]);
</script>
</head>
<body ng-controller="AccordionDemoCtrl">
<div class="accordion" id="accordionParent">
<div class="accordion-group" ng-repeat="group in groups" >
<div class="accordion-heading">
<a class="accordion-toggle" main-template="$parent.mainTemplate" panel-template="{{ group.template }}" data-toggle="collapse" data-parent="#accordionParent" href="#collapse{{ $parent.group.id }}">
Collapsible Group Item {{ $parent.group.id }}
</a>
</div>
<div id="collapse{{ group.id }}" class="accordion-body collapse">
<div class="accordion-inner">
<div class="include-example" ng-include="mainTemplate"></div>
</div>
</div>
</div>
</div>
</body>
</html>

Dynamically inserting content within same page rather then going to a new page

EDIT italics = more detailed explanation added to the question. Thanks.
I'm building a jQuery Mobile site which has a Gallery section.
The gallery has a series of thumbnails on the top of the screen.
Users click on the thumbnail to load in new content, that being a larger image, text, and potentially audio on some of them.
It's at this point that I'm not sure what to do: the way jQuery Mobile works, it's geared towards loading new pages, or views. But I just want to inject new content in a container on the current page.
To be clear, when the user clicks on another thumbnail, a new image replaces the content of the container with new content.
I have two questions:
I'm not sure how to structure the dynamic content. I was thinking i'd create an html file for each item, which as a rule always contains a title, information and sometimes, audio.
I'm not sure how to script this functionality in jQuery Mobile. It's obviously Ajax, but I'm not familiar with it yet, especially since jQuery Mobile has it's own methods in place already which seems to redefine behaviors in a way that's contradictory to this approach described here.
Here is a code explanation of what i'm trying to do:
<!-- Galleries -->
<div data-role="page" id="galleries">
<div data-role="content" role="main">
This is the Selection UI, if i click on thumb2.jpg, it'd
fill #content-holder with the whatever html is in content2.php
<div id="thumb-carousel">
<img src="thumb1.jpg">
<img src="thumb2.jpg">
<img src="thumb3.jpg">
<img src="thumb4.jpg">
<img src="thumb5.jpg">
<img src="thumb6.jpg">
<img src="thumb7.jpg">
<img src="thumb8.jpg">
<img src="thumb9.jpg">
</div>
<!-- This is the container, currently it's filled
with the kinda stuff i need to put in it. -->
<div id="content-holder">
<img src="myimage1.jpg"/>
<p>Artwork Title</p>
<p>Caption</p>
<audio>//mp3</audio>
</div>
</div>
</div>
//remember to use event delegation because you never know when the page will be in the DOM
$(document).delegate('#galleries', 'pageinit', function () {
//bind a `click` event handler to each thumbnail link
$('#thumb-carousel').children().bind('click', function () {
$.ajax({
url : $(this).attr('href'),
success : function (serverResponse) {
//select the container,
//then fade it out,
//change it's HTML to the response from the AJAX request,
//and fade it back in
$('#content-holder').fadeOut(500, function () {
$(this).html(serverResponse).fadeIn(500);
});
},
error : function (jqXHR, textStatus, errorThrown) {
//remember to handle errors so your page doesn't seem broken to the user
}
});
//prevent the default behavior of the link, which is to navigate to the `href` attribute
return false;
});
});
This expects your server-response to be valid HTML markup that is ready to inject into the DOM, meaning no <html> or <body> tags, just what you want to add to the DOM:
<img src="..." />
<span>TITLE</span>
<audio src="..."></audio>
Here are some docs for ya:
$.ajax(): http://api.jquery.com/jquery.ajax
.closest(): http://api.jquery.com/closest
.fadeIn(): http://api.jquery.com/fadein

How to load plain text in to div from another page

I'm trying to load content from another page div into another page div.
What i've got:
JQUERY:
$('#news_date-1').load('test.php .news_date-1');
TEST.PHP
<div class="news_date-1">20-11-2009</div>
Destination.html
<div id="news_date-1"></div>
The result i get =
<div id="news_date-1"><div class="news_date-1">20-11-2009</div></div>
The result i want =
<div id="news_date-1">20-11-2009</div>
Can anybody help out?
You can try calling unwrap() on it in the callback.
$('#news_date-1').load('test.php .news_date-1', function () {
$(this) //will refer to #news_date-1
.find('.news_date-1') //find the inserted div inside
.contents() //find all its contents
.unwrap(); //unwrap the contents, thus removing the unneeded div
});
This is not the most beautiful solution, because .load() already inserts it into the DOM, and then you tamper with the DOM again, which should be minimized.
Another way I see is using $.get() instead:
$.get('test.php', function(receivedHtml) {
//getting only the parts we need
var neededHtml = $(receivedHtml).find('.news_date-1').html();
//adding it to DOM
$('#news_date-1').append(neededHtml);
});
Try this:
$.get('test.php', function(data) {
$('#news_date-1').append($(data).find('.news_date-1'));
});

Reloading everything but one div on a web page

I'm trying to set up a basic web page, and it has a small music player on it (niftyPlayer). The people I'm doing this for want the player in the footer, and to continue playing through a song when the user navigates to a different part of the site.
Is there anyway I can do this without using frames? There are some tutorials around on changing part of a page using ajax and innerHTML, but I'm having trouble wrapping my head aroung getting everything BUT the music player to reload.
Thank you in advance,
--Adam
Wrap the content in a div, and wrap the player in a separate div. Load the content into the content div.
You'd have something like this:
<div id='content'>
</div>
<div id='player'>
</div>
If you're using a framework, this is easy: $('#content').html(newContent).
EDIT:
This syntax works with jQuery and ender.js. I prefer ender, but to each his own. I think MooTools is similar, but it's been a while since I used it.
Code for the ajax:
$.ajax({
'method': 'get',
'url': '/newContentUrl',
'success': function (data) {
// do something with the data here
}
});
You might need to declare what type of data you're expecting. I usually send json and then create the DOM elements in the browser.
EDIT:
You didn't mention your webserver/server-side scripting language, so I can't give any code examples for the server-side stuff. It's pretty simple most of time. You just need to decide on a format (again, I highly recommend JSON, as it's native to JS).
I suppose what you could do is have to div's.. one for your footer with the player in it and one with everything else; lets call it the 'container', both of course within your body. Then upon navigating in the site, just have the click reload the page's content within the container with a ajax call:
$('a').click(function(){
var page = $(this).attr('page');
// Using the href attribute will make the page reload, so just make a custom one named 'page'
$('#container').load(page);
});
HTML
<a page="page.php">Test</a>
The problem you then face though, is that you wouldnt really be reloading a page, so the URL also doesnt get update; but you can also fix this with some javascript, and use hashtags to load specific content in the container.
Use jQuery like this:
<script>
$("#generate").click(function(){
$("#content").load("script.php");
});
</script>
<div id="content">Content</div>
<input type="submit" id="generate" value="Generate!">
<div id="player">...player code...</div>
What you're looking for is called the 'single page interface' pattern. It's pretty common among sites like Facebook, where things like chat are required to be persistent across various pages. To be honest, it's kind of hard to program something like this yourself - so I would recommend standing on top of an existing framework that does some of the leg work for you. I've had success using backbone.js with this pattern:
http://andyet.net/blog/2010/oct/29/building-a-single-page-app-with-backbonejs-undersc/
You can reload desired DIVs via jQuery.ajax() and JSON:
For example:
index.php
<script type="text/javascript" src="jquery-1.4.2.js"></script>
<script type="text/javascript" src="ajax.js"></script>
<a href='one.php' class='ajax'>Page 1</a>
<a href='two.php' class='ajax'>Page 2</a>
<div id='player'>Player Code</div>
<div id='workspace'>workspace</div>
one.php
<?php
$arr = array ( "workspace" => "This is Page 1" );
echo json_encode($arr);
?>
two.php
<?php
$arr = array( 'workspace' => "This is Page 2" );
echo json_encode($arr);
?>
ajax.js
jQuery(document).ready(function(){
jQuery('.ajax').click(function(event) {
event.preventDefault();
// load the href attribute of the link that was clicked
jQuery.getJSON(this.href, function(snippets) {
for(var id in snippets) {
// updated to deal with any type of HTML
jQuery('#' + id).html(snippets[id]);
}
});
});
});

Resources