Finding if a string already exists inside an array of strings -javascript - javascript

I have an array called blog.likes and i want to check to see if the id of the current logged in user(req.user._id) already exists inside the array of likes. If it does then delete the id from the array if it doesn't then add the user id inside the array. With the code i have now if i press the like button once it likes the post if i press it again it removes the like but if a post has a like and i log in with a different user and press the like button many times it starts to delete all the likes not only the likes that are made by one user.
if (blog.likes.indexOf(req.user._id) > -1 ){
blog.likes.shift(req.user._id);
blog.save();
} else {
blog.likes.push(req.user);
blog.save();
}

The shift function will only remove the first element from the array, paying no heed to the logged in user id. Use splice function to achieve the desired result.
Change your code to this:
let userIndex = blog.likes.indexOf(req.user._id);
if (userIndex > -1) {
blog.likes.splice(userIndex, 1);
} else {
blog.likes.push(req.user);
}
blog.save();

As I mentioned in the comments .shift() is not the correct method to use. Give this a try:
var f = blog.likes.indexOf(req.user._id);
if (f > -1 ) {
blog.likes.splice(f, 1);
} else {
blog.likes.push(req.user);
}
blog.save();

Related

How to get exact match of what a user types in an input filed to what's in an array

When a user types in a number in the search field, an image with that number populates an image wheel. When a user types in 49, the image with the number 49 should appear. Instead, the current code gets me all images with the number 4 and all images with the number 9 (like 14, 19, 244, 596, etc) instead of returning one image #49. filter() did not work, includes() did not work, indexOf() did not work. How to get the one image that corresponds to the input number?
function searchInspired() {
$(".treatment").each(function() {
$(this).removeClass('searched');
});
var searchNum = document.getElementById('searchField').value; //user input
//treatments is an array of images declared globally
for (var i=0; i<treatments.length; i++){
if (treatments[i].number.toString().indexOf(searchNum) !== -1){
console.log(treatments[i]);
treatments[i].$elem.addClass('searched');
}
}
$('.treatment').each(function(index, el){
if(!$(el).hasClass('searched')){
$(el).hide();
}
else{
$(el).show();
}
});
}
The class resetting code might not be working, causing your issue with the "4" of "49" always being shown. I would try making your reset function look more like your show/hide function.
$('.treatment').each(function(index, el){
$(el).removeClass('searched');
})
Your matching checks to see if the character they typed appears anywhere in the image number '149'.indexOf('49') passes your check. There are a lot ways you could force this to match exactly, I recommend leaving both as a number and just doing searchNum === treatments[i].number.
Possible example:
var searchNum = Number(document.getElementById('searchField').value);
if(isNaN(searchNum)) {
return; //bad input, don't show any images
}
Then your check for the matching image can simply be:
if (treatments[i].number === searchNum) {
...add the class...
}
You can filter treatments array and then map to
treatments.filter(function(treatment){
return treatment.number.toString() === searchNum.toString()
}).each(function(treatment){
treatment.$elem.addClass('searched');
});
$(".treatment").not(".searched").show();
$(".treatment.searched").hide();
I was able to solve this. My original code worked when adding a break so it would no longer loop and give me exact match
for (var i=0; i<treatments.length; i++){
if (treatments[i].number.toString().indexOf(searchNum) !== -1){
treatments[i].$elem.addClass('searched');
break;
}
}

How to pass a function only after an entire array has been read and not for each element?

