Super simple page navigation with Backbone - javascript

I have searched all over the place to no avail. Everyone seems to have their own way of building some form of a todo list with backbone. I need to do something a little different albeit more crude. I need to build a four page site on top of backbone–I know I could easily do this with jQuery or equivalent, but this might be something that is increased in scope down the road. So really Im not using Models or Collections, just routes, views and templates. My number of templates is so small I don't need to get them from an external folder I can just swap out divs and have the templates live inline.
In its most simple form I have a single page web app that I need to swap out 4 static views with with one button, one direction, with a start and finish. Thats it. No tutorial or documentation I have found performs something this basic with backbone. Any savvy folks out there care to point me in the right direction?

Here's a simple little one-page app that swaps out 4 different templates and steps from page 1 to 4 as you press the button. Let me know if you have questions.
<html>
<head>
<title>Steps</title>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script type="text/x-template" id="page-1">
<p>Page one content</p>
</script>
<script type="text/x-template" id="page-2">
<p>Page two content</p>
</script>
<script type="text/x-template" id="page-3">
<p>Page three content</p>
</script>
<script type="text/x-template" id="page-4">
<p>Page four content</p>
</script>
<script>
(function($){
// Helper to get template text.
function getTemplate(index){
return $('#page-' + index).text();
}
// Simple view to render a template, and add a button that
// will navigate to the next page when clicked.
var PageView = Backbone.View.extend({
index_: null,
events: {
'click button': 'nextPage_'
},
initialize: function(options){
this.index_ = options.index;
},
render: function(){
var html = getTemplate(this.index_);
// If there is a next page, add a button to proceed.
if (html && getTemplate(this.index_ + 1)){
html += '<button>Next</button>';
}
this.$el.html(html);
},
nextPage_: function(){
router.navigate('page/' + (this.index_ + 1), {trigger: true});
}
});
// Router handling a default page, and the page urls.
var Router = Backbone.Router.extend({
routes: {
'page/:index': 'loadPage',
'*notFound': 'defaultPage'
},
defaultPage: function(){
this.loadPage();
},
loadPage: function(index){
// Default to page 1 when no page is given.
index = parseInt(index, 10) || 1;
if (this.pageView_) this.pageView_.remove();
this.pageView_ = new PageView({index: index});
this.pageView_.render();
this.pageView_.$el.appendTo('#content');
}
});
var router;
$(function(){
router = new Router();
Backbone.history.start({pushState: true});
});
})(jQuery);
</script>
</head>
<body>
<!-- Some page header -->
<section id="content"></section>
</body>
</html>

Related

Toggle hide/show not working on childs div

