Backbone.js Model, adding setInterval correctly - model-view-controller

I'm creating a simple Backbone app for learning purposes. I'm just creating a time and date display. The display has to update at least every minute. I'm using "Time" for the model and "TimeView" for the View. My first question is sort-of philosophical, which holds the setInterval, the Model or the View? I think that the Model should self-update but I couldn't get the code to work. It looks like it's updating the model but the binding of model.update() to the view.render() function doesn't work.
In the code below, I switched the setInterval to the View and commented out my other attempt. Even though this works, (and maybe the View should control the updating of the model) but this.model.bind( 'update', this.render ) doesn't work and I have to initiate the render seperately which feels wrong.
var Time = Backbone.Model.extend({
initialize: function(){
_.bindAll( this, 'update', 'startLoop', 'stopLoop' );
//this.startLoop();
this.update();
},
startLoop: function(){
this.update();
this.interval = window.setInterval(_.bind(this.update, this), 10000);
},
stopLoop: function(){
this.interval = window.clearInterval( this.interval );
},
update: function(){
var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
var months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
var date = new Date();
var tHour = date.getHours();
if( tHour < 12 ){ if( tHour == 0 ) tHour = 12 } else { tHour = tHour-12 };
tHour = tHour.toString();
var tMin = date.getMinutes();
tMin = ( tMin < 10 ) ? '0' + tMin.toString() : tMin.toString();
this.set({
hour : tHour,
ampm : ( date.getHours() < 12 ) ? "am" : "pm",
minute : tMin,
day : days[ date.getDay() ],
month : months[ date.getMonth() ],
date : date.getDate(),
year : date.getFullYear()
});
}
});
var TimeView = Backbone.View.extend({
el: '#time-date-display',
interval: 0,
template: $( '#tpl-time-date' ).html(),
initialize: function(){
_.bindAll( this, 'render' );
this.model = new Time();
this.render();
//this.model.bind( 'update', this.render );
this.interval = window.setInterval( _.bind( function(){ this.model.update(); this.render();}, this), 10000 );
},
render: function(){
//alert( 'TimeView.render()' );
$( this.el ).html(
_.template( this.template, this.model.toJSON())
);
}
});
$( 'body' ).append( _.template( $( '#tpl-time-weather-display' ).html()));
var tv=new TimeView();

You are binding to the update event on the model, but that event will never be triggered. Calling update on the model isn’t the same as an update event being generated. Instead, bind to the model’s change event, then the view will be updated.
Regarding the philosophical question, I’d choose the model to be updating with the time, too, but this example is so contrived it’s almost arbitrary.

Related

infinite scroll + isotope

I need help: I use isotope with infinite scroll to display thumbnails for a gallery. Everything works when all items are displayed (without isotope filter). By cons, when one uses the isotope filter (that is to say at the opening of my page), animation to view thumbnails runs for all new elements even those that should be filtered !
In short: we see animation bits for each new item loaded, it expands and then shrinks, becoming opaque and hides, creating sparkles ...
How to disable and hide the animation from the beginning each new element that should be filtered?
Thanks for your help ! (sorry for my English)
/*Masonry*/
var $containermasonry = $('.masonry');
$containermasonry.imagesLoaded( function() {
$containermasonry.masonry({
itemSelector: '.item',
});
$containermasonry.isotope({
transitionDuration: '0.8s',
animationEngine: 'best-available',
itemSelector : '.item',
layoutMode : 'masonry',
filter : '.new',
getSortData: {
date: '[data-date]',
categories:'[data-categ]',
}
});
});
/*infinitescroll*/
$containermasonry.infinitescroll({
navSelector : '#page-nav',
nextSelector : '#page-nav a',
itemSelector : '.item',
loading: {
finishedMsg: '',
img: '_include/img/supersized/progress.gif'
}
},
function( newElements ) {
var $newElems = $( newElements ).css({'display': 'none', 'visibility': 'hide', opacity: 0});
$newElems.imagesLoaded(function(){
/*$newElems.animate({ opacity: 1 });*/
$containermasonry.infinitescroll('retrieve');
$containermasonry.masonry( 'appended', $newElems, true );
$containermasonry.isotope( 'appended', $newElems, true );
});
}
);
// filter items
var $optionSets = $('#options .option-set'),
$optionLinks = $optionSets.find('a');
$optionLinks.click(function(){
var $this = $(this);
if ( $this.hasClass('selected') ) {
return false;
}
var $optionSet = $this.parents('.option-set');
$optionSet.find('.selected').removeClass('selected');
$this.addClass('selected');
var filterValue = $(this).attr('data-option-value');
$containermasonry.isotope({ filter: filterValue });
});
It is difficult to answer well without a jsfiddle or link.
The big issue is that you are using calling masonry.js and isotope.js at the same time! They are two separate plugins, not designed to be used together. Isotope has a masonry layout which is where your confusion lies, it is not called with masonry.js. Choose one or the other.
Also, if your using isotope v2, animationEngine has been removed from that version.
Here is the code you should use for isotope use:
var $containermasonry = $('.masonry');
$containermasonry.imagesLoaded( function() {
$containermasonry.isotope({
transitionDuration: '0.8s',
itemSelector : '.item',
layoutMode : 'masonry',
filter : '.new',
getSortData: {
date: '[data-date]',
categories:'[data-categ]',
}
});
});
//infinitescroll
$containermasonry.infinitescroll({
navSelector : '#page-nav',
nextSelector : '#page-nav a',
itemSelector : '.item',
loading: {
finishedMsg: '',
img: '_include/img/supersized/progress.gif'
}
},
function( newElements ) {
var $newElems = $( newElements ).css({'display': 'none', 'visibility': 'hide', opacity: 0});
$newElems.imagesLoaded(function(){
//$newElems.animate({ opacity: 1 });
$containermasonry.infinitescroll('retrieve');
$containermasonry.isotope( 'appended', $newElems, true );
});
}
);
// filter items
var $optionSets = $('#options .option-set'),
$optionLinks = $optionSets.find('a');
$optionLinks.click(function(){
var $this = $(this);
if ( $this.hasClass('selected') ) {
return false;
}
var $optionSet = $this.parents('.option-set');
$optionSet.find('.selected').removeClass('selected');
$this.addClass('selected');
var filterValue = $(this).attr('data-option-value');
$containermasonry.isotope({ filter: filterValue });
});

