Related
I understand this question has been answered already, but most of them are in jquery. At the moment function one and function two run at the same time. But how do I alter this code so function two only runs after function one has completed its journey to the top of the screen and back down again?
<html>
<head>
<title>JavaScript Animation</title>
</head>
<body>
<script>
function start() {
animation();
animationone();
}
function animation() {
obj = document.getElementById("jbtext");
obj.style.position = "absolute";
obj.style.bottom = "0px";
w = document.body.clientHeight;
goUp = true;
animateText();
}
var obj, w, goUp;
function animateText() {
var pos = parseInt(obj.style.bottom, 10);
(goUp) ? pos++ : pos--;
obj.style.bottom = pos + "px";
if (pos < 0) {
goUp = true;
}
if (pos > w) {
goUp = false;
}
if (pos < 0) {
return;
}
setTimeout(animateText, 10);
}
document.addEventListener("DOMContentLoaded", start, false);
function animationone() {
obja = document.getElementById("jbtexta");
obja.style.position = "absolute";
obja.style.left = "10px";
obja.style.bottom = "10px";
wtwo = document.body.clientWidth;
goRight = true;
animatesecond();
}
var obja, wtwo, goRight;
function animatesecond() {
var position = parseInt(obja.style.left, 10);
(goRight) ? position++ : position--;
obja.style.left = position + "px";
if (position > wtwo) {
goRight = false;
}
if (position < 0) {
goRight = true;
}
if (position < 0) {
return;
}
setTimeout(animatesecond, 10);
}
</script>
<p id="jbtext"> first function</p>
<p id="jbtexta"> second function</p>
</body>
</html>
You can use promises in javascript. Promises are a block of code that will run asynchronously and return at a later point in time. It "returns" by calling the resolve method which is an argument of the Promise constructor. You can then chain promises together to accomplish what you need.
function animationOne() {
return new Promise(function(resolve) {
// ... do your logic for the first animation here here.
resolve(); // <-- call this when your animation is finished.
})
}
function animationTwo() {
return new Promise(function(resolve) {
// ... do your logic for animation two here.
resolve(); // <-- call this when your animation is finished.
})
}
animationOne().then(function() {
animationTwo();
})
This is just another way of Peter LaBanca's answer.
I do not enjoy using Promises. Instead, I use async and await
function runFirst() {
//animation
}
async function waitThenRun() {
await runFirst();
//second animation
}
waitThenRun();
I just don't enjoy the idea of Promise. The code above runs waitThenRun(). That function then runs runFirst(), but waits until it has been finished to run the rest of the function. Having setTimeout or other ways of delaying code in runFirst means you should use Promise. (Pure JS)
MDN
How about the following script AnimationOneAndTwo? The script uses setInterval to “run” the animations. To use it create an instance using the factory method createInstance. Then when the condition or conditions to end the first animation are true call on the next method of the instance to start the second animation. Then when the condition or conditions to end the second animation are true call on the end method of the instance. The following snippet includes the definition for AnimationOneAndTwo and its application to your situation. For more details on how I created the function please refer to “How to Run One Animation after Another: A Reply to a Question at Stack Overflow”.
<html>
<head>
<title>JavaScript Animation</title>
</head>
<body>
<script>
/***
* AnimationOneAndTwo
* Copyright 2019 John Frederick Chionglo (jfchionglo#yahoo.ca)
***/
function AnimationOneAndTwo(parms) {
this.id = parms.id;
}
AnimationOneAndTwo.objs = [];
AnimationOneAndTwo.createProcessLogic = function(parms) {
var obj;
obj = new AnimationOneAndTwo({id: parms.id});
AnimationOneAndTwo.objs[parms.id] = obj;
if ("animationStepOne" in parms) {}
else {
throw new RangeError("animationStepOne not found in parms.");
}
obj["animationStepOne"] = parms.animationStepOne;
if ("animationStepTwo" in parms) {}
else {
throw new RangeError("animationStepTwo not found in parms.");
}
obj["animationStepTwo"] = parms.animationStepTwo;
if ("speed" in parms) {
obj.msf_0 = parms.speed;
}
return obj;
};
with (AnimationOneAndTwo) {
prototype.ap = window;
prototype.dc = window.document;
prototype.np = 6;
prototype.nt = 4;
prototype.ni = 7;
prototype.no = 3;
prototype.nn = 1;
prototype.nr = 1; (function(ia, pa) {
var str, j;
for (j=0; j<ia.length; j++) {
str = ' prototype.' + 'iE_in_' + ia[j] + ' = function() {\n';
str += ' this.s_in_' + ia[j] + ' = ( this.m_' + pa[j] + ' < 1 ? true : false );\n';
str += '};\n';
eval(str);
}
})([1], [0]);
(function(ia, pa) {
var str, j;
for (j=0; j<ia.length; j++) {
str = ' prototype.' + 'iE_in_' + ia[j] + ' = function() {\n';
str += ' this.s_in_' + ia[j] + ' = ( this.m_' + pa[j] + ' < 1 ? false : true );\n';
str += '};\n';
eval(str);
}
})([0,2,3,4,5,6], [0,2,0,2,5,4]);
(function(ia, pa) {
var str, j;
for (j=0; j<ia.length; j++) {
str = ' prototype.' + 'fE_in_' + ia[j] + ' = function() {\n';
str += ' this.m_' + pa[j] + ' -= 1;\n';
str += '};\n';
eval(str);
}
})([3,4,5,6], [0,2,5,4]);
(function(oa, pa, ka) {
var str, j;
for (j=0; j<oa.length; j++) {
str = ' prototype.' + 'fE_ou_' + oa[j] + ' = function() {\n';
str += ' this.m_' + pa[j] + ' += 1;\n';
str += '};\n';
eval(str);
}
})([0,1,2], [1,3,2]);
(function(ta, ia) {
var str, j, k, h;
for (j=0; j<ta.length; j++) {
str = ' prototype.' + 'iE_T_' + ta[j] + ' = function() {\n';
for (h=0; h<ia[j].length; h++) {
k = ia[j][h];
str += ' this.iE_in_' + k + '();\n';
}
if (ia[j].length<1) {
str += ' this.s_t_' + ta[j] + ' = true;\n';
} else {
str += ' this.s_t_' + ta[j] + ' = this.s_in_' + ia[j][0];
for (k=1; k<ia[j].length; k++)
str += ' && this.s_in_' + ia[j][k];
}
str += ';\n';
str += '};\n';
eval(str);
}
})([0,1,2,3], [[0], [1, 2], [3, 6], [4, 5]]);
(function(ta, ia, oa) {
var str, j, k, h;
for (j=0; j<ta.length; j++) {
str = ' prototype.' + 'fE_T_' + ta[j] + ' = function() {\n';
for (h=0; h<ia[j].length; h++) {
k = ia[j][h];
str += ' this.fE_in_' + k + '();\n';
}
for (h=0; h<oa[j].length; h++) {
k = oa[j][h];
str += ' this.fE_ou_' + k + '();\n';
}
str += '};\n';
eval(str);
}
})([0,1,2,3], [[], [], [3, 6], [4, 5]], [[], [], [2], []]);
(function(parms) {
var str, j, k, h, i;
var ta = parms.ta;
var pad = parms.pad;
var pat = parms.pat;
var tar = parms.tar;
var tad = parms.tad;
var tav = parms.tav;
for (i=0; i<ta.length; i++) {
j = ta[i];
str = ' prototype.' + ' pEv_T_' + j + ' = function() {\n';
str += ' this.fE_T_' + j + '();\n';
for (h=0; h<tar[j].length; h++) {
k = tar[j][h];
str += ' this.iE_T_' + k + '();\n';
}
str += ' };\n';
eval(str);
}
})({
ta: [0,1,2,3],
tar: [[0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3], [1, 3]]
});
prototype.pEv_T_0 = function() {
this.fE_T_0();
this.iE_T_0();
this.iE_T_1();
this.iE_T_2();
this.animationStepOne();
};
prototype.pEv_T_1 = function() {
this.fE_T_1();
this.iE_T_0();
this.iE_T_1();
this.iE_T_2();
this.iE_T_3();
this.animationStepTwo();
};
prototype.ipn = function() {
this.iE_T_0();
this.iE_T_1();
this.iE_T_2();
this.iE_T_3();
};
prototype.im = function() {
var j, h, pa;
for (j=0; j<this.np; j++) {
eval('this.m_' + j + ' = 0');
}
pa = [1,2,3];
for (h=0; h<pa.length; h++) {
j = pa[h];
eval('this.m_' + j + ' = ' + 0);
}
pa = [0,4,5];
for (h=0; h<pa.length; h++) {
j = pa[h];
eval('this.m_' + j + ' = ' + 1);
}
};
prototype.ai_0 = undefined;
prototype.msf_0 = 10;
prototype.mss_0 = 1500;
prototype.ms_0 = prototype.msf_0;
prototype.sp_0 = function() {
if (this.ai_0) { this.ap.clearInterval(this.ai_0); this.ai_0 = undefined; }
};
prototype.st_0 = function() {
if (this.ai_0) { this.sp_0(); }
this.ai_0 = this.ap.setInterval('AnimationOneAndTwo.objs[' + this.id + '].rn_0()', this.ms_0);
};
prototype.rn_0 = function() {
var t;
var et = [];
if (this.s_t_0) {
this.pEv_T_0();
} else if (this.s_t_1) {
this.pEv_T_1();
} else {
if (this.ai_0) {
this.sp_0();
}
}
};
prototype.start = function() {
with (this) {
if (ai_0) { sp_0(); }
im();
ipn();
st_0();
}
};
prototype.next = function() {
if (this.s_t_2) {
this.pEv_T_2();
} else if (this.s_t_3) {
this.pEv_T_3();
}
};
prototype.end = function() {
if (this.s_t_2) {
this.pEv_T_2();
}
if (this.s_t_3) {
this.pEv_T_3();
}
};
}
var aotobj;
function start() {
animation();
animationone();
aotobj = AnimationOneAndTwo.createProcessLogic({
id: 12345
, animationStepOne: animateText
, animationStepTwo: animatesecond
});
aotobj.start();
}
function animation() {
obj = document.getElementById("jbtext");
obj.style.position = "absolute";
obj.style.bottom = "0px";
w = document.body.clientHeight;
goUp = true;
// animateText();
}
var obj, w, goUp;
function animateText() {
var pos = parseInt(obj.style.bottom, 10);
(goUp) ? pos++ : pos--;
obj.style.bottom = pos + "px";
if (pos < 0) {
goUp = true;
}
if (pos > w) {
goUp = false;
}
if (pos < 0) {
aotobj.next();
return;
}
// setTimeout(animateText, 10);
}
document.addEventListener("DOMContentLoaded", start, false);
function animationone() {
obja = document.getElementById("jbtexta");
obja.style.position = "absolute";
obja.style.left = "10px";
obja.style.bottom = "10px";
wtwo = document.body.clientWidth;
goRight = true;
// animatesecond();
}
var obja, wtwo, goRight;
function animatesecond() {
var position = parseInt(obja.style.left, 10);
(goRight) ? position++ : position--;
obja.style.left = position + "px";
if (position > wtwo) {
goRight = false;
}
if (position < 0) {
goRight = true;
}
if (position < 0) {
// AnimationOneAndTwo.objs[12345].end();
aotobj.end();
return;
}
// setTimeout(animatesecond, 10);
}
</script>
<p id="jbtext"> first function</p>
<p id="jbtexta"> second function</p>
</body>
</html>
DEMO
I'am developing a Pagination Functionality using handlebars js and fetching the data from JSON.
First 5 results will be shown on page load.
on click of next pagination another set of 5 results will be displayed and so on.
If i have total number of results 100 by displaying each 5 Results in page. Page Numbers will be 1 of 20.
if the pagination has more then 5 number of Pages , I want to display "1,2,3 ... last Page Number (20)" same vice versa
on load Previous Button Should be hidden when ever next page is clicked it has to be enabled.
Request to you please look into this and give some advice / suggestion on this.
Should be Like Below
Appreciate your kind help !
Thanks
some code sample :
$(function () {
var opts = {
pageMax: 5,
postsDiv: $('#posts'),
dataUrl: "searchResult.json"
}
function range(i) { return i ? range(i - 1).concat(i) : [] }
function loadPosts(posts) {
opts.postsDiv.empty();
posts.each(function () {
var source = $("#post-template").html();
var template = Handlebars.compile(source);
var context = {
title: this.title,
desc: this.body,
};
var html = template(context);
opts.postsDiv.append(html);
});
}
function paginate(pageCount) {
var source = $("#pagination-template").html();
var template = Handlebars.compile(source);
var context = { pages: range(pageCount) };
var html = template(context);
opts.postsDiv.after(html);
function changePage(pageNumber) {
pageItems.removeClass('active');
pageItems.filter('[data-page="' + pageNumber + '"]').addClass('active');
loadPosts(data.slice(pageNumber * opts.pageMax - opts.pageMax, pageNumber * opts.pageMax));
}
var pageItems = $('.pagination>li.pagination-page');
pageItems.on('click', function () {
changePage(this.getAttribute('data-page'));
}).filter('[data-page="1"]').addClass('active');
$('.pagination>li.pagination-prev').on('click', function () {
gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) - 1;
if (gotoPageNumber <= 0) { gotoPageNumber = pageCount; }
changePage(gotoPageNumber);
});
$('.pagination>li.pagination-next').on('click', function () {
gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) + 1;
if (gotoPageNumber > pageCount) { gotoPageNumber = 1; }
changePage(gotoPageNumber);
});
}
$.ajax({
dataType: 'json',
url: opts.dataUrl,
success: function (response_json) {
data = $(response_json.records.page);
dataCount = data.length;
pageCount = Math.ceil(dataCount / opts.pageMax);
if (dataCount > opts.pageMax) {
paginate(pageCount);
posts = data.slice(0, opts.pageMax);
} else {
posts = data;
}
loadPosts(posts);
}
});
});
I had to solve a similar issue a few months ago. I found this Gist from kottenator.
Your range function is modified thusly, with c being the current page, and m your pageCount. Calls to the function have been modified a bit and a recursive call to your paginate(...) function is also added to recompute the tag after navigation (also, a branch was added to your DOM appending function calls, to modify the pagination tag, I used a ternary operator. There may be more elegant to achieve this).
See this CodePen
function range(c,m) {
var current = c || 1,
last = m,
delta = 2,
left = current - delta,
right = parseInt(current) + delta + 1,
range = [],
rangeWithEllipsis = [],
l,
t;
range.push(1);
for (var i = c - delta ; i <= c + delta ; i++) {
if (i >= left && i < right && i < m && i > 1) {
range.push(i);
}
}
range.push(m);
for (var i of range) {
if (l) {
if (i - l === 2) {
t = l+1;
rangeWithEllipsis.push(t);
} else if (i - l !== 1) {
rangeWithEllipsis.push("...");
}
}
rangeWithEllipsis.push(i);
l = i;
}
return rangeWithEllipsis;
}
It doesn't solve exactly your problem per say, but it does paginate correctly.
If I have some time, I'll try and make it paginate the exact way you want to (it's really only about customizing the delta, left and right operand in the algorithm, and changing your pagination next and pagination prev event handler calls).
Edit I changed the algorithm to find the left and right boundary. Your index.html is also modified a bit.
The idea is to compute the left and right boundary by multiples of 5. You then create a range of the indexes to show and add an elipsis if the difference is too big. This should effectively solves your original problem.
JavaScript
getFirstDigits = (t) => {
return parseInt(t.toString().slice(0,-1))
}
getLastDigit = (t) => {
return parseInt(t.toString().slice(-1))
}
isMultipleOf5 = (t) => {
return [0,5].reduce((res,curr)=>{
return res = res || curr === getLastDigit(t);
},false);
}
isBetween0and5 = (t) => {
const _t = getLastDigit(t);
return _t < 5;
}
isBetween5and9 = (t) => {
const _t = getLastDigit(t);
return _t => 5 && _t <= 9;
}
appendDigit = (t,d) => {
return parseInt(getFirstDigits(t).toString() + d.toString())
}
getSecondRightMostDigit = (t) => {
return parseInt(t.toString().slice(-2,-1))
}
incrementSecondDigit = (t) => {
return t+10;
}
getLeft = (t) => {
if(t>=10){
if(isBetween0and5(t)) return appendDigit(t,0);
else return appendDigit(t,5);
} else {
if (t<5) return 0;
else return 5;
}
}
getRight = (t) => {
if(t<5) return 5;
else if (t<10) return 10;
else if(isBetween0and5(t)) return appendDigit(t,5)
else return appendDigit(incrementSecondDigit(t),0);
}
function range(c,m) {
var current = c || 1,
last = m,
delta = 2,
left = getLeft(c),
right = getRight(c),
range = [],
rangeWithEllipsis = [],
l,
t;
var rightBoundary = right < 5 ? 5 : right;
for (var i = left ; i < rightBoundary ; ++i) {
if( i < m && i > 0) range.push(i);
}
range.push(m);
for (var i of range) {
if (l) {
if (i - l === 2) {
t = l+1;
rangeWithEllipsis.push(t);
} else if (i - l !== 1){
rangeWithEllipsis.push("...");
}
}
rangeWithEllipsis.push(i);
l = i;
}
return rangeWithEllipsis;
}
HTML/HandleBars
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Handlebars Pagination</title>
<link href="main.css" rel="stylesheet" />
<script src="jquery.min.js"></script>
<script src="handlebars.min.js"></script>
<script src="functions.js"></script>
</head>
<body class="container">
<div id="posts"></div>
<script id="pagination-template" type="text/x-handlebars-template">
<ul class="pagination">
<li class="pagination-prev">«</li>
{{#each pages}}
<li class="pagination-page" data-page="{{this}}">{{this}}</li>
{{/each}}
<li class="pagination-next">»</li>
</ul>
</script>
<script id="post-template" type="text/x-handlebars-template">
<div class="score-structural score-column2-wideright search-listings post">
<div class="score-right">
<h4>{{record_count}}</h4>
<h5 style="z-index: 1;">
{{ title }}
</h5>
<p style="z-index: 1;"> {{ desc }} </p>
</div>
</div>
<hr>
</script>
</body>
</html>
<script>
$(function () {
var opts = {
pageMax: 2,
postsDiv: $('#posts'),
dataUrl: "searchResult.json"
}
function loadPosts(posts) {
opts.postsDiv.empty();
posts.each(function () {
var source = $("#post-template").html();
var template = Handlebars.compile(source);
var context = {
title: this.title,
desc: this.body,
};
var html = template(context);
opts.postsDiv.append(html);
});
hidePrev();
}
function hidePrev() { $('.pagination .pagination-prev').hide(); }
function showPrev() { $('.pagination .pagination-prev').show(); }
function hideNext() { $('.pagination .pagination-next').hide(); }
function showNext() { $('.pagination .pagination-next').show(); }
function paginate(page,pageCount) {
var source = $("#pagination-template").html();
var template = Handlebars.compile(source);
var context = { pages: range(page,pageCount) };
console.log(range(page,pageCount));
var html = template(context);
var paginationTag = opts.postsDiv.parent().find(".pagination");
paginationTag.length > 0 ? paginationTag.replaceWith(html) : opts.postsDiv.before(html);
function changePage(page) {
pageItems.removeClass('active');
pageItems.filter('[data-page="' + page + '"]').addClass('active');
loadPosts(data.slice(page * opts.pageMax - opts.pageMax, page * opts.pageMax));
paginate(page,pageCount);
if (gotoPageNumber <= 1) {
hidePrev();
}
}
var pageItems = $('.pagination>li.pagination-page');
var pageItemsLastPage = $('.pagination li').length - 2;
pageItems.removeClass('active');
pageItems.filter('[data-page="' + page + '"]').addClass('active');
pageItems.on('click', function () {
getDataPageNo = this.getAttribute('data-page')
console.log(getDataPageNo)
changePage(getDataPageNo);
if (getDataPageNo == 1) {
hidePrev()
}
else if (getDataPageNo == pageItemsLastPage) {
hideNext();
}
else {
showPrev();
showNext();
}
});
$('.pagination>li.pagination-prev').on('click', function () {
gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) - 1;
changePage(gotoPageNumber);
});
$('.pagination>li.pagination-next').on('click', function () {
gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) + 1;
if (gotoPageNumber > pageCount) {
gotoPageNumber = 1;
showPrev();
}
changePage(gotoPageNumber);
});
}
$.ajax({
dataType: 'json',
url: opts.dataUrl,
success: function (response_json) {
data = $(response_json.records.page);
dataCount = data.length;
pageCount = Math.ceil(dataCount / opts.pageMax);
if (dataCount > opts.pageMax) {
paginate(1,pageCount);
posts = data.slice(0, opts.pageMax);
} else {
posts = data;
}
loadPosts(posts);
}
});
});
</script>
I'm new to Javascript, and callbacks are blowing my mind a little at the moment. How do I turn the teletyperDiologue function into a callback? The main reason is I want the teletyper to finish it's job before the displayOut function finishes. Thank you in advance for your help.
function displayOut() {
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
};
// Teletyper for Diologue Box
function teleTyperDiologue(string) {
for (let i = 0; i < string.length; i++) {
setTimeout(function() {
diologueBox.innerHTML += string.slice(i, i + 1);
}, 5 * i);
}
}
As an example:
function test(a) { a(); }
function x() { alert('hello'); }
test(x);
in your case:
function displayOut(callback) {
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
callback(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
};
displayOut(teleTyperDiologue);
You can pass functions around like variables and return them in functions and use them in other functions. So, when you pass a callback function as an argument to another function, you only need to pass the function definition.
See example below.
function displayOut() {
console.log("Display Out running...");
}
function teleTyperDiologue(stringParam, callback) {
console.log("Running teleTyper with string param passed of: ", stringParam);
callback();
}
teleTyperDiologue ("Test string", displayOut);
This is a program to find the nth fibonacci number.
var fib = (function() {
var save = [];
var i = 0;
return {
"getNum": function(input) {
this.input = input;
if (input === 0) {
console.log("Invalid input");
}
save[i] = i;
save[i + 1] = i + 1;
save[i + 2] = i + 1;
i = 2;
for (i >= 2; i < input; i = i + 1) {
save[i + 1] = save[i] + save[i - 1];
}
console.log(save[i - 1]);
}
}
}());
fib.getNum(4);
My question is when I implement this problem in the following way, it doesn't work. I understand this is because I am not calling the sub-functions and only calling the main function. Is there a better pattern we can use that will keep the code organised and we won't have to make calls to so many functions?
var fib = (function() {
var save = [];
var i = 0;
return {
"getNum": function(input) {
this.input = input;
function valid() {
if (input === 0) {
console.log("Invalid input");
}
}
function config() {
save[i] = i;
save[i + 1] = i + 1;
save[i + 2] = i + 1;
i = 2;
}
function nthNum() {
for (i >= 2; i < input; i = i + 1) {
save[i + 1] = save[i] + save[i - 1];
}
console.log(save[i - 1]);
}
}
}
}());
fib.getNum(4);
You can think of using closure to create private and public functions.If you see the below code only _getNum function is exposed.
var fib = (function() {
var save = [];
save[0] = 0;
save[1] = 1;
var i = 0;
//This will validate the number
// This function can be avoided and make _getNum do the same
function _valid(input){
console.log("Method Executing:_valid");
input === 0 ? console.log('Invalid Input') : _nthNum(input);
}
// Will calualte the series.
// This is a private function
function _nthNum(input) {
console.log('Method Executing:_nthNum');
for (i = 2; i<=input; i++) {
save[i] = save[i-2] + save[i - 1];
}
console.log(save.pop());
}
// Private Function
function _getNum(input){
console.log("Method Executing :_getNum" ,input);
_valid(input);
}
//Expose the private function
return {
getNum :_getNum // Expose _getNum
}
}());
fib.getNum(0);
fib.getNum(4);
fib.getNum(7);
WORKING COPY
My suggestion:
var Fibonacci = (function() {
var _Fibonacci = {
// set initial values
result: [0, 1, 1],
input: 0,
// main function
find: function (number) {
this.input = number;
if (this.isValid()) {
this.calculate();
return this.result.pop();
}
return 'Invalid input';
},
// sub functions
isValid: function () {
return this.input != 0
},
calculate: function () {
for (var i=2; i<this.input; i++) { // fix your code here
this.result[i+1] = this.result[i] + this.result[i-1];
}
}
};
// return the main function
return _Fibonacci.find.bind(_Fibonacci);
}());
console.log(
Fibonacci(0),
Fibonacci(4),
Fibonacci(6)
);
I've tried this a thousand different ways in a thousand different times and my JS code won't come out the way I want it. When I run it in the Mozilla scratchpad, I get "userHand is undefined" and the second printHand shows as undefined, too. Could someone show me where are the errors in my blackjack game?
function Card (s, n) {
var suit = s;
var number = n;
this.getNumber = function () {
return number;
};
this.getSuit = function () {
return suit;
};
this.getValue = function () {
if (number > 10) {
return 10;
} else if (number === 1) {
return 11;
} else {
return number;
}
};
}
var cardNames = {1:"Ace", 2:"2", 3:"3", 4:"4", 5:"5", 6:"6", 7:"7", 8:"8", 9:"9", 10:"10", 11:"Joker", 12:"Queen", 13:"King"};
var suitNames = {1:"Clubs", 2:"Diamonds", 3:"Hearts", 4:"Spades"};
var deal = function () {
var s = Math.floor(Math.random() * 4 + 1);
var n = Math.floor(Math.random() * 13 + 1);
return new Card(s, n);
};
function Hand(){
var cards = [];
cards.push(deal());
cards.push(deal());
this.getHand = function () {
return cards;
};
this.score = function () {
var score;
for (i = 0; i < cards.length; i++) {
score = score + cards[i].getValue();
}
for (i = 0; i < cards.length; i++) {
if (score > 21 && cards[i].getValue() === 11) {
score = score - 10;
}
} return score;
};
this.printHand = function () {
for (i = 0; i < cards.length; i++) {
var hand;
if (i === 0) {
hand = cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
} else {
hand = hand + " and a " + cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
}
} alert(hand);
};
this.hitMe = function () {
cards.push(deal());
};
}
var playAsDealer = function () {
var playDealer = new Hand();
while (playDealer.score() < 17) {
playDealer.hitMe();
}
this.printHand = function () {
return playDealer.printHand();
};
this.score = function () {
return playDealer.score();
};
};
var playAsUser = function () {
var playUser = new Hand();
this.printHand = function () {
return playUser.printHand();
};
this.score = function () {
return playUser.score();
};
var decision = confirm("Your hand is " + playUser.printHand() + ". Click OK to hit or Cancel to stand");
for (i = 0; decision !== false; i++) {
playUser.hitMe();
decision = confirm("Your hand is " + playUser.printHand() + ". Click OK to hit or Cancel to stand");
}
};
var declareWinner = function (userHand, dealerHand) {
if ((userHand.score < dealerHand.score) || userHand.score > 21) {
return "You lose.";
} else if (userHand.score > dealerHand.score) {
return "You win.";
} else {
return "You tied.";
}
};
var playGame = function () {
var user = playAsUser();
var dealer = playAsDealer();
declareWinner(user, dealer);
console.log("User got " + user.printHand());
console.log("Dealer got " + dealer.printHand());
};
playGame();
You aren't returning nothing on printHand()
I just added the return statement and worked. See this fiddle
this.printHand = function () {
for (i = 0; i < cards.length; i++) {
var hand;
if (i === 0) {
hand = cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
} else {
hand = hand + " and a " + cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
}
}
//alert(hand); //remove this alert
return hand; // <----- solution
};