Captain.speak() method issue - javascript

I am currently learning about objects within class. I created an object with constructor notation in Javascript, and instantiated four different objects with distinct names. For some reason, when I try to run the Captain.speak() method in my code, it doesn't work. It should display the Captain.strPhase string that I created right before initiating the command for the function. When I check this in online compilers, there are no errors, but it doesn't output my string. Would anyone happen to know why?
$(document).ready(function() {
function Pirate(rank, phrase, id) {
output = "";
randNum = 1;
secretNum = 1;
this.strRank = rank;
this.intNum = favnum;
this.strPhrase = phrase;
this.elOutput = document.getElementById(id);
this.speak = function() {
this.elOutput.innerHTML += "<br>" + this.strPhrase;
}; //End speak
this.chooseRandNum = function() {
this.randNum = Math.floor(Math.random() * 10);
}; //End chooseRandNum
}; //End Pirate
var Captain = new Pirate("Captain", "", "captain");
var firstMate = new Pirate("First Mate", "I love guessing games!", "pirate1");
var Quartermaster = new Pirate("Quartermaster", "This game should be fun.", "pirate2");
var Gunner = new Pirate("Gunner", "Let's start playing!", "pirate3");
Captain.strPhrase = "Argh maties, ready to play a guessing game?";
Captain.speak();
}); // end of $(document).ready()
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Begin every html page with everything up to this point (just use your own header block) -->
<!-- Also, feel free to remove all the instructional comments as you modify this file to make it yours. -->
<!-- This <title> displays in the page tab -->
<title>Randomness</title>
<!-- This will link to your CSS stylesheet for formatting as soon as you create the file. The page will work without it, though. -->
<link rel="stylesheet" href="css/myFancyStylesheet.css">
<!-- This links to the jQuery library so your js code will work
Always include this *before* your own js code (extremely important) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- This links to the js code specific for this page -->
<script src="Randomness.js"></script>
</head>
<body>
Captain's Guessing Game:
<br></br>
<div id="captain">
</div>
<br></br>
<div id="pirate1">
</div>
<br></br>
<div id="pirate2">
</div>
<br></br>
<div id="pirate3">
</div>
</body>
</html>

When I run your code, I get an error message:
Uncaught ReferenceError: favnum is not defined
If you comment out this line...
// this.intNum = favnum;
...everything should work just fine.

Related

How to load javascript files using event listeners