fullcalendar loaded with ajax symfony2 doctrine2

this my function in controller
public function loadcalendarAction() {
$eventsloaded = $this->container->get('calendarbundle.serviceloadcalendar')->loadCalendar();
$response = new JsonResponse();
//dump($eventsloaded);
//die();
$response->setData(array('events' => $eventsloaded));
return $response;
}
the $eventsloaded is an array of 2 events in my database its OK .. but $response is empty i don't know why ..
and this my calendar_setting.js
$(document).ready(function () {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultDate: '2016-01-12',
lang: 'ar-tn',
buttonIcons: false, // show the prev/next text
weekNumbers: true,
editable: true,
eventLimit: true, // allow "more" link when too many events
dayClick: function () {
alert('a day has been clicked!');
},
events: Routing.generate('loadcalendar')
});
});
if the response not empty all the events will be displayed in the events:
Look at this questions' answer. You need either to use some external bundle (such as JMSSerializerBundle) to serialize entity, to pass it to json response, or implement something like toArray() method in your entity which will return an array of needed data from entity, after that you could do smth like:
$responseData = [];
foreach ($eventsloaded as $i => $event) {
$responseData[$i] = $event->toArray();
}
return new JsonResponse($responseData);

WP_Query with ajax handler returns the same posts

I have a problem that is getting me bald atm. I have a ajax call that handles a loop that handles some querys and returns posts for me.
So far so good, but the first time the user sees the page we should load 10 posts, and then we want to click a button to request 5 more.
So far so good.
But when we request the 5 more posts we get the 5 first posts again.
My batchloop
<?php
// Our include
define('WP_USE_THEMES', false);
require_once('../../../wp-load.php');
// Our variables
$posts = (isset($_GET['numPosts'])) ? $_GET['numPosts'] : 0;
$page = (isset($_GET['pageNumber'])) ? $_GET['pageNumber'] : 0;
$category = (isset($_GET['category_name'])) ? $_GET['category_name'] : 0;
var_dump($posts);
$args = array(
'posts_per_page' => $posts,
'category_name' => $category,
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
'paged' => $page
);
query_posts($args);
// $query = new WP_query($args);
// our loop
if (have_posts()) {
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; query_posts($args);
while (have_posts()){
the_post();
get_template_part( 'thumbs', get_post_format() );
}
}
// unset($page, $posts, $category);
// wp_reset_postdata();
wp_reset_query();
?>
Does anybody sees what im doing wrong?
EDIT:
batch handler
function _batchhandler() {
var getamount = localStorage.getItem('amount');
console.log('amount of posts to retrive ' + JSON.parse(getamount));
// Ajax call
$.ajax({
type: 'GET',
data: {
posts: getamount,
page: page,
category: 'work'
},
dataType: 'html',
url: 'http://dev.xxx.se/wp-content/themes/xxx/batch.php',
beforeSend: function() {
_setHeader;
if( page != 1 ) {
console.log('Loading');
// Show the preloader
$('body').prepend('<div class="preloader"><span class="rotate"></span></div>');
}
// If we reach the end we hide the show more button
if( page >= total ) {
$('.load').hide();
}
},
success: function(data) {
console.log(page);
var scroll = ($('.thumb').height() * posts);
// If thumbs exist append them
if( data.length ) {
// Append the data
$('#batch').append(data);
// Remove the crappy width and height attrs from the image * Generated by WP *
$('img').removeAttr('height').removeAttr('width');
// Animate each new object in a nice way
(function _showitem() {
$('#batch .thumb:hidden:first').addClass('show', 80, _showitem);
// On the last request do load any more
loading = false;
})();
// Remove the preloader
$('.preloader').fadeOut(200, function() {
$('.preloader').remove();
});
}
// return false;
},
complete: function() {
// Delete storage
localStorage.clear();
// Update the scroller to match the updated content length
if (scroller)
setTimeout("scroller.refresh()", 300);
// Initalize the load more button
_clickhandler();
},
error: function() {
console.log('No page found');
}
});
}
and my load more button function
$('.load').on('click', function(event) {
event.preventDefault();
// Delete storage
localStorage.clear();
if(!loading) {
loading = true;
// Increase our pagenumber per click
page++;
count++;
// Remove preloader
$('.preloader').remove();
setTimeout(function() {
$('#batch').css({
'-webkit-transform' : 'translateY(-' + ($('#batch li').outerHeight() * count) + 'px)'
});
}, 30);
// Clear storage and set a new
localStorage.setItem('amount', JSON.stringify(amount.medium));
var getamount = localStorage.getItem('amount');
// Send the request to the handler
_batchhandler(page);
}
});
Everything seems fine, the first 10 (1-10) posts loads as the should, but the first time "load more" is clicked we get the next 5 results but the results are posts that loaded the first time (5-10). If we click the "load more" again, we get the correct result
I don't think you have defined a start value for page, set it to 1 at the start of your script so when it increments on click it goes to page 2. Otherwise it'll just get the first page.