I have a script that gets data from a Google Sheet and displays it as a webpage - using JS and Tabletop.js.
There are multiple entries in the Sheet thus multiple entries in the webpage. To organise the Data I have a hide/show button. When the button is clicked on the first entry it works. However when the any of the other buttons are clicked it hides or shows the first entries data, not its own!
How do I hide/show each individual entries data? Below is the code I am working with!
I am new to JavaScript - Thanks in advance!
P.S - I struggled writing the Title to the questions!
<link href="../common/cats-copy.css" media="screen" rel="stylesheet" type="text/css" />
</head>
<style>
#add-info {
display: none
}
</style>
<body>
<div class="container">
<h1>Resturants</h1>
<div id="content"></div>
<script id="cat-template" type="text/x-handlebars-template">
<div class="entry">
<h5>{{establishment_name}}</h5>
<h6>Area: {{area}}</h6>
<h6>Cuisine: {{cuisine}}</h6>
<button id="btn" class="button-primary" onclick="myFunction()">Hide</button>
<div id="add-info">
<h6>Address: {{address}}</h6>
<h6>Google Maps: {{google_maps_location}}</h6>
<h6>Opening Times: {{opening_times}}</h6>
<h6>Rating: {{rating}}</h6>
<h6>Added By: {{added_by}}</h6>
<h6>Date Added: {{date_added}}</h6>
</div>
</div>
</script>
</div>
<!-- Don't need jQuery for Tabletop, but using it for this example -->
<script type="text/javascript" src="handlebars.js"></script>
<script type="text/javascript" src="../../src/tabletop.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
var public_spreadsheet_url = 'https://docs.google.com/spreadsheets/d/1h5zYzEcBIA5zUDc9j4BTs8AcJj-21-ykzq6238CnkWc/edit?usp=sharing';
$(document).ready( function() {
Tabletop.init( { key: public_spreadsheet_url,
callback: showInfo,
parseNumbers: true } );
});
function showInfo(data, tabletop) {
var source = $("#cat-template").html();
var template = Handlebars.compile(source);
$.each( tabletop.sheets("food").all(), function(i, food) {
var html = template(food);
$("#content").append(html);
});
}
</script>
<script>
function myFunction() {
var x = document.getElementById("add-info");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
</body>
</html>
Are all the entries on your page filled from the given template, meaning they are divs with the class entry? If so, I think your issue is the following: Your entry div has a child div with the id="add-info". And when you click the button, your handler function (myFunction()) tries to get a reference to that div via document.getElementById("add-info"); Now, if you have multiple such entries on a page, you will have multiple divs with id="add-info". But the id attribute of an element must be unique in your whole document. See the description of id or that of getElementById().
So the root cause of your problem is that the same id is used multiple times in the document when it shouldn't be. You get the behavior you're seeing because getElementById() just happens to be returning a reference to the first element it finds on the page, regardless of which button you click. But I believe you're in undefined behavior territory at that point.
One way to solve the problem is to somehow give myFunction() information about which button was clicked, while making each div you'd like to manipulate unique so they can be found easier. For instance, you can use the order of the restaurant on your page as its "index", and use that as the id of the div you'd like to hide/show. And you can also pass this index as an argument when you call your click handler:
...
<button id="btn" class="button-primary" onclick="myFunction('{{index}}')">Hide</button>
<div id="{{index}}">
<!-- The rest of the code here... -->
...
... add the index into your template context, so Handlebars can fill in the {{index}} placeholder:
...
$.each( tabletop.sheets("food").all(), function(i, food) {
food.index = i // Give your context its 'index'
var html = template(food);
$("#content").append(html);
});
...
... and then alter your function slightly to use the given argument instead of always looking for the div with id="add-info":
function myFunction(indexToToggle) {
var x = document.getElementById(indexToToggle);
// rest of the code is same
With this approach, I expect your DOM to end up with divs that have ids that are just numbers ("3", "4", etc.) and your click handler should get called with those as arguments as well.
Also note that your <button> element has id="btn". If you repeat that template on your page, you will have multiple <button>s with the same id. If you start trying to get references to your buttons via id you will have similar issues with them too since the ids won't be unique.

lazy loading images on scroll and "come into view"

I am using Lazy as a lazy image loading plugin. I have a div where I load divs like this:
<div class="nano-content" id="lScroll">
/*... MORE LIKE THIS ... */
<div class="card">
<div class="city-selected city-medium clickChampion pointer"
data-champ-id="1">
<article>
<div class="info">
<div class="city">
CHAMPNAME
</div>
</div>
</article>
<figure class="cFigure lazy" data-src="images/champions/CHAMPNAME_0.png"></figure>
</div>
</div>
/*... MORE LIKE THIS ... */
</div>
So I initiate the plugin and it works for the first ones visible and when I scroll:
var $lazy = $('#lScroll .lazy');
if ($lazy.length) {
$lazy.Lazy({
appendScroll: $('#lScroll')
});
}
But now I have a function that "filters" the divs by their attributes when I enter sth in my search input and it fails to load the image when the according div is shown:
$(document).on("keyup", "#searchVod", function () {
var $search = $(this);
var $sVal = $search.val().toLowerCase();
if ($sVal !== "") {
$(".vodCard").hide();
$('[data-champ*="' + $sVal + '"]').show();
$('[data-role*="' + $sVal + '"]').show();
} else {
$(".vodCard").show();
}
});
I tried bind: "event" /w and w/out delay: 0 (loading the plugin in the search function) but when I searched it would load ALL images immediately in the background.
Any hint highly appreciated
UPDATE: I just noticed in Chrome DevTab after entering one letter in my searchbox it loads ALL the images and eventually the one I am searching for (if its the last it takes some time (30MB sth)
There is an excellent library called Lozad.js which can help you to make it easier to load your images like lazy load do but in easier way.
You can download it here from Github.
Demo page here.
Explanation:
This library will load your images one by one on scrolling to each image anchor by class name.
Example
HTML:
At the header ->
<script src="https://cdn.jsdelivr.net/npm/lozad"></script>
Image element should looks like this:
<img class="lozad" data-src="image.png">
Javascript
// Initialize library
lozad('.lozad', {
load: function(el) {
el.src = el.dataset.src;
el.onload = function() {
el.classList.add('fade')
}
}
}).observe()
Hope it will help you.
Best,
Ido.

Url click counter, only registering one unique click counter from one browser

I want to make my post url to update the total click by registering it one unique click per browser everytime it is(the url) clicked, in simpler words, i want my total clicks to be unique.
I have found the method for url clicking here
http://jsfiddle.net/donejs/qYdwR/
//html
<!-- YOUR CODE HERE -->
<div id="content"></div>
<!-- PUT ANY TEMPLATES YOU NEED HERE -->
<script id="main-template" type="text/mustache">
<h2>CanJS component example</h2>
<click-counter></click-counter>
</script>
//javascript
var Component = can.Component.extend({
tag: 'click-counter',
template: '<a href="javascript://" can-click="updateCount">' +
'Click Me</a>' +
'<p id="msg">Clicked {{count}} times</p>',
scope: {
count: 0,
updateCount: function() {
this.attr('count', this.attr('count') + 1);
}
}
});
$('#content').html(can.view('main-template', {}));
The example of what i wish to do can be seen here pingje.org (article post).
Help me gurus, point me where to start, ive been trying to achieve this for days now, any time you took to answer my question is highly appreciated.

Single page app reload

I am writing a single page app with several divs that have the attribute data-roll="page". Pushing buttons fires ajax queries and the user is redirected to divs down the document like this
<body>
<div data-role="page" id="menu">
//bunch of nav buttons like <a href="#faculty">
</div>
<div data-role="page" id="faculty" data-theme="b">
//dynamicly loaded list of faculty
</div>
and so on.
I want to return to the menu div on refresh but no amount of scrolling
seems to work. Here is my JS with two attempts at getting back to the menu page on page load.
document.ready = init;
function init(){
var button = $('#facultyButton')
,facList = $('#facultyList')
,search = $('#facSearch')
,monikerBox = $('.monikerBox')
,events = $('#events')
,ajaxString = "http://stage.webscope.com/veith/dev/ajax.pl?"
,html = "";
//executed on init
$('html').scrollTop(0);
//events
$(window).on('load',function(){
$('html').scrollTop(0);
});
button.click(function(){
var value = "a";
search.html( "" );
facultyAjax(value);
});
I also tried window.location= menu url (home) in various functions with disastrous results!
Set the window.location you want the user to view with the location object on the load event.
I put this in the html.
<body onload="location.href='#menu'">

Nested layouts in backbone.marionette.js

Let's say that I have this JavaScript all nicely written out for Backbone.js, with Marionette.backbone.js):
(function () {
var Application;
$(function () {
Application = new Backbone.Marionette.Application();
Application.addRegions({
top: "#top",
middle: "#middle",
bottom: "#bottom"
});
var topLayout = Backbone.Marionette.ItemView.extend({
template: "#tpl_topLayout",
tagName: "article"
});
var middleLayout = Backbone.Marionette.Layout.extend({
template: "#tpl_middleLayout",
regions: {
left: "#left",
right: "#right"
}
});
var middleLayoutOne = Backbone.Marionette.ItemView.extend({
template: "#tpl_middleLayoutOne",
tagName: "article"
});
var middleLayoutTwo = Backbone.Marionette.ItemView.extend({
template: "#tpl_middleLayoutTwo",
tagName: "article"
});
var bottomLayout = Backbone.Marionette.ItemView.extend({
template: "#tpl_bottomLayout",
tagName: "article"
});
var a = new middleLayout;
a.left.show(new middleLayoutOne);
a.right.show(new middleLayoutTwo);
Application.top.show(new topLayout);
Application.middle.show(a);
Application.bottom.show(new bottomLayout);
Application.start();
});
}());
and this HTML ...
<article id="layouts">
<section id="top"></section>
<section id="middle"></section>
<section id="bottom"></section>
</article>
<script type="text/template" id="tpl_topLayout">
Top layout
</script>
<script type="text/template" id="tpl_middleLayout">
Middle layout
<div id="left"></div>
<div id="right"></div>
</script>
<script type="text/template" id="tpl_middleLayoutOne">
Middle layout 1
</script>
<script type="text/template" id="tpl_middleLayoutTwo">
Middle layout 2
</script>
<script type="text/template" id="tpl_bottomLayout">
Bottom layout
</script>
The 'middle' layout doesn't render properly (it renders #tpl_middleLayout, but not #tpl_middleLayoutOne or #tpl_middleLayoutTwo).
Any ideas on what I'm "forgetting" to do? I've got my guesses as to /why/ it's not working, but no idea on how to fix that problem .. and Google doesn't seem to want me to know the answer yet. :)
Any help would be very, very much appreciated.
when a parent is shown, all of it's existing children are closed so just change the order your code to show the parent view before showing children inside of it
Application.middle.show(a);
a.left.show(new middleLayoutOne);
a.right.show(new middleLayoutTwo);
Here follows the working JSFiddle. What happens is that your nested views are closed if you show your middle region after showing them. It's a "cascade". :)
So:
var a = new middleLayout;
Application.middle.show(a);
a.left.show(new middleLayoutOne);
a.right.show(new middleLayoutTwo);

Categories

Resources