I'm trying to make movies likeable one time by storing them in an array like this:
let likedMovies = [];
const movieLike = document.getElementById("likeButton");
likedMovies = JSON.parse(localStorage.getItem("likedMovies"));
movieLike.addEventListener("click", () => {
if (likedMovies.indexOf(allMovies[i].name) === -1) {
confirm("Movie liked");
axios.patch(`url`);
likedMovies.push(allMovies[i].name);
localStorage.setItem("likedMovies", JSON.stringify(likedMovies));
return true;
}
confirm("Movie already liked");
return false;
});
it was working this afternoon but now the console display an error log saying this: "script.js:75 Uncaught TypeError: Cannot read properties of null (reading 'indexOf')
at HTMLDivElement." and when I log my likedMovies array, it says that arrays's "null", could you please help me understanding why it doesn't work ?
The problem is that you are reassigning likedMovies with the result of JSON.parse which is null if it's unable to parse it.
let likedMovies = JSON.parse(localStorage.getItem("likedMovies")) || [];
This should solve the error, but also you can do some optimization by storing it as an Object.
let likedMovies = JSON.parse(localStorage.getItem("likedMovies")) || {};
const movieLike = document.getElementById("likeButton");
movieLike.addEventListener("click", () => {
if (likedMovies[allMovies[i].name]) {
confirm("Movie liked");
axios.patch(`url`);
likedMovies[allMovies[i].name] = true;
localStorage.setItem("likedMovies", JSON.stringify(likedMovies));
return true;
}
confirm("Movie already liked");
return false;
});
Now your search will happen not in linear time which is O(n) but in constant O(1). Tiny performance improvement.
Related
I'm having a strange problem with my code. There is an object that comes from an API call where videos are stored and I need to add the number of videos on the website. But sometimes there can be "null" coming from API call and obviously, I don't have to show the length of the null value.
As I wrote this code which works when I try on editors, but when I use it on my project it gives an error Cannot convert undefined or null to object. Can anyone give me an idea or hint of what I'm doing wrong? And sorry if I explained unclearly, this is my very first post here. Thank you!
const object = {
background_video: null,
vimeo_branded: 'video url',
vimeo_unbranded: "video url"
}
const removeFalsyElement = object => {
let sum = 0;
Object.keys(object).forEach(key => {
if (object[key]) {
sum += 1;
}
});
return sum;
};
console.log(removeFalsyElement(object)) // output should be 2.
The Object.keys method expects an object always. if we pass null we would get the above mentioned error
const removeFalsyElement = (object = {}) => {//default value for object in case it is null. Object.keys needs an object always
let sum = 0;
Object.keys(object).forEach(key => {
if (object[key]) {
sum += 1;
}
});
return sum;
};
Good afternoon,
Please, could you help me with an issue below.
I am getting an error "Cannot read properties of null (reading 'split')" when trying to click "cancel" on prompt.
What all I want, to loop canceled when I cancel it in prompt.
ps.: this is a simple array with a name/surname which in future will shows via console.log
function UserList () {
let users = [];
while(true) {
users.push (prompt('Please, enter your name surname?').split(' '));
if (prompt=== null) {
alert('cancel');
}
}
}
let userList = new UserList();
You need to test whether the result of prompt() is null before you try to split it.
You need to break out of the loop when the user cancels, otherwise the function will never return.
Also, since you're using this as a object constructor, users should be a property this.users.
function UserList () {
this.users = [];
while(true) {
let response = prompt('Please, enter your name surname?');
if (response == null) {
alert('cancel');
break;
}
this.users.push (response.split(' '));
}
}
I've been following this tutorial and trying to add a third player to the game. Here is the source code that works for two players. Below is my data structure:
"matchmaking" : {
"32idNK8OndcujN8CFNe3VBTxsXL2" : {
"gameId" : "placeholder"
},
"LnMnOtdLJYbsRuTeUpeHfaAhpX32" : {
"gameId" : "placeholder"
},
"plpISHWWtuNJvhSlFwfik6DOHR53" : {
"gameId" : "placeholder"
}
}
I have a cloud function that is called every time a user joins the matchmaking room. Depending on whichever two users are available, the function generates a unique game room for all three users. I am not well-versed in Javascript so I've been struggling on this for a while.
How can I retrieve and assign the gameId value to three players during a transaction?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var database = admin.database();
exports.matchmaker = functions.database.ref('matchmaking/{playerId}')
.onCreate((snap, context) => {
var gameId = generateGameId();
database.ref('matchmaking').once('value').then(snapshot => {
var secondPlayer = null;
var thirdPlayer = null;
// add two players into the queue
snapshot.forEach(child => { // check that its not the playerId who just joined
var playerId = child.key
var gameId = child.val().gameId
if (gameId === "placeholder" && playerId !== context.params.playerId) {
secondPlayer = child;
}
});
snapshot.forEach(child => { // check that its not the playerId who just joined
var playerId = child.key
var gameId = child.val().gameId
if (gameId === "placeholder" && playerId !== secondPlayer.key && playerId !== context.params.playerId) {
thirdPlayer = child;
}
});
if (secondPlayer === null || thirdPlayer === null) return null; // one room needs three players
database.ref("matchmaking").transaction(function (matchmaking) {
console.log(matchmaking)
// ================================================
// PROBLEM STARTS HERE
// ================================================
console.log("playerId gameId:",context.params.playerId.gameId) // returns undefined
// If any of the players gets into another game during the transaction, abort the operation
if (matchmaking === null ||
context.params.playerId.gameId !== "placeholder" ||
matchmaking[secondPlayer.key].gameId !== "placeholder" ||
matchmaking[thirdPlayer.key].gameId !== "placeholder") return matchmaking;
// matchmaking.forEach(player => { // check that its not the playerId that just joined
// var playerId = player.key
// var gameId = player.val().gameId
// if (gameId !== "placeholder") {
// player["gameId"] = gameId;
// }
// });
context.params.playerId.gameId = gameId; // assign game id to player
matchmaking[secondPlayer.key].gameId = gameId;
matchmaking[thirdPlayer.key].gameId = gameId;
return matchmaking;
}).then(result => {
if (result.snapshot.child(context.params.playerId).val() !== gameId) return;
// ENDS HERE
// ================================================
var game = {
gameInfo: {
gameId: gameId,
playersIds: [context.params.playerId, secondPlayer.key, thirdPlayer.key]
},
turn: context.params.playerId
}
database.ref("games/" + gameId).set(game).then(snapshot => {
console.log("Game created successfully!")
return null;
}).catch(error => {
console.log(error);
});
return null;
}).catch(error => {
console.log(error);
});
return null;
}).catch(error => {
console.log(error);
});
});
function generateGameId() {
var possibleChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var gameId = "";
for (var j = 0; j < 20; j++) gameId += possibleChars.charAt(Math.floor(Math.random() * possibleChars.length));
return gameId;
}
I've been getting errors such as matchmaking.forEach is not a function or Cannot read property 'params' of undefined or Cannot read property 'val' of undefined
console.log(matchmaking) shows the following:
{ '32idNK8OndcujN8CFNe3VBTxsXL2': { gameId: 'placeholder' },
LnMnOtdLJYbsRuTeUpeHfaAhpX32: { gameId: 'placeholder' },
plpISHWWtuNJvhSlFwfik6DOHR53: { gameId: 'placeholder' } }
I would really appreciate any help.
Update:
Solution:
database.ref("matchmaking").transaction(function (matchmakingSnapshot) {
if (matchmakingSnapshot) {
matchmakingSnapshot[context.params.playerId].gameId = gameId; // assign game id to player
matchmakingSnapshot[secondPlayer.key].gameId = gameId;
matchmakingSnapshot[thirdPlayer.key].gameId = gameId;
return matchmakingSnapshot;
} else if ( // If any of the players gets into another game during the transaction, abort the operation
matchmakingSnapshot === null ||
context.params.playerId.gameId !== "placeholder" ||
matchmakingSnapshot[secondPlayer.key].gameId !== "placeholder" ||
matchmakingSnapshot[thirdPlayer.key].gameId !== "placeholder") {
return matchmakingSnapshot;
}
}).then(result => {
The problem was that when I was trying to update the gameId, the transaction returns a null data. I had to make sure matchmaingSnapshot is not null before accessing the context params playerId. I'm not sure why calling matchmakingSnapshot.val() returns function undefined, but yeah that's it!
You should not currently be getting the error `matchmaking.forEach is not a function`.
The ".forEach" function can work on an array or on a DataSnapshot (where it iterates over the children, providing a DataSnapshot of each in turn).
But if you have an Object, ".forEach" will give you the error message you describe. The code as it stands appears to be having "matchmaking" as a DataSnapshot, so it should be ok for ".forEach" at the moment.
Explanation for error: Cannot read property 'params' of undefined
I think you have accidentally inserted a variable name, instead of telling javascript to use the variable name's value
if (matchmaking === null ||
matchmaking.context.params.playerId.gameId !== "placeholder" ||
matchmaking.secondPlayer.key.gameId !== "placeholder" ||
matchmaking.thirdPlayer.key.gameId !== "placeholder"
) return matchmaking;
I think you don't mean matchmaking.secondPlayer.key.gameId. I think you mean matchmaking[secondPlayer].key.gameId, so that if secondPlayer is "ABC123", you would be referring to matchmaking.ABC123.key.gameId
Same for thirdPlayer.
Explanation for error: Cannot read property 'params' of undefined
Did you mean just context.params.playerId.gameId, not matchmaking.context.params.playerId.gameId? You might have added the "matchmaking" by mistake?
Exploring the error: TypeError: Cannot read property 'gameId' of undefined
If you get the above error with this:
matchmaking[context.params.playerId].key.gameId`
First, check that you need the step ".key". Looking at your object, it looks to me that ".gameId" comes straight after the matchmaking[playerId], with no ".key" needed. If you are sure you need the ".key", then I would debug as follows. Immediately before that statement, insert the following console logs.
console.log("playerId:",context.params.playerId)
console.log("matchmaking[context.params.playerId]:",
matchmaking[context.params.playerId])
Then check that the playerId is something sensible. If it isn't, console.log the entire context with
console.log("context:",JSON.stringify(context)) // This avoids getting something useless logged like `[Object object]`.
If the playerId is correct, you will then see if matchmaking has an entry for that player. This approach to debugging will eventually expose where the problem lies.
I think the final problem is the confusion between 'matchmaking' being a DataSnapshot versus a straightforward, writeable Object
This was hard for me to understand because matchmaking is currently a DataSnapshot, which is a somewhat confusing type of thing. It seems to get console.logged as though it is an object, but it isn't writeable.
I suggest we extract an actual object, as follows:
database.ref("matchmaking").transaction(function (matchmaking) {
let matchmakingObject = matchmaking.val();
// ... remainder of code as before, and then:
matchmakingObject[context.params.playerId.gameId] = gameId; // assign game id to player
matchmakingObject[secondPlayer.key].gameId = gameId;
matchmakingObject[thirdPlayer.key].gameId = gameId;
return matchmakingObject;
I hope this fixes things!
My way to avoid such problems is to ALWAYS call snapshots xxxxSnapshot. That way I never forget that while it may console.log as though it was an object, in reality it is some sort of mystery thing.
For example, if I was writing this code, I would call things as follows:
database.ref("matchmaking")
.transaction(function (matchmakingSnapshot) {
let matchmakingObject = matchmakingSnapshot.val();
// ... remainder of code as before, and then:
matchmakingObject[context.params.playerId.gameId] = gameId; // assign game id to player
matchmakingObject[secondPlayer.key].gameId = gameId;
matchmakingObject[thirdPlayer.key].gameId = gameId;
return matchmakingObject;
It's a bit ugly but less painful than trying to debug a name that has two powerfully different meanings that are easily conflated.
I'm trying to make an app that will help me with my workouts and help me constantly lift more so that I can get stronger. I keep getting the error "Cannot set inner property of null" on the very bottom when I try to output the variables to the HTML. It's the code under the last section of comments that I am getting the error. Can some give me some guidance on how to fix this?
//Get the variables from the user. This will be the previous exercise or the exercise that the user has performed
const userSet = document.getElementById("set-user-1");
const userReps = document.getElementById("reps-user-1");
const userWeight = document.getElementById("weight-user-1");
var futureSet;
var futureReps;
var futureWeight;
//Define the functions that need to be done between the previous exercise and the next exercise
function getNewSet(previousSet) {
return previousSet;
}
function getNewRep(previousReps){
if(previousReps < 12) {
return previousReps + 2;
} else {
previousReps = 6;
return previousReps;
}
}
function getNewWeight(previousReps, previousWeight) {
if(previousReps < 12){
return previousWeight;
} else {
previousWeight = previousWeight + 10;
return previousWeight;
}
}
//Make a function that runs all the functions with the user input
function getNewWorkout() {
futureSet = getNewSet(parseInt(userSet));
futureReps = getNewRep(parseInt(userReps));
futureWeight = getNewWeight(parseInt(userReps, userWeight));
return futureSet;
return futureReps;
return futureWeight;
}
//Output will go to the future exercise dividers
document.getElementById("future-sets").innerHTML = futureSet;
document.getElementById("future-reps").innerHTML = futureReps;
document.getElementById("future-weight").innerHTML = futureWeight;
The error is in the last two lines of this function. A function can only return one value, it might be worth putting all the values in an array
and then returning it.
//Make a function that runs all the functions with the user input
function getNewWorkout() {
futureSet = getNewSet(parseInt(userSet));
futureReps = getNewRep(parseInt(userReps));
futureWeight = getNewWeight(parseInt(userReps, userWeight));
return futureSet;
//error here
return futureReps;
return futureWeight;
}
So you can update your code as follows to return object,
function getNewWorkout() {
const futureSet = getNewSet(parseInt(userSet));
const futureReps = getNewRep(parseInt(userReps));
const futureWeight = getNewWeight(parseInt(userReps, userWeight));
return {futureSet, futureReps, futureWeight};
}
Which you can access through object.
This kind of error comes when you load the script before DOM is ready. You can try to load the script at the end of the HTML, usually in footer. This should fix your error.
Also, please call the function 'getNewWorkout()' in your script to get expected output.
I get the error in the title even though I have tried all the solutions. About the value of null;
If my code is ;
Output: TypeError: Cannot read property of null
case '!facebook':
face.Profile(facebook, function(result) {
let like = result.profiles.like;
let comments = result.profiles.comments;
if(like === null || comments === null){
//code.
}
else {
//code.
}
});
break;
You have to verify that each child of your object exists before you reference the next level. In your case, that means testing the existence of result and then result.profiles before trying to use any of the object values in profiles. See the code below.
Without seeing the rest of your case statement or how you're setting the value of face, it's hard to tell if you're going to run into other issues.
case '!facebook':
face.Profile(facebook, function(result) {
// Set default values
let like = null;
let comments = null;
// Set values only if there's a result containing profiles
if (result && result.profiles) {
like = result.profiles.like;
comments = result.profiles.comments;
}
if (like === null || comments === null){
//code
} else {
//code
}
});
break;