I have created a constructor function and a few objects that are pushed into an array.
From here I need to call a function on these objects in an array which outputs to a basic html front end. I have created the constructor function and have it all mostly working, however I keep getting an error in dev tools stating my this.render() method shown below is not a function.
I can get this working when I try to just console.log the objects in the array (with a loop), but cannot get past this error of not being able to use render() method. Any help would be appreciated. Code below. Note that the end goal is to have the rendered info appended to a div with id of "output". Thank you
function ArtistType(name, genre, albums) {
this.name = name;
this.genre = genre;
this.albums = albums;
this.publishAlbum = function () {
this.albums ;
};
this.render = function () {
const artistName = document.createElement("h2");
artistName.innerText = this.name;
const genre = document.createElement("div");
genre.innerText = this.genre;
const albums = document.createElement("div");
albums.innerText = this.albums;
document.getElementById("output").appendChild(artistName, genre, albums)
};
}
let artists = [];
const artist1 = new ArtistType("Black Sabbath", "metal", 0)
const artist2 = new ArtistType("Huey Lewis and the News", "rock", 0)
const artist3 = new ArtistType("Beastie Boys", "hip hop", 0)
artists.push(artist1, artist2, artist3);
artist1.publishAlbum();
//below some of what I have tried...
//artists.forEach(this.render())
//have also tried for...in loop and others...example:
//for (var i = 0; i < artists.length; i ) {
// this.render();
}
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Name will go here</h1>
<!-- Output the content -->
<div id="output"></div>
<!-- Link the script -->
<script src="scripts.js"></script>
</body>
</html>
CodePudding user response:
You have to refer to a particular object in order to use its function render()
. Something like this:
function ArtistType(name, genre, albums) {
this.name = name;
this.genre = genre;
this.albums = albums;
this.publishAlbum = function () {
this.albums ;
};
this.render = function () {
const artistName = document.createElement("h2");
artistName.innerText = this.name;
const genre = document.createElement("div");
genre.innerText = this.genre;
const albums = document.createElement("div");
albums.innerText = this.albums;
document.getElementById("output").appendChild(artistName, genre, albums)
};
}
let artists = [];
const artist1 = new ArtistType("Black Sabbath", "metal", 0)
const artist2 = new ArtistType("Huey Lewis and the News", "rock", 0)
const artist3 = new ArtistType("Beastie Boys", "hip hop", 0)
artists.push(artist1, artist2, artist3);
artist1.publishAlbum();
//below some of what I have tried...
//artists.forEach(this.render())
//have also tried for...in loop and others...example:
for (var i = 0; i < artists.length; i ) {
artists[i].render();
}
<div id="output"></div>
CodePudding user response:
this
only exists inside the function, you can't just magically use it outside of it
Try this:
artists.forEach(artist => artist.render())
or
for (const artist of artists) {
artist.render()
}
CodePudding user response:
When accessing an array in a for loop, you should use bracked annotation and an index - artists[i].render();
. In my example I actually used forEach
to show you another way of looping. You can reference this documentation to know more about forEach
.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Unless you need to support old browsers, you could consider using classes. Classes help simplify the code a bit as well and can help make it easier to access objects. More in line with other object oriented languages.
Finally, note that I am using append
instead of appendChild
. append
lets you pass in multiple nodes and appends them all. It does not however support IE. appendChild
will only append the first node you pass in.
class Artist {
constructor(name, genre, albums) {
this.name = name;
this.genre = genre;
this.albums = albums;
}
publishAlbum() {
this.albums ;
}
render() {
const artistName = document.createElement("h2");
artistName.innerText = this.name;
const genre = document.createElement("div");
genre.innerText = this.genre;
const albums = document.createElement("div");
albums.innerText = this.albums;
document.getElementById("output").append(artistName, genre, albums)
}
}
let artists = [new Artist("Black Sabbath", "metal", 0),
new Artist("Huey Lewis and the News", "rock", 0),
new Artist("Beastie Boys", "hip hop", 0)
];
artists[0].publishAlbum();
artists.forEach(function(artist) {
artist.render();
});
<div id="output"></div>
CodePudding user response:
You can do:
function ArtistType(name, genre, albums) {
this.name = name
this.genre = genre
this.albums = albums
this.publishAlbum = function (event) {
// Logic to publish album
console.log('event', event.target)
this.albums
}
this.render = function () {
const wrapper = document.createElement('div')
const name = document.createElement('h2')
name.innerHTML = this.name
const genreP = document.createElement('p')
genreP.innerHTML = `Genre: ${this.genre.toUpperCase()}`
const albumsP = document.createElement('p')
albumsP.innerHTML = `Albums: ${this.albums}`
albumsP.addEventListener('click', this.publishAlbum)
const elems = [name, genreP, albumsP]
elems.forEach(el => wrapper.appendChild(el))
document
.getElementById('output')
.appendChild(wrapper)
}
}
const data = [{name: 'Black Sabbath',genre: 'metal',albums: 0,},{name: 'Huey Lewis and the News',genre: 'rock',albums: 0,},{name: 'Beastie Boys',genre: 'hip hop',albums: 0,},]
data.forEach(({ name, genre, albums }) => {
const artist = new ArtistType(name, genre, albums)
artist.render()
})
<div id="output"></div>