Does anyone know what I'm doing wrong with the append?
function filterPosts(){
let filterValue = document.getElementById('search-filter').value.toUpperCase();
let posts = document.getElementById('posts');
let post = posts.querySelectorAll('div.post');
for (let i = 0; i < post.length; i++) {
let filterItem = post[i].getElementsByTagName('h5')[0];
if (filterItem.innerHTML.toUpperCase().indexOf(filterValue) > -1) {
post[i].append();
} else {
post[i].remove();
}
}
}
I've tried a few different things to no avail. I'm trying to remove elements based on type and then readd them if they exist based on heading.
for (let i = 0; i < post.length; i++) {
let filterItem = post[i].getElementsByTagName('h5')[0];
if (filterItem.innerHTML.toUpperCase().indexOf(filterValue) > -1) {
posts.appendChild(post[i]);
} else {
post[i].remove();
}
}
This ended up working for the filtering, but it doesnt bring back posts if textbox is backspaced or empty.
you could use https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild (has better browser support than append) and https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild - in your case this would looks like posts.appendChild(post[i]) and posts.removeChild(post[i])
you could also just change the visibility of the elements - this should be faster and simpler for your case.
another way would be to have an array with the all the posts data and work with it primarily. this way you can also "bring back the data".
each time the filter changes: create a new array by filtering the posts data, remove all post elements, then append only those that match the filtered data e.g.
let postsData = ["content1", "content2"];
for (let i = 0; i < post.length; i++) {
post[i].remove();
}
postsData.filter(function (post) {
return post.toUpperCase().indexOf(filterValue) > -1;
}).forEach(function () {
var postElem = document.createElement("div");
posts.appendChild(postElem);
});
Related
What I am trying to do is:
set an array value (list) to another array (options).
If the user's input (searchVal) matches with a list value it will delete options, push this match, and then will keep pushing the next matches without deleting options again.
So according to the code below, if searchVal was "whatever", options should return: ["whatever", "whatevEver1"] but, instead, it returns: ["whatever", "WhatEver1", "whatttever", "whatever", "whatevEver1"]
Relevant code:
var list = ["whatever", "WhatEver1", "whatttever"];
var clear = 0;
var options = [];
for (var i=0 ; i < list.length ; i++)
{
options.push([list[i]]);
}
var searchVal = window.prompt(" ");
for (var i=0 ; i < list.length ; i++)
{
if (list[i].toLowerCase().includes(searchVal.toLowerCase())) {
if (clear == 0) {
options.length = 0;
}
options.push([list[i]]);
}
clear++;
}
return options;
Js arrays are pass-by-reference. In order to make independent copy of array you need to use:
let options = JSON.parse(JSON.stringify(list));
I didnt try to implement this to your problem cause im too lazy but i think it might work.
Inside the loop in the function thirdNavFunction, I need to target all the .third-nav classes except the one clicked on and it needs to be done without jQuery, how do I do this?
var thirdNav = document.getElementsByClassName("third-nav");
for (var i = 0; i < thirdNav.length; i++){
thirdNav[i].addEventListener("click", thirdNavFuntion);
}
function thirdNavFuntion() {
for (i = 0; i < thirdNav.length; i++) {
thirdNav[i].parentElement.className = "";
}
if (this.parentElement.className === "") {
this.parentElement.className = "nav-sub-li-active";
} else {
this.parentElement.className = "";
}
}
In the code here, I target all the .third-nav divs, but that doesn't work as intended, I need to exclude the one that is clicked. I hope it makes sense.
Convert thirdNav to array using Array.from().
Filter out the clicked element using the filter() method.
Call the forEach method to change the class name of all parent elements.
function thirdNavFuntion() {
const elements = Array.from(thirdNav).filter(el => el !== this)
elements.forEach(el => el.parentElement.className = "")
}
I have an object and an array of categories that should be kept in the object. This snip https://jsfiddle.net/h10rkb6s/2/ ( see log ) works but I cant seems to shake the idea that it is to complicated for a simple search and keep task.
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"],"Others":["othericon1","othericon2"]};
var $categories = '["Spinners","Awesome"]';
var $CatsArray = JSON.parse($categories);
var groups = [];
for(var k in thz_icon_source) groups.push(k);
$.each($CatsArray,function(i,keep){
var index = groups.indexOf(keep);
if (index !== -1) {
groups.splice(index, 1);
}
});
for (var i = 0; i < groups.length; i++) {
delete thz_icon_source[groups[i]];
}
I tried with
$.each(thz_icon_source,function(category,icons){
$.each($CatsArray,function(i,keep){
var index = category.indexOf(keep);
if (index !== -1) {
delete thz_icon_source[category];
}
});
});
but this works only if 1 item is inside my search array.
Any help is appreciated.
There's no need to iterate over $CatsArray to find out which ones should be deleted. You will need to iterate over the keys of the object, and find out for each of them whether it should be deleted, to filter by that.
Leaving the top 3 lines of your script intact, you could simplify to
var keysToDelete = Object.keys(thz_icon_source).filter(function(groupName) {
return $CatsArray.indexOf(groupName) == -1;
});
($.grep would be the jQuery-ism for the filter method, if you are into that).
But assuming we don't even need those groups in an array, you could simply do
for (var groupName in thz_icon_source)
if ($CatsArray.indexOf(groupName) == -1)
delete thz_icon_source[groupName];
However, instead of deleting items from that object, I'd recommend to create a new object with only those that you want to keep. It's much easier to use:
var kept = {};
for (var i=0; i<$CatsArray.length; i++)
kept[$CatsArray[i]] = thz_icon_source[$CatsArray[i]];
I have a listview div on screen and I have added itemDataSource to it successfully
var lettersList = new WinJS.Binding.List(jsonArrayForClearance);
var list_ = document.getElementById("prodListView").winControl;
list_.itemDataSource = lettersList.dataSource;
list_.itemTemplate = document.getElementById("tileTemplate");
list_.forceLayout();
Now in each item I have added a custom input type for user to specify(using template). I want to iterate through all the items of list and obtain the value of that input type in an array.
how can I do it?
EDIT: My question is to access custom input type declared in list items. As such we use following code to access any input type named "inpT"
document.getElementById('inpT');
but how to access the same from list item? can I use Following code(as suggested by user2608614)
var listView = document.getElementById("prodListView").winControl;
var list = listView.itemDataSource.list;
for (var i = 0; i < list.length; i++) {
var item = list.getAt(i);
item.getElementById('inpT');
}
You can iterate through the list elements like this:
var listView = document.getElementById("prodListView").winControl;
listView.itemDataSource.getCount()
.done(function(count) {
for (var i = 0; i < count ; i++) {
listView.itemDataSource.itemFromIndex(i)
.done(function (item) {
//***item will contain your property
});
}
});
Is not the best solution as it make it difficult to chain the promises, I'm also looking for a better one. But it works.
Since you're using a Binding.List you can just iterate through that much like an array.
var listView = document.getElementById("prodListView").winControl;
var list = listView.itemDataSource.list;
for (var i = 0; i < list.length; i++) {
var item = list.getAt(i);
// do something with this item
}
The only thing to remember is that it doesn't support [] and instead you have to use .getAt() and .setAt().
I have an array of strings in Javascript like `var elements = ["string1", "string2"]; The array is created dynamically so it could contain any number of strings. I want to associate a counter to each element of the array. The counter will increment or decrement during the webpage's life.
I was going to try element["string1"].counter = 1; but it didn't work.
What's a good way to implement this?
If you had an array var elements = ["string1", "string2"], you could not access an element with elements["string1"], you are using the value not the index. elements[0] is the correct form of access to the element, using the numerical key.
Even then, strings are special types of object and do not appear to take additional parameters readily, at least not when I tested a moment ago. Which is odd.
You could quickly knock the array in to a set of objects with separate text and counter components.
var elements = ["string1", "string2"];
var elementsWithCounter = [];
for(var index = 0; index < elements.length; index++) {
elementsWithCounter[i] = { text: elements[index], counter: 1 };
}
You could also create a "hash table" using a plain object such as:
var counter = {};
for(var i = elements.length; i--; ) {
counter[elements[i]] = 1;
}
Then you could increment the counter with:
counter['string1'] += 1;
or
counter[elements[0]] += 1;
This might help you.
elementArray = ["string1", "string2"]
function setCounter(str, val) {
for (var i = 0; i < elementArray.length; i++) {
if (str === elementArray[i]) elementArray[i].counter = val;
}
}
function getCounter(str) {
for (var i = 0; i < elementArray.length; i++) {
if (str === elementArray[i]) return elementArray[i].counter;
}
}
setCounter("string1", 5);
getCounter("string1");
Alternatively just access elementArray[index].counter
Javascript primitives/built in objects can't have properties/attributes added to their prototype (i.e. String.prototype.counter = -1 doesn't work correctly). Image, String, Date, Array all can't have properties added.
Maybe instead of a string you should make it an object, similar to what Orbling has posted.