I'm trying to make a functioning searchbar in javascript,that when you press enter, will delete all the content of the page while only showing the elements that I'm searching for. The elements I just mentioned are in order list.
You could have 2 lists. One for all of the elements and the other one for filtered ones.
You could use Array.filter to narrow the list down to items that don't meet the search criteria, and then loop over those elements, and set those items style.display to none.
Something like this
(Im not sure how/what the elements of the ordered list are)
//You may have to change this to reflect the actual structure your list
let orderedList = Array.from(document.querySelectorAll('ol>li'))
// get the
let query = document.getElementById('search').value.toLowerCase()
orderedList.filter(element=>{
// get the text in the list and compare it to the query
let elementText = element.innerText.toLowerCase()
let matchesQuery = elementText === query || elementText.startsWith(query) || elementText.contains(query)
//return the ones that don't match
return !matchesQuery
}).forEach(element=>{
//now loop over the ones that dont match
element.style.display = 'none'
})
Related
I'm finally learning better methods for my JS. I'm trying to find a way to go faster than I do so far :
In my code, I have two arrays :
one with unique keys in first position
one with those keys in first position but not unique. There are multiple entries with a certain value I want to filter.
The thing is I don't want to filter everything that is in the second array. I want to select some positions, like item[1]+item[5]+item[6]. What I do works, but I wonder if there isn't a faster way to do it ?
for (let i=0;i<firstArrayOfUniques.length;i++){
const findRef = secondArrayOfMultiple
.filter(item => item[0]==firstArrayOfUniques[i][0]);
// Afterwards, I redo a map and select only the second element,
//then I join the multiple answers
// Is there a way to do all that in the first filter?
const refSliced = findRef.map(x=>x[1]);
const refJoin = refSliced.join(" - ");
canevasSheet.getRange(1+i,1).setValue(refJoin);
}
The script snippet you quote will spend almost all of its running time calling the Range.setValue() method. It gets called separately for every data row. Use Range.setValues() instead, and call it just once, like this:
function moot(firstArrayOfUniques, secondArrayOfMultiple) {
const result = firstArrayOfUniques.map(uniqueRow =>
secondArrayOfMultiple
.filter(row => row[0] === uniqueRow[0])
.map(row => row[1])
.join(' - '));
canevasSheet.getRange(1, 1, result.length, result[0].length).setValues(result);
}
See Apps Script best practices.
I am using Vanilla JS and PHP. I have a series of checkboxes for blog posts. Each post has its own associated checkbox and on each checkbox there is a value which is the equivalent of the postID from the mysql db. I have a foreach checking the checkboxes to see which one is clicked and then it pushes that value onto an empty array.
I also have a 2nd array that is filled with the posts id using a separate data attribute as the elements are not on the same DOM level. The 2nd array values contain a status within a <span> that either say 'Published' or 'Draft'. The span has its own data- attribute identifying the post id. I want to compare ids from both arrays and check the innerHTML of the span belonging to the 2nd array. Right now I have a check in place but it only checks the first value int the 2nd array.
Checkbox foreach
//Store post id from checkbox
let checkBox = document.querySelectorAll('.postCheckBox');
let postIDs = [];
let blogIDs = [];
checkBox.forEach(function (element) {
if (element.checked) {
//Store POST ids
postIDs.push(element.value);
//Store BLOG ids
blogIDs.push(element.dataset.blog);
}
});
and in the dom it looks like (the value is the postID)
<input type="checkbox" class="postCheckBox" value="5" data-blog="1">
My 2nd array with values
let customPostIds = [];
Array.prototype.slice.call(postStatus).forEach(post => {
customPostIds.push(post);
})
console.log(customPostIds)
which when consoled returns
And in each of those elements I do see dataset and the innerHTML just not sure how to use it to compare it to the first array AND extract the innerHTML to do a check.
If you need more info to give feedback let me know so I can add whatever info is needed.
The end result I am hoping to achieve is to have a valid if statement check. Pseudo code:
if((postID.id === customPostIds.id) && customPostIds.innerHTML === 'Draft') {return true;}
The tricky part is that customPostIds needs 2 values extracted from it... 1) The data-post-id and the innerHTML from each item in the array. However, the dataset.postId and the innerHTML from the customPostIds array which I want to extract, do not live on the same HTML element in the DOM.
Does there exist a function in vanilla JavaScript or jQuery that operates similarly to Node.insertBefore(), but for arrays and/or HTMLCollections?
An example could look something like:
var list = document.getElementsByClassName("stuff");
var nodeToMove = list[0];
var otherNode = list[4];
list.insertBefore(nodeToMove, otherNode);
Basically I'm trying to perform insertBefore() without manipulating the actual DOM, as I want the changes to only be applied to the DOM under certain conditions. If those conditions are met, then I would perform insertBefore() on the actual nodes.
To clarify, I'm looking for a function that would insert an element before a target element at a given index in an array, not necessarily at a given index. Examples I've seen using splice() usually insert an element at a given index, which sometimes puts the element before the target element, and sometimes after, depending on where the element to be moved originally was in the array. I'm looking for something that would reliably put the element to be moved before the target element.
HTMLCollection does not have an insertBefore method. jQuery can apply any jQuery methods both to a single element being selected, as well as many.
https://api.jquery.com/insertBefore/
There is no single method to do this in one step, but there doesn't need to be. If you convert the collection to an Array, you can call the Array.prototype.splice() method to achieve the same result.
Here's an example:
let ary = [1,2,3,4,5];
// Swap 2 and 3
// Start at the 3rd item and remove one item (3).
// Store the removed item
let removed = ary.splice(2,1);
// Start at the second item, don't remove anything, insert the removed
// item at that position
ary.splice(1,null,removed[0]);
// Log the result
console.log(ary);
And, with that knowledge, you can create your own more easily callable function:
let ary = [1,2,3,4,5];
function insertBefore(ary, newItem, target){
ary.splice(target,null,newItem);
}
// Insert 999 before the 3rd array item
insertBefore(ary,999,2)
console.log(ary);
You need to get the index you want, then use Array.splice.
Myself I would do something like this :
const myArr = ['Aurore', 'Dimitri', 'Alban', 'Frédéric'];
const insertBeforeThis = 'Alban';
const eltToInsert = 'Laura';
const index = myArr.findIndex(name => name === insertBeforeThis);
myArr.splice(index, 0, eltToInsert);
Please feel free to try it out in your browser's console. Note i used const for my array, as it fixes the type of the variable as an array but allow me to manipulate it.
MDN: Array.prototype.findIndex()
stackoverflow: How to insert an item into an array at a specific index (JavaScript)?
Have a happy coding time!
I have some dynamically created filters on a web app's page where the filter "entry" is at times the combination of a few different inputs and the values for the collection are gathered into an array to send back to the server. If these were all just single inputs then an array of values would be easy to map over to the inputs on the backend, however when one or more is a multiselect with multiple options, a flattened array of values mixing the multiselect's values and the individual input values isn't appropriate.
As an example: if I have two inputs for a given filter on a search control page, one being a multiselect and another being a text input, I would like to gather an array of two elements, the first being an array of selected values and the second as the value entered in the text input. So if in the first multiselect I select "A", "B" and the text input I enter "Joe" and the code below gathers the input values:
Coffeescript:
filters = []
$(#customFilterElements.selector).each ->
filterName = $(#).find('.filter_entry .filter_name:input').val()
filterValues = $(#).find('.filter_entry .filter_value:input').map(->
if $(#).data('multiselect')
$(#).find('option:selected').map(->
$(#).val()
).get()
else
$(#).val()
).get()
filters.push({name: filterName, value: filterValues})
Javascript: (converted from above)
var filters = [];
$(this.customFilterElements.selector).each(function() {
var filterName, filterValues;
filterName = $(this).find('.filter_entry .filter_name:input').val();
filterValues = $(this).find('.filter_entry .filter_value:input').map(function() {
if ($(this).data('multiselect')) {
return $(this).find('option:selected').map(function() {
return $(this).val();
}).get();
} else {
return $(this).val();
}
}).get();
return filters.push({
name: filterName,
value: filterValues
});
});
Current result for filterValues: ["A","B","Joe"]
The above code ends up producing an array ["A","B","Joe"] for filterValues.
I think this may be because the .get() is converting everything to a flattened array. I tried using $.makeArray() instead of .get() and I get the same results but perhaps I missed something.
Desired result for filterValues: [["A","B"],"Joe"]
What I am hoping to produce is [["A","B"],"Joe"] so it is clear that the first element (in this example) is a collection of selected values from a multiselect to the backend.
How can I adjust the above code to get the desired result (for any combination or ordering of multiselects and single inputs together) in a fairly elegant manner?
The code is intended to be applied to any dynamically created filter, so reusable instead of hardcoding to each filter.
Ok, after a full night's rest the answer came to me right away and it seems so obvious now - just need to wrap the multiselect in an array bracket after the .get()! - doh. Sometimes documenting the problem here forces a solution to bubble up or highlight what I was missing.
filters = []
$(#customFilterElements.selector).each ->
filterName = $(#).find('.filter_entry .filter_name:input').val()
filterValues = $(#).find('.filter_entry .filter_value:input').map(->
if $(#).data('multiselect')
[$(#).find('option:selected').map(->
$(#).val()
).get()]
else
$(#).val()
).get()
filters.push({name: filterName, value: filterValues})
I’m 100% certain this code has been working before. Now it strangely doesn’t.
The goal is to create a multiple choice quiz for a flashcard. I create an array to store the card's ids: the first one goes the current card id, then three other random ones. My goal is to make sure they don’t repeat either the first card or themselves.
This is how I do it:
// Array of cards’ ids to use
var randomCardsIds = [];
// Get the active card’s element id, add it to the array
randomCardsIds[0] = this.activeCardId;
// Get the current cards collection
var allCurrentCards = this.carouselEl.items.items;
// Get three random ids of other cards
var i = 0
while (i<3) {
// Get a random card element
var randomCardEl = allCurrentCards[Math.floor(Math.random() * allCurrentCards.length)];
// Get its id
var randomCardElId = randomCardEl.body.down('.card').id;
randomCardElId = randomCardElId.substring(randomCardElId.indexOf('_')+1);
console.log(randomCardElId, randomCardsIds, randomCardsIds.indexOf(randomCardElId));
// Make sure it is not in the array yet, and then add it
if (randomCardsIds.indexOf(randomCardElId) == -1) {
randomCardsIds.push(randomCardElId);
i++;
}
// Otherwise, the loop will have to run again
}
Basically, in a loop, for each item I check whether it already exists in the array or not. If it doesn’t, push it to the array, otherwise, run the loop again. Here is the console logging result:
Well, the first thing: it always shows the final state of the array: as if it is already filled with the results, which is weird. But the most important thing: the script does not recognise a duplicate (e.g. in the first result, 74 is repeated, and in the second to last, 47).
It only returns something different then -1, when it finds a match in the second position (returns 1, obviously). When a match is in a different position in the array, it always returns -1.
What am I doing wrong here?
Are you testing this in IE6? The problem is indexOf doesnot work with IE6.
For alternative you can check Best way to find if an item is in a JavaScript array?
A variation on a shuffling algoruthm seems to be the best bet here.