This question is not duplicate of
Conditionally load JavaScript file
and nor this
How to include an external javascript file conditionally?
I have gone through them, they are kind of similar to what I want to do but not exactly same. Here is how, in the above question the user just wants to load the script file once based on a condition. But in my case I want to load different js files based on click events.
So here in my case I have an HTML document:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Experiment</title>
<link href="s.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navigation">
<nav>
<ul>
<li id="home_btn"> Home</li>
<li id="about_btn"> About </li>
</ul>
</nav>
</div>
<canvas id="myCanvas">
</canvas>
<div class="notePane">
<p> This is just a bunch of text not explanation</p>
</div>
</body>
<script src="./exp.js" type="text/javascript"></script>
</html>
and this h.html file is linked to an exp.js file. Now in the exp.js file :
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
var js = document.createElement("script");
js.type="module";
h_btn.addEventListener("click", showHome );
a_btn.addEventListener("click", showAbout);
function showHome() {
js.src="./j1.js";
head.appendChild(js);
}
function showAbout() {
js.src="./j2.js";
head.appendChild(js);
}
So things work fine when I click the h_btn on the web page. It loads j1.js. But then when I click on the a_btn on the web page I expect to see j2.js linked but I don't see it. I have to refresh the page and then click on a_btn to see j2.js linked. How do I link j1.js and j2.js such that I don't have to refresh the page again and again to load the correct script.
Update: OP has updated the question requirements such that he wants to "unload" a JS file when another is clicked. There is no way to undo all the runtime logic once a JS file is loaded: the only way is to reload the page. Removing the <script> tag or changing the src attribute will not magically unbind event listeners or "undeclare" variables.
Therefore, if OP wants to "start anew", the only way is to check if a custom script has been loaded before: if it has, we force reload the page. There are of course many ways to "inform" the next page which source to load, if available: in the example below, we use query strings:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
var appendedScriptKey;
var scripts = {
'home': './j1.js',
'about': './j2.js'
}
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
// Check query string if a specific script is set
var params = (new URL(document.location)).searchParams;
var scriptKey = params.get('scriptKey');
if (scriptKey && scriptKey in scripts) {
appendScript(scriptKey);
}
function appendScript(key) {
if (hasAppendedScript) {
location.href = location.href + (location.search ? '?' : '&') + 'script=' + key;
location.reload();
}
var js = document.createElement("script");
js.type="module";
js.src = scripts[key];
head.appendChild(js);
appendedScript = key;
}
function showHome() {
appendedScriptKey('home');
}
function showAbout() {
appendScript('about');
}
This is because of how Node.appendChild() works. The first click works because you're creating a new element and inserting it into your document. However, the second click will not work as you've expected because the node already exists:
The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position
This means that the second click will only mutate the src attribute of the already-injected <script> element instead of creating a new one, and that also means that the second script src will not be loaded.
A solution will be to use a function that will create a script tag every single time:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
function insertScript(src) {
var js = document.createElement("script");
js.type = "module";
js.src = src;
head.appendChild(js);
}
function showHome() {
insertScript('./j1.js');
}
function showAbout() {
insertScript('./j2.js');
}
But this will also mean that multiple clicks on the same button will cause the script to be injected multiple times. This does not affect browser performance much since the browser has the loaded script cached somewhere, but to guard against this, it might be a good idea to implement some kind of unique identifier per script, and check against that before injection. There are many ways to do this, and this is just one way:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
// Store scripts that you've injected
var scripts = [];
function insertScript(src) {
// If we have previously attempted injection, then do nothing
if (scripts.indexOf(src) !== -1) {
return;
}
var js = document.createElement("script");
js.type = "module";
js.src = src;
head.appendChild(js);
// Push script to array
scripts.push(src);
}
function showHome() {
insertScript('./j1.js');
}
function showAbout() {
insertScript('./j2.js');
}
Alternative unique script injection strategies and ideas:
Use ES6 Map() to track unique script sources being injected
Perhaps only store src to array/dict/map when the script has successfully loaded
You have to create the element twice, as there can only be one element with 1 src.
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var js1 = document.createElement("script");
var js2 = document.createElement("script");
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
function showHome() {
js1.src = "j1.js";
document.body.appendChild(js1);
}
function showAbout() {
js2.src = "j2.js";
document.body.appendChild(js2);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Experiment</title>
<link href="s.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navigation">
<nav>
<ul>
<li id="home_btn"> Home</li>
<li id="about_btn"> About </li>
</ul>
</nav>
</div>
<canvas id="myCanvas">
</canvas>
<div class="notePane">
<p> This is just a bunch of text not explanation</p>
</div>
</body>
<script src="exp.js" type="text/javascript"></script>
</html>

Load Function to HTML//Generate Random Words

I'm super stuck. I'm creating a hangman game for a class and I cannot get the words to generate and show in my HTML. We're required to have them show as underscores but I cannot get them to show in the HTML either. I've been able to get it to show in the console but not in my HTML.Any help would be appreciated or any assistance in troubleshooting.
please see the code.
//horror movie titles selected to guess
var movieTitles = [
"halloween",
"suspiria",
"audition",
"hereditary",
"the beyond",
"the evil dead",
"the blair witch project"
];
//letters already guessed
var guessedLetters = [];
var numOfLetters = [];
//randomly assigned variable
var movieToGuess = null;
//attempts left
var livesLeft = 8;
//games won
var wins = 0;
//games lost
var losses = 0;
window.onload = function() {
updateMovieToGuess();
};
var updateMovieToGuess = function() {
for (var i = 0; i < numOfLetters.length; i++){
numOfLetters[i] = "_".join(" ");
}
var movieToGuess = movieTitles[Math.floor(Math.random() * movieTitles.length)];
document.getElementById("movie-title").innerHTML = movieToGuess;
};
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hangman</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="javascript/games.js"></script>
<link href="https://fonts.googleapis.com/css?family=IM+Fell+Double+Pica+SC" rel="stylesheet"> </head>
<body>
<p>Press any key to get started<span id='any-key'> </span> </p>
<p>Movie Title:<span id="movie-title"> </span> </p>
<p>Letters Guessed: <span id='letters'> </span> </p>
<p>Lives Remaining:<span id='lives-left'> </span> </p>
<p>Movies You've Survived:<span id='wins'> </span> </p>
<p>Movies You Died In:<span id='lost'> </span> </p>
<footer> </footer>
</body>
</html>
Two problems:
querySelector is looking for <movie-title> instead of <span id="movie-title">. To fix it, either use getElementById instead of querySelector, or change movie-title to #movie-title.
As Mark Meyer pointed out in a comment, you're using movieToGuess before you set it.
EDIT: I see you edited your question and its code after I answered it. You fixed problem #2 but not #1. Worse, you introduced a new problem: you now add the call to updateMovieToGuess via window.onload inside of updateMovieToGuess instead of at top level, so it never gets called (essentially, you've created a chicken-and-egg problem).

Javascript of selected php file won't load when using JQuery's load(file.php) method

I have a master container php file with a div container. Initially, the div container doesn't have any content or html children by default when page is loaded. I use JQuery to load php files to this div container when the user clicks a navigation item in the navbar.
landingpage.php
<?php
require_once 'navbar.php';
?>
<!DOCTYPE html>
<html>
<head>
<title>Admin | Dashboard</title>
<link rel="stylesheet" href="css/dashboard_admin.css">
</head>
<body>
<div class="wrapper">
<!-- CONTENT CONTAINER's content depends on what was clicked on navbar -->
<div class="container" id="content_container">
<div class="div_dashboardLabel" id="dashboard_Label">
<h2 id="label_Dashboard">Admin Dashboard</h2>
</div>
</div>
<!-- END OF CONTENT CONTAINER-->
</div>
<!-- end of wrapper-->
<script src="js/jquery-3.3.1.js"></script>
<script type="text/javascript">
var user = '<?php echo json_encode($user);?>';
var role = '<?php echo json_encode($role); ?>';
</script>
<script src="js/landingpage.js"></script>
</body>
</html>
landingpage.js
/* GLOBAL VARIABLES WITHIN THIS DOCUMENT*/
var div_content_container = $("#content_container");
var navitem_dashboard = $("#admin_dashboard");
var navitem_admin_account_management = $("#admin_accountmanagement");
var userObj = JSON.parse(user);
var roleObj = JSON.parse(role);
var logout = $('#logout');
/* END */
$(document).ready(function(){
loadDashboard(); // dashboard is loaded as default view.
navitem_admin_account_management.on("click",loadAccountManagement);
});
function loadDashboard() {
var url_admin_dashboard = 'view/admin_dashboard.php';
var url_teacher_dashboard = 'view/teacher_dashboard.php';
var url_student_dashboard = 'view/student_dashboard.php';
div_content_container.html('');
if (roleObj.rolename === 'Administrator') {
div_content_container.load(url_admin_dashboard);
} else if (roleObj.rolename === 'Teacher') {
div_content_container.load(url_teacher_dashboard);
} else if (roleObj.rolename === 'Student') {
div_content_container.load(url_student_dashboard);
}
}
function loadAccountManagement(){
var url = 'view/admin_accountmanagement.php';
div_content_container.html('');
div_content_container.load(url);
}
Everything works as expected for landingpage.php which uses landingpage.js for the front end. No problem.
The problem is when admin_accountmanagement.php file is loaded in div_content_container. The JS of admin_account_management.php doesn't seem to bind to elements:
function loadAccountManagement(){
var url = 'view/admin_accountmanagement.php'; // has its JS file
div_content_container.html('');
div_content_container.load(url);
}
For example, let's take url which is 'view/admin_accountmanagement.php' This page gets loaded within div_content_container when user clicks a navbar item Account Management
as in
<div class="wrapper">
<!-- CONTENT CONTAINER's content depends on what was clicked on navbar -->
<div class="container" id="content_container">
<!-- view/admin_accountmanagement.php loaded here -->
</div>
<!-- END OF CONTENT CONTAINER-->
</div>
There are no problems displaying the page or replacing the current element contained in the div_content_container. The problem is, the JS file attached to view/admin_accountmanagement.php doesn't seem to apply when view/admin_accountmanagement.php page is loaded in div_content_container
The view/admin_accountmanagement.php is loaded but the click events binded to the elements of view/admin_accountmanagement.php doesn't work. I know this because I tried to display an alert() message on $(document).ready()
admin_accountmanagement.php
<body>
<div>
<button class="button" id="btn_AddUser">
Add New User
</button>
</div>
<script src="js/admin_accountmanagement.js"></script> <!-- this JS doesn't seem to get binded when this page is loaded in the div_content_container -->
</body>
admin_accountmanagement.js
var btn_add_user = $('#btn_AddUser');
$(document).ready(function(){
alert("TEST"); //doesn't work no alert message.
btn_add_user.on("click",test); //doesn't work no alert message
});
function test(){
alert("testing"); //doesn't work. no alert message
}
I'm only able to display the page but when I click on the <button id="btn_AddUser"> nothing happens.
How can I solve this given the how I structured the loading of pages to div_content_container?
Thanks in advance.
Change your admin_accountmanagement.js to
var btn_add_user = $('#btn_AddUser');
alert('Account management js loaded'); // this should show alert
$(document).on("click",btn_add_user,test);
function test(){
alert("testing"); //doesn't work. no alert message
}
This method works because the binding is not dependent on "document ready" as document ready has already been fired when you loaded the parent page for the first time
#jordan i agree with #Magnus Eriksson as it is better to bind it on('event','selector','function') but make use of .off() before your .on() as you are playing with dynamic content which may cause multiple binding of the function. And if you are still not able to get the binding event to work you can try injecting the .js file in your page's head section after the load of your content like: $('head').append('<script src="admin_accountmanagement.js"></script>'). With your load() function in your js to bind the click event.
Or, your use the below code snippet:
function LoadContent()
{
var url = 'view/admin_accountmanagement.php';
var jssrc = 'js/admin_accountmanagement.js';
div_content_container.html('');
div_content_container.load(url);
if($('head').find('*[src="'+jssrc+'"]').length==0)
{
//the below approach have some consequences related to it as you will not be able to see the injected js in your developers tool's Sources(in chrome).
$('head').append('<script src="'+jssrc+'"></script>');
}
}
and then on your .js will look like this:
var btn_add_user = null;
$(window).load(function(){
alert("TEST");
btn_add_user = $('#btn_AddUser');
btn_add_user.off('click').on("click",test); //use .off('event') if load() is being called multiple times.
});
function test(){
alert("testing");
}

how to create a dynamic array in javascript based on the number of files in same directory

I have a static page, which I'm using for viewing pictures, and the javascript does the slide show; however, I would like to dump the pictures in same directory and when page is opened, the javascript will create an array with all the pictures without me having to edit the array for every scenario.... is this possible?... I know javascript has some security restrains when it comes to read from local filesystem. here's the static page and javascript
<!doctype html>
<html lang="en">
<head>
<title>Picture Show</title>
<link type="text/css" rel="stylesheet" href="stylesheet.css" />
<script type="text/javascript" src="slideshow.js"></script>
</head>
<body>
<!-- Insert your content here -->
<div id="container">
<div id="header">
<h1>Slide Show</h1>
<a id="link" href="javascript:slideShow()"></a>
</div>
<div id="slideShow">
<img name="image" alt="Slide Show" src="pics/0.jpg" />
</div>
</div>
</body>
</html>
javascript
//javascript code for slideshow
//pictures
var imgs = [ "pics\/0.jpg", "pics\/1.jpg", "pics\/2.jpg", "pics\/3.jpg", "pics\/4.jpg", "pics\/5.jpg" ];
var imgNum = 0;
var imgsLength = imgs.length-1;
var time = 0;
//changing images function
function changeImg(n) {
imgNum += n;
//last position of array
if (imgNum > imgsLength) {
imgNum = 0;
}
//first position of array
if (imgNum < 0) {
imgNum = imgsLength;
}
//console.log(images.tagName);
document.image.src = imgs[imgNum];
return false;
}
//slideshow function
function slideShow() {
var tag = document.getElementById('link').innerHTML;
if(tag == "Stop") {
clearInterval(time); //stoping slideshow
document.getElementById('link').innerHTML = "Start";
document.getElementById('link').style.background = "yellow";
}
else { //all other cases come here
time = setInterval("changeImg(1)", 4000);
document.getElementById('link').innerHTML = "Stop";
document.getElementById('link').style.background = "green";
}
}
window.addEventListener('load', slideShow);
It's not possible to automatically read a directory with in-browser javascript because of security issues. You have two options here:
Make a multiple file input and let the user select the images to display. He could just use "ctrl+a" inside a directory to select everything ... of course this is bad cuz it requires a file select for every slideshow.
or...
Make a server side application that will upload the files or a list with their path. This will do the trick just the way you want, but the application must be installed and running on the machine in order to work. This could be easily achieved with nodejs and I bet you will find a module that will help you.

Trying to parse xml file for javascript quiz

I am trying to create a javascript quiz, that gets the questions from a xml file. At the moment I am only starting out trying to parse my xml file without any success. Can anyone point me to what I am doing wrong?
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="prototype.js"></script>
</head>
<body>
<div class="spmArr">
</div>
<script type="text/javascript">
var quizXML = '<quiz><Sporsmal tekst="bla bla bla"/><alternativer><tekst>bla</tekst><tekst>bli</tekst><tekst correct="yes">ble</tekst></alternativer><Sporsmal tekst="More blah"/><alternativer><tekst>bla bla</tekst><tekst correct="yes">bli bli</tekst><tekst>ble ble</tekst></alternativer></quiz>'
var quizDOM = $.xmlDOM( quizXML );
quizDOM.find('quiz > Sporsmal').each(function() {
var sporsmalTekst = $(this).attr('tekst');
var qDiv = $("<div />")
.addClass("item")
.addClass("sporsmal")
.appendTo($(".spmArr"));
var sTekst = $("<h2/>")
.html(sporsmalTekst)
.appendTo(qDiv);
});
</script>
</body>
</html>
When I try this in my browser the classes and div are not being created. And the page is just blank. Am i doing something wrong when I intialize the xml?
edited to add prototype.js and close function
Looks like you're forgetting to close your .each call. append ); after the statement for sTekst and your call will parse correctly.

Categories