How to use a normal pagination with jQuery Isotope?

I've implemented Isotope this way http://jsfiddle.net/circlecube/LNRzZ/ to my Joomla website. Sorting and filtering work perfeclty but only in the current page.
I would like to sort/filter all items but display only 20 items per page. I wish to keep a numeric navigation, like this http://tutorials.vinnysingh.co/quicksand/.
Can Isotope handle this or should I use another plugin? Any help is greatly appreciated. Thanks in advance.
Here is my full code:
jQuery( document ).ready( function ($) {
// cache container
var $container = $('#container');
// initialize isotope
$container.isotope({
getSortData : {
author : function ( $elem ) {
return $elem.find('.author').text();
},
city : function ( $elem ) {
return $elem.find('.city').text();
},
country : function ( $elem ) {
return $elem.find('.country').text();
},
price : function( $elem ) {
return parseFloat( $elem.find('.price').text().replace( /[\(\)]/g, '') );
},
rating : function ( $elem ) {
return parseInt( $elem.find('.rating').text(), 10 );
},
review : function ( $elem ) {
return parseInt( $elem.find('.review').text(), 10 );
},
perfDate: function (element) {
// parse out the performance date from the css classes
var classList = element.attr('class').split(/\s+/);
var dateClassPrefix = 'date-';
var date;
$.each(classList, function(index, cssClassName){
if (cssClassName.substring(0, dateClassPrefix.length) === dateClassPrefix) {
// Should be a date in format 'yyyy-MM-dd'
var dateString = cssClassName.substring(dateClassPrefix.length);
date = SF.parseDate('dd/mm/yyyy').getTime();
}
});
return date;
}
}
});
$('#sort-by a').click(function(){
// get href attribute, minus the '#'
var sortName = $(this).attr('href').slice(1);
$('#container').isotope({ sortBy : sortName });
return false;
});
// filter items when filter link is clicked
$('#filters a').click(function(){
var selector = $(this).attr('data-filter');
$container.isotope({ filter: selector });
return false;
});
var $optionSets = $('#options .option-set'),
$optionLinks = $optionSets.find('a');
$optionLinks.click(function(){
var $this = $(this);
// don't proceed if already selected
if ( $this.hasClass('selected') ) {
if ($this.hasClass('lock')){
//return false;
}
else if ($this.hasClass('asc')){
$this.removeClass('asc').addClass('desc');
}
else if ($this.hasClass('desc')){
$this.removeClass('desc').addClass('asc');
}
}
var $optionSet = $this.parents('.option-set');
$optionSet.find('.selected').removeClass('selected');
$this.addClass('selected');
// make option object dynamically, i.e. { filter: '.my-filter-class' }
var options = {},
key = $optionSet.attr('data-option-key'),
value = $this.attr('data-option-value');
// parse 'false' as false boolean
value = value === 'false' ? false : value;
options[ key ] = value;
if ($this.hasClass('asc') || $this.hasClass('desc'))
options[ 'sortAscending' ] = $this.hasClass('asc');
if ( key === 'layoutMode' && typeof changeLayoutMode === 'function' ) {
// changes in layout modes need extra logic
changeLayoutMode( $this, options )
} else {
// otherwise, apply new options
$container.isotope( options );
}
return false;
});
});
Isotope doesn't do pagination. You'll need to implement the pagination in Joomla.