I'm trying to run a function when reading an array, but instead of running the function to each element, which I'm currently using forEach for, I want to make the script to read the entire array and then pass a function.
What I'm trying to say is this:
data.forEach(movie => {
// Log each movie's title
//console.log(movie.title);
// Check if the userWord matches
if (movie.title.toUpperCase().includes(userWord.toUpperCase())) {
alert("YES");
} else {
alert("NO").
}
});
Let's say my array is: array = ["Aa", "Ba", "Ca", "Da"];
If the user enters: a, then the script would alert("YES") four times, and I want to make it alert just once, at the end of the iteration.
For the same example, if the users enters: B, then the script would first alert("NO") once, then alert("YES"), then alert("YES") 2 times, and I want to make it just alert("YES")once, in the end.
Finally, if the users enters: Ferrari, then the script would alert("NO") four times, and I just want it to alert("NO") at the end.
I tried to make it very clear here, that's why the three "cases" of what is happening.
In the end, I want to know if there is a method that is kinda the opposite of the forEach or the common for. Something that just executes the function after reading the entire array.
Change the alert to a bool variable
Remove else (it would only overwrite any match)
if bool statement outside the loop to perform actions
if you want a list of the results, you should store the names in an array and outside of the loop - print.
see below:
Non-loop method:
data = ["test","hello", "hello1"];
search = "lo";
const matches = data.filter(movie => movie.includes(search));
alert(matches) //array of only matches - only has hello and hello 1
I don't know if there are performance gains against a loop... I suppose you could do a side by side comparison on a large dataset
Loop method:
var matches = "";
data.forEach(movie => {
// Check if the userWord matches
if (movie.title.toUpperCase().includes(userWord.toUpperCase())) {
matches += movie.title + "<br> ";
}
});
if (matches.length > 0)
{
document.getElementById("results").innerHTML = matches;
} else {
alert("No match found");
}
You'll see more customization on the first loop, but I think filtering data first is the way to go.
I think closest what you can get is some. Here is example
let data = ["test","hello", "hello1"];
let userWord = "el";
let res = data.some(movie => movie.toUpperCase().includes(userWord.toUpperCase()));
console.log(res) // prints true- means there was at least one "match", so you can alert
You could use the filter array function to filter array elements that match your criteria and then finally alert only if a match is found. Using this method you could get all the elements that have matched to your userWord. That is, the match array will contain all the possible matches.
var data = ['Aa', 'Bb', 'Cc', 'Dd'];
var flag = false;
var userWord = 'F'
var match = data.filter(movie => movie.indexOf(userWord) !== -1);
if(match.length)
console.log('YES');
else
console.log('NO');
If I understand the question correctly, I believe you want to execute something if a predicate matches at least one of the items in the array (correct me if I'm wrong). For that you can use the some method like so:
if (movies.some((movie) => movie.toUpperCase().includes(userWord.toUpperCase()))) {
alert('YES');
} else {
alert('NO');
}

designate an errorpage.html for a JS document.getElementById('link_id').value + '.html'; if value not found in directory?

Here is a function for a popup search function, which, when a word is typed, and enter is pressed (the handleKeyPress(e) function, it automatically goes to say, dogs.html (its a kids language learning app). However say they type 'dogg' and not 'dog', Iw ould like it to go to a designated error page. I cannot code at all and have only manipulated other people's scripts. for example, the directory
would have a list of animals.html, i.e. dog.html, cat.html, etc. but if a word is typed that is not in this directory
(there should be a search function to see if *.html is there or not, then go to error page if its not there. But I can't do this. I have no training. Can anyone help me with this? I hope I don't get thrown off this forum again, you really shouldn't be so harsh on idiots...!)
i.e. what I need is : if .value+'.html' not in dir;
goto errorpage.html
Here's "my" code to load whatever word's page that's typed in:
function goTo()
{
location.href = document.getElementById('link_id').value + '.html';
/*window.location.replace("spellcheck.html");*/
}
function handleKeyPress(e){
var key=e.keyCode || e.which;
if (key==13){
goTo();
/*window.location.replace("spellcheck.html"); */
}
}
You would probably have to use an XmlHttpRequest to check if the file exists in the location specified or not and redirect to the error page if the file doesn't exist. But this raises it's own set of problems.
Or, you could create a service on the server that could tell you the same. Either way it's not super easy.
As mentioned earlier, you can create an array that can hold all of the values for the pages you know to exist in your site.
(there's a decent amount of commented text in the code snippet for further details)
JavaScript arrays: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
JavaScript .indexOf() (in relation to arrays): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
A JavaScript array is a series of data that is common separated inside of square brackets. Each element is automatically assigned an index value so that developers can quickly reference specific pieces. However, it's important to know that arrays start their index number at 0...
So, in this example:
const arrayName = ['element1', 'element2', 'page3', 'dog']
'element1' is at index 0 inside arrayName
'element2' is at index 1 inside arrayName
'page3' is at index 2 inside arrayName
'dog' is at index 3 inside arrayName
You can use JavaScript array's .indexOf() to find these array index values. If an element does not exist within an array then .indexOf() will return -1 (negative one).
arrayName.indexOf( 'dog' ) === 3
// get the input element that's getting the text
const linkID = document.getElementById('link_id');
// get the search button
const linkBtn = document.getElementById('link_btn');
// listen for when the keyup event (so when the user is
// typing, this will trigger when a key is released)
linkID.addEventListener('keyup', (e)=>{
// get the keyCode to test for [ENTER]/13
let key = e.keyCode || e.which;
// get the textBox element
let target = e.target || e.srcElement;
// test if the [ENTER] key was hit
if( key === 13 ){
// if [ENTER] test the value
processPage( target.value );
}
});
// Listen to the click event on the search button to
// kick off the process workflow...
linkBtn.addEventListener('click', ()=>{
processPage( linkID.value );
});
// Broke this out so that the processing of the text
// field can be done by [ENTER] or by clicking a
// search button
function processPage( val ){
// checkPage will return true/false if the text matches
// a page in the array list
if( checkPage( val ) ){
// if the page does exist, then kick off the redirect
goTo( val );
}else{
// display an error message
alert( 'Sorry, the page you are looking for does not exist' );
// reset the value of #link_id
linkID.value = '';
}
}
// This function checks if the text value submitted matches
// one of the static pages saved to the array
function checkPage( val ){
// pages[] is an array that holds all the pages you know
// to exist
const pages = ['dog', 'cat', 'bunny'];
// .indexOf() will return the array position of a search
// query (in this case the value of val)
// Arrays start at 0 so if the user searches "dog" the
// .indexOf() will provide the answer 0.
// If an element does not exist, .indexOf() returns -1
// By assigning this as a condition:
// "is the index of val from the array pages[] greater
// than or equal to 0?"
// we create a condition that will return true/false
return ( pages.indexOf( val ) >= 0 );
}
function goTo( val ){
console.log( val + '.html' );
// location.href = val + '.html';
}
<input type="text" id="link_id" /><button id="link_btn">search</button>

Trouble showing alert after iterating through an array

I have an input field where the user inputs their zip code which I then attempt to match to a zip code within an array. While the following works, I need it to actually show an alert dialog once saying that zip code wasn't found, however, it current pops up a lot even if the zip code is in the list.
Here's my snippet:
_zipcodeBtn.onclick = function(){
var userZip = _zipcode.value;
for (var i = 0; i < zipcode_list.length; i++) {
if (zipcode_list[i] === userZip) {
console.log('works');
break;
} else {
alert("repeating");
}
}
};
I want it to check if their zip is available without it also repeating the else statement multiple times. Whats the best way to prevent this?
There's an easier way to find an item in an array, by referencing the array's indexOf() method (docs).
if (zipcode_list.indexOf(userZip) != -1) {
//found - do something
} else
alert('Zip not found!');
As Angel Politis shows, you can also use includes() if you literally just want to know whether an item is in an array, not its actual position within it.
Sidenote: it's important to check against -1 when using indexOf() because it returns the index at which the search is found - or -1 if it's not. If the search is found at the first key, this is 0, and 0 is a falsy value, which can catch people out sometimes when they do things like this:
var arr = [1, 2, 3];
if (arr.indexOf(1))
alert('success');
else
alert('failed');
You'd think the success alert would fire here, but actually it'll be the failure alert, because indexOf() in this case returns 0, and 0 is a falsy value when it's interrogated in a condition.
There's no need to use a loop here. You can just say:
if (!zipcode_list.includes(userZip)) alert("Doesn't work!");
If you must use a loop, then just set a flag by default to false and then, if the zip is found set it to true. Then you can check it outside the loop:
/* Create a flag and set it by default to false. */
var found = false;
/* Loop */
for (var i = 0, l = zipcode_list.length; i < l; i++) {
if (zipcode_list[i] === userZip) {
/* Set the flag to true and stop the loop. */
found = true;
break;
}
}
/* Check whether the zip was found in the array. */
if (found) console.log("Works!");
else alert("Doesn't work!");

Check if item already exists in json array by matching ID

So I've this shopping cart, as JSON.
[{"tuote":{"id":"2","name":"Rengas 2","count":16,"price":"120.00"}},{"tuote":{"id":"1","name":"Rengas 6","count":"4","price":"25.00"}},{"tuote":{"id":"4","name":"Rengas 4","count":"4","price":"85.00"}}]
Formatted here.
So, I want to prevent from having the same value in there twice, and match them by their ids.
This is my current solution (buggy as a cockroach, doesn't really do the job), as the only time it works is when the matching value is first in the JSON string.
for (var i = 0; i < ostoskori.length; i++) {
if (ostoskori[i].tuote.id == tuoteID) {
addToExisting(tuoteID, tuoteMaara); //this doesn't matter, it works.
break //the loop should stop if addToExisting() runs
}
if (ostoskori[i].tuote.id != tuoteID) {
addNew(tuoteID, tuoteNimi, tuoteMaara, tuoteHinta); //this doesn't matter, it works.
//break
//adding break here will stop the loop,
//which prevents the addToExisting() function running
}
}
ostoskori is the json if you're wondering. As you can probably see, for each item the JSON has inside it, the more times addNew() will run.
So basically, if the JSON has a value with the same id as tuoteID, addToExisting() should run. If the JSON doesn't have a value same as tuoteID, run addNew().
But how?
You could use some to check if the id already exists. The beauty of some is:
If such an element is found, some immediately returns true.
If you're catering for older browsers there's a polyfill at the bottom of that page.
function hasId(data, id) {
return data.some(function (el) {
return el.tuote.id === id;
});
}
hasId(data, '4'); // true
hasId(data, '14'); // false
So:
if (hasId(data, '4')) {
addToExisting();
} else {
addNew();
}
Fiddle

Categories

Resources