grizzly_beer grizzly_beer - 1 month ago 6
Javascript Question

Javascript, table and array. tricky issue

I'm making a bookshop website (for a little college javascript project) So far all my book info is in arrays in a .js file which looks like this..

var headings = new Array(4);
headings [0] = "title"
headings [1] = "author"
headings [2] = "cat"
headings [3] = "bookid"
headings [4] = "cost"

var bookid = new Array(6);
var title = new Array(6);
var cat = new Array(6);
var author = new Array(6);
var cost = new Array(6);
var desc = new Array(6);

bookid [0] = "0001"
title [0] = "For whom the tell bowls";
cat[0] = "fiction";
author[0] = "John Doe";
cost[0] = "€12.99";
desc[0] = "This book is frickin' amazing blah blah blah"


and so on... there are 7 books...

Now I want to generate a table when I click on a thumbnail pic which has the author, title, cost etc. in one column and the actual corresponding details in the other column, Heres the code

for(var j = 0; j < 5; j++) {
row = document.createElement("tr");

// Each with 2 cells
for(var i = 0; i < 2; i++) {

var cell = document.createElement("td");

var temp = headings[j];
var temp2 = (temp + '[' + filename + ']');
if (i==1)
{var text = document.createTextNode(temp2);
}
else
{var text = document.createTextNode(temp);}


btw "filename" is passed to this function and it is the #of the book, eg, 0, 1, 2 and so on...
Now, what displays on the page is sorta correct.. for book 0 I get..

title title[0]
author author[0]
cat cat[0]
bookid bookid[0]
cost cost[0]


and for book 1 I get

title title[1]
author author[1]
cat cat[1]
bookid bookid[1]
cost cost[1]


and so on, but details are not being interpreted as actual variables in an array. I'm guessing the solution has something to do with "innerHTML" or maybe casting my variables in some way..

If someone knows the solution to this it would be greatly appreciated!.. I'm planning to get this site finished today and move onto to something else more important (as this project is not worth many marks) But leaving this flaw in there would bug me!

Answer

The way you're tackling this problem right now is (trying to) access a variable by its name, e.g. you want to use "title" to find the variable named title. Do not do this. You'll either end up polluting the global scope and relying on window to access those variables, or you'll fall in the hand of the eval devil.

Here's a better idea: make objects to store your books. A book would then look like:

var book = {
    title: "Foo",
    author: "Bar",
    cat: "Baz",
    bookid: 123456,
    cost: "One hundred billion dollars"
};

Even better would be to define a type of books:

function Book(title, author, cat, bookid, cost) {
    this.title = title;
    this.author = author;
    this.cat = cat;
    this.bookid = bookid;
    this.cost = cost;
}
var book = new Book("Foo", "Bar", "Baz", 123456, "One hundred billion dollars");

You could store these books into a single book array:

var books = [book1, book2, book3, ...];

and suddenly, it becomes easy to make a table!

// Create or get a table
var table = document.createElement("table");

// Loop over the books array
for (var i=0, l=books.length; i < l; ++i) {
    // Get the current book
    var book = books[i];

    // Create a table row
    var row = document.createElement("tr");

    // Loop over the *properties* of the book
    for (var propertyName in book) {
        // Skip inherited properties
        if(!book.hasOwnProperty(propertyName)) continue;

        // Get the *property value*
        var property = book[propertyName];

        // Create a table cell and append to the row
        var textNode = document.createTextNode(property);
        var cell = document.createElement("td");
        cell.appendChild(textNode);
        row.appendChild(cell);
    }
    // Append the row to the table
    table.appendChild(row);
}

You could even create the table headings using one book element:

// Some book to loop over its property names
var someBook = books[0];

var row = document.createElement("tr");
// Loop over the book properties
for(var propertyName in someBook) {
    // Now placing the *property name* in a text node
    var textNode = document.createTextNode(propertyName);
    var header = document.createElement("th");
    cell.appendChild(textNode);
    row.appendChild(header);
}
table.appendChild(row);

Update: Better control over the headings

As Dennis suggested, you probably want more control over the headings. You don't want to display "cat" as the heading for the book's category, you want something more readable. Also, you probably don't want to display all properties stored on a book object. In this case, you could store the headings to display in another object and add some more information about those headings:

var headings = {
    title: {
        text: "Book title"
    },
    author: {
        text: "Author"
    },
    cat: {
        text: "Category"
    },
    bookid: {
        text: "ID"
    },
    cost: {
        text: "Price"
    }
};

In your data loop, you would then iterate over the properties of headings instead of book.

// Loop over the properties to display
for (var propertyName in headings) {
    // Get the property value
    var property = book[propertyName];

    // [snipped]
}

In your headings loop, you would use headings[propertyName].text as display name instead of just propertyName. You won't need a book instance any longer, so the someBook variable can be removed.

// Loop over the book properties
for(var propertyName in headings) {
    var headingName = headings[propertyName].text;
    var textNode = document.createTextNode(headingName);

    // [snipped]
}