Passing the date value in fullcalendar

I am using fullcalendar to upload dates times to my database and i have the following script
$dialogContent.dialog({
modal: true,
title: "New Listing",
close: function() {
$dialogContent.dialog("destroy");
$dialogContent.hide();
},
buttons: {
save : function () {
calEvent.id = id;
id++;
calEvent.start = new Date(startField.val());
calEvent.end = new Date(endField.val());
calEvent.title = titleField.val();
calEvent.body = bodyField.val();
$.ajax({
type: "POST",
url: "addnew.php",
data: (
{
'st':new Date(startField.val()),
'et':new Date(endField.val()),
'title':titleField.val(),
'body':bodyField.val()
}
),
success: function(msg){
alert( "Data Saved: " + msg );
}
});
However my date values are not being sent at all. Its wrong but I don't know how or why.
the Date constructor does not parse any old date string. use fullCalendar's parsing function instead (provided you are using ISO8061 format):
http://arshaw.com/fullcalendar/docs/utilities/parseDate/
What value of date do you get in server side?
May be, you should to send simple data type like UNIX timestamp or using .serialize() for your form.
I have been playing around with ParseDate but I'm just not getting results, seems I have the concept all wrong;
dayClick : function(date, allDay, jsEvent, view) {
var $dialogContent = $("#event_edit_container");
y = date.getFullYear();
m = date.getMonth();
d = date.getDate();
h1 = date.getHours();
m1 = date.getMinutes();
h2 = h1 + 1;
m2 = m1;
calEvent = { title: 'New Calendar Event', editable:true, distributor: '', etype: '', location: '', website: '', start: new Date(y, m, d, h1, m1), end: new Date(y, m, d, h2, m2), allDay: false };
$calendar.fullCalendar("renderEvent",calEvent, true);
resetForm($dialogContent);
var startField = $dialogContent.find("select[name='start']").val(calEvent.start);
var endField = $dialogContent.find("select[name='end']").val(calEvent.end);
var titleField = $dialogContent.find("input[name='title']").val(calEvent.title);
var distributorField = $dialogContent.find("input[name='distributor']").val(calEvent.distributor);
var etypeField = $dialogContent.find("select[name='etype']").val(calEvent.etype);
var locationField = $dialogContent.find("input[name='location']").val(calEvent.location);
var websiteField = $dialogContent.find("input[name='website']").val(calEvent.website);
var bodyField = $dialogContent.find("textarea[name='body']");
//var start_date = eval($.fullCalendar.parseDate(this_one['start']).getTime()) / 1000;
$dialogContent.dialog({
modal: true,
title: "New Listing",
close: function() {
$dialogContent.dialog("destroy");
$dialogContent.hide();
},
buttons: {
save : function () {
calEvent.id = id;
id++;
calEvent.start = $.fullCalendar.parseDate(new Date(startField.val()));
calEvent.end = new Date(endField.val());
calEvent.title = titleField.val();
calEvent.distributor = distributorField.val();
calEvent.etype = etypeField.val();
calEvent.location = locationField.val();
calEvent.website = websiteField.val();
calEvent.body = bodyField.val();
//$.fullCalendar.parseDate(calEvent.start);
//calEvent.st = start_date.val();
//$.fullCalendar.parseDate(startField.val());
$.ajax({
type: "POST",
url: "addnew.php",
data: (
{
'st':calEvent.start,
'et':new Date(endField.val()),
'title':titleField.val(),
'distributor':distributorField.val(),
'etype':etypeField.val(),
'location':locationField.val(),
'website':websiteField.val(),
'body':bodyField.val()
}
),
success: function(msg){
alert( "Data Saved: " + msg );
}
});
I'm at a brick wall with this I've tried tons of variations of hte code but its all just guess work. If there is an example of the date filed being passed or even printed out I'd really appreciate it just to see how this should work. Trial and error is not working for me in this case.
Thanks
It's late and i haven't used Javascript in a while, but surely it's input.value not input.val()

Resources