Home > OS >  Arrays in a class
Arrays in a class

Time:12-04

I'm trying to make a media register that allows the user to submit a book or a movie which gets stored in an array. This is what I have so far:

let titleInput = document.getElementById("title");
let authorInput = document.getElementById("author");
let pagesInput = document.getElementById("pages");
let title2Input = document.getElementById("title2");
let directorInput = document.getElementById("director");
let runTimeInput = document.getElementById("runTime");

let displayBox = document.getElementById("display");
let displayBox2 = document.getElementById("display2");

class Media {
  constructor(title) {
    this.title = [];
  }
}

class Book extends Media {
  constructor(title, author, pages) {
    super(title);
    this.author = [];
    this.pages = [];
  }
  insert() {
    title.push(titleInput.value);
    author.push(authorInput.value);
    pages.push(pagesInput.value);

    clearAndShow();
  }
  clearAndShow() {
    titleInput.value = "";
    authorInput.value = "";
    pagesInput.value = "";

    displayBox.innerHTML = "";
    displayBox.innerHTML  = "Title: "   title.join(", ")   "<br/>";
    displayBox.innerHTML  = "Author: "   author.join(", ")   "<br/>";
    displayBox.innerHTML  = "Pages: "   pages.join(", ")   "<br/>";
  }
}

class Movie extends Media {
  constructor(title, director, runTime) {
    super(title);
    this.director = [];
    this.runTime = [];
  }
  insert2() {
    title2.push(title2Input.value);
    director.push(directorInput.value);
    runTime.push(runTimeInput.value);
    clearAndShow2();
  }
  clearAndShow2() {
    title2Input.value = "";
    directorInput.value = "";
    runTimeInput.value = "";

    displayBox2.innerHTML = "";
    displayBox2.innerHTML  = "Title: "   title2.join(", ")   "<br/>";
    displayBox2.innerHTML  = "Director: "   director.join(", ")   "<br/>";
    displayBox2.innerHTML  = "Run Time: "   runTime.join(", ");
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div class="container">
    <div class="tab">
      <button class="tablinks" onclick="openMedia(event, 'Book')">Book</button>
      <button class="tablinks" onclick="openMedia(event, 'Movie')">Movie</button>
    </div>
    <div id="Book" class="tabcontent">
      <form id="tabcontent" name="myForm" class="bookContainer" onsubmit="return(validate());">
        <label for="Title">Title:</label>
        <input id="title" type="text" placeholder="Book title">
        <small class="error"></small>
        <br>
        <label for="Author">Author:</label>
        <input id="author" type="text" placeholder="Author's name">
        <small class="error"></small>
        <br>
        <label for="Pages">Pages:</label>
        <input id="pages" type="text" placeholder="Amount of Pages">
        <small class="error"></small>
        <br>
        <button onclick="insert()" id="submit-btn" type="submit">Submit</button>
      </form>
      <div id="display">
        <h3> </h3>
      </div>
    </div>
    <div id="Movie" class="tabcontent">
      <form name="form2" class="movieContainer" onsubmit="return(validate());">
        <label id="" for="Title">Title:</label>
        <input id="title2" type="text" placeholder="Movie title">
        <small class="error"></small>
        <br>
        <label for="Director">Director:</label>
        <input id="director" type="text" placeholder="Director's name">
        <small class="error"></small>
        <br>
        <label for="runTime">Runtime:</label>
        <input id="runTime" type="text" placeholder="Runtime of movie">
        <small class="error"></small>
        <br>
        <button onclick="insert2()" id="submit-btn" type="submit">Submit</button>
      </form>
      <div id="display2">
        <h3></h3>
      </div>
    </div>
  </div>

  <script src="main.js"></script>
</body>

</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

I assumed this was the correct way to do this but I end up getting scope errors I believe. Please take a look at the code pen here: https://codepen.io/nstersleep/pen/GRMRzpo?editors=0011

My question is, how would I make the Arrays that hold all the user values work in a class? This is the first time I've done something like this!

CodePudding user response:

As I've commented, the question is incomplete, but the main issue is you're missing this. when referring to properties and methods in the class. JavaScript doesn't have implied this like Java and C# do, it must always be explicit. So for instance, in Book's insert, you need

this.title.push(titleInput.value);
^^^^^

Without it, you're trying to use an in-scope variable (title) that doesn't exist.

That's also true for method calls like clearAndShow.

But some other things jump out as well:

  • You have constructor parameters you're not using for anything. Just remove them.

  • I wouldn't tie the classes to the input elements by having the classes close over the input element variables. Instead, pass the input elements to use into the class constructor.

  • Parallel arrays like your title, author, and pages are fragile, it's too easy to modify one of them and not the others, making things mismatched. Instead, do a single array of objects with properties for the title, author, and pages.

  • Book and Movie are singular, but you're using them to hold multiple books and movies (plural). If you wanted to do that, it would make more sense to use either the plural (Books, Movies) or some name indicating they're a container (BookStore, MovieStore).

  • There isn't any reason Movie's insert and clearAndShow. methods need to have different names from Book's.

  • Book and Movie don't really serve much of a purpose. After all, they're really just arrays. Instead, I'd have a Book class that represents a single book (with title, author, and pages properties) and a Movie class that represents a movie (with title, directory, and runtime properties). (They could inherit from a Media class that has title if you like.) Then just keep an array of Book instances and an array of Movie instances.

Here's a quick sketch of that last point:

class Media { // If you want it, it doesn't add much value with just the one property
    constructor(title) {
        this.title = title;
    }
}

class Book extends Media {
    constructor(title, author, pages) {
        super(title);
        this.author = author;
        this.pages = pages;
    }
}

class Movie extends Media {
    constructor(title, director, runTime) {
        super(title);
        this.director = director;
        this.runTime = runTime;
    }
}

const books = [];
const movies = [];

// Adding a book:
books.push(new Book(titleInput.value, authorInput.value, pagesInput.value));

// Adding a movie:
movies.push(new Movie(titleInput.value, directorInput.value, runTimeInput.value));

CodePudding user response:

On submit, You are trying to call insert function which is out of scope because insert is defined within Book class and not in global scope.

<button onclick="insert()" id="submit-btn" type="submit">Submit</button> 

Add a caller function which you can call from html. This caller function will build the object of the book class then call insert() of Book object.

a sample could be a below -

function submitBook() {
    var book =  new Book(titleInput);
    book.insert();
    book.clearAndShow();
  }

then call it from HTML as below

<button onclick="submitBook()" id="submit-btn" type="submit">Submit</button> 

Another point is - please use this keyword to assign/read values from the variables in your functions as mentioned in first answer. for example -

this.title.push(titleInput.value);
  • Related