JavaScript - Splitting Multiple Return Values - javascript

I'm building a filter for a search. Everything worked fine before since we only allowed 1 filter at a time. So I'd get a return like this:
var returnVal = "&filterName=filterProperty"
var filterFields = returnVal.split(['=']);
var filterCategory = filterFields[0];
var filterCatSplit = filterCategory.substr(1);
var filterTitle = filterFields[1];
<h4>filter title</h4>
<ul>
<li>filter one</li>
</ul>
i'd just get the returnVal and split it at the '='
Now we're going to allow multiple values and I'm not sure how to get them all onto the page in a nice list. Now, returnVal can look like this:
var returnVal = "&sizeFilterName=filterProperty,filterPropery&colorFilterName=filterProperty,filterProperty"
I now need this to return like this (or something like this)
<h4>Size Filter Name</h4>
<ul>
<li>Size Filter One</li>
<li>Size Filter Two etc</li>
</ul>
<h4>Color Filter Name</h4>
<ul>
<li>Color Filter One</li>
<li>Color Filter Two etc</li>
</ul>
I've never had to split and slice so many variants before. I'm a bit lost. I hope this is enough to get an idea of what I'm trying to do.
Thanks!

You can pass returnVal to URLSearchParams() then .split() the value by "," perform tasks using the returned array
let returnVal = "&sizeFilterName=filterProperty,filterPropery&colorFilterName=filterProperty,filterProperty";
let params = Array.from([...new URLSearchParams(returnVal)]
, ([key, value]) => [key, value.split(",").filter(Boolean)]);
// do stuff with `params`
params.forEach(([key, value]) =>
document.body.insertAdjacentHTML("beforeend", `<h4>Size ${key}</h4>
<ul>
${value.map(prop => `<li>Color ${prop}</li>`).join("")}
</ul>`)
);

Related

Filtering the data in angular 6

I am in new in angular 6. I am currently working on angular 6 project. I am coming into a situation where i need tho filer the data, but i have problem to keep the original object. Here is code:
this.loginService.categoryType$.subscribe((data) => {
for(var i=0; i<this.listPosts.length; i++){
if(this.listPosts[i]['categoryName'] == data){
}else{
this.listPosts.splice(i,1);
}
}
});
Html:
<li class="nav-item" (click) = "selectedCategory('buy')" style="cursor: pointer;">
<a class="nav-link" [ngClass]="{'active':selectedCat == 'buy'}">
<i class="material-icons left-nav">
shopping_cart
</i>
Buy
</a>
</li>
<li class="nav-item" (click) = "selectedCategory('sell')"style="cursor: pointer;">
<a class="nav-link" [ngClass]="{'active':selectedCat == 'sell'}">
<i class="material-icons left-nav">
shopping_basket
</i>
Sell
</a>
</li>
The problem is how to keep the original object value, because data is already spliced .
If you need to keep the original list as well as a filtered one, I suggest you to save the original list in a variable, and then use rxjs methods to display the filtered
originalList$: BehaviorSubject<any> = new BehaviorSubject<any>([]);
filteredList = [];
this.loginService.categoryType$.subscribe((data) => {
this.originalList$.next(data);
});
this.originalList$.pipe(
map(data => yourLogicToFilter(data))
).subscribe(list => filteredList = list);
filteredList can be an Observable so you can use an async pipe in your code as well.
Probably there are even cleaner solutions embracing rxjs, but at least this should get you going on the logic
From my understanding, you want to get the data and you do not want to mutate the original object stored in your component as a property. In which case, using splice defeats the purpose of what you are trying to do since it mutates the object.
There are a number of ways you could do this but I'll try to keep my answer as close to your code as possible. Correct me if I'm wrong but in my understanding, this.loginService.categoryType$ is an observable or a subject for determining the category type. Since you already have the category type as an observable, you could use map on it and filter this.listPosts based on the category name.
const listPosts$ = this.loginService.categoryType$.pipe(
map(categoryType => this.listPosts.filter(
listPost => listPost.categoryName === categoryType
)),
);
You could use listPosts$ on your template and pipe async on it.
listPosts$ | async
Or you could tap or subscribe against it like what you did to get the value and assign it to your component property or variable. I personally don't like this approach since you're storing the values from your stream in a variable.
const listPosts$ = this.loginService.categoryType$.pipe(
map(categoryType => this.listPosts.filter(
listPost => listPost.categoryName === categoryType
)),
);
listPosts$.subscribe(currentList => this.currentListPosts = currentList);
Hope this helps!

how to use .map() in nodelist in javascript?

Why am i getting this error? How can i access and print the nodes when i'm selecting the <li> tags with querySelectorAll?
script.js:14 Uncaught TypeError: list.map is not a function
HTML
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
JS
let list = document.querySelectorAll("li");
let items = list.map(elem => {
console.log(elem);
})
querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors. Use array#from to convert NodeList to array then iterate through array#map.
let list = document.querySelectorAll("li");
let items = Array.from(list).map(elem => {
console.log(elem);
})
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
In addition to Itang and Foo's suggestion, you can also use:
[].concat(document.querySelectorAll("li")).map((el) => { console.log(el); })
In fairness I think Foo's suggestion using spread syntax Is probably the most elegant, I'm just not sure how widely the spread operator is supported for NodeLists. (pasted below for reference)
[...document.querySelectorAll('li')].map((el) => { console.log(el); })
If you're using ES6, you can use [...selectors] syntax, like this:
let getMappingList = function (list) {
console.log(typeof list);
for (let item of list) {
console.log(item);
}
console.log("___________________");
list.map(item => console.log(item));
};
getMappingList([...document.querySelectorAll("li")]);
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
After getting the list, we can also use map function, or looping the list using for...of... syntax.
Array(...selectors) is the same way to use:
let getMappingList = function (list) {
console.log(typeof list);
for (let item of list) {
console.log(item);
}
console.log("___________________");
list.map(item => console.log(item));
};
getMappingList(Array(...document.querySelectorAll("li")));
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
I know this is an old thread but listed as #1 on Google search result. So here is an alternative to those in need.
let items = [].map.call(list, item => console.log(item));
I encountered the question of how to use a nodelist (result of document.querySelectorAll) with .map on my project and solved it by using a SPREAD operator to create an array from the nodelist.
Learning as I go so don't hesitate to correct me. It's weird that modern browsers can directly execute a foreach function to a nodelist but not map.
let list = document.querySelectorAll("li");
let items = [...list].map(elem => {
console.log(elem);
})
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
edit : understood how snippets work / SPREAD not REST

ngFor call function Angular2

The following works:
*ngFor="let child of items || []; let i = index;"
This doesn't:
*ngFor="let child of items || []; let specialVersionOfI = someFunction(index);"
I get:
Parser Error: Unexpected token (, expected identifier, keyword, or string at column 56 in [ngFor let child of items |
What's the reasoning behind this, and is there an alterantive?
Much more readable will be version with mapping in component, sth like:
this.items.map((child, i) => {
child['specialVersionOfI'] = this.someFunction(i);
return child;
})
and then in template just {{child.specialVersionOfI}}
Use the function later within the loop, not when you assign the index.
<u>
<li *ngFor="let item of items || []; let i=index">
use function here >> {{someFunction(i)}}
</li>
</u>
You could also manipulate the array in the model and store the special index in a second parallel array, then access it within the template.
<u>
<li *ngFor="let item of items || []; let i=index">
access special index >> {{customIndices[i]}}
</li>
</u>

Use of "for...of" in ng-repeat

Looking through ng-repeats source, it doesn't look like theres any instance of it using for-of. Is there any custom directive that does this or some other way of achieving this loop in templates to make use of iterator functions?
Class with iterator
class Cache{
constructor(items){
this.cache = {
"one" : 1,
"two" : 2
};
};
// custom iterator that turns our cache into an array
// for use in "for...of" loops
[Symbol.iterator](){
var index = 0;
// turn cache object into array of its values (underscore method)
var data = _.values(this.cache);
return {
next: function(){
if(index < data.length){
return {
value: data[index++],
done: false
};
}else{
return { done:true };
}
}
};
};
};
var myCache = new Cache();
// looping my cache in simple js would look like
for(let val of myCache){
console.log(val);
}
// 1, 2
proposed angularjs ng-repeat directive
<ul>
<li ng-repeat="item in myCache track by $index"></li>
</ul>
However that does not work as ng-repeat does not implement for...of. My question is: is there a way to get the ng-repeat directive to work nicely with iterators with minimal interface changes, or better yet, a custom directive identical to ng-repeat that is made for for...of loops?
You could just use Array.from to convert your iterable source to an array, which ngRepeat will be able to iterate:
<ul>
<li ng-repeat="item in Array.from(myCache) track by $index"></li>
</ul>
Ideally this would happen in your javascript directive/controller:
scope.myCache = Array.from(new Cache());
View:
<ul>
<li ng-repeat="item in myCache track by $index"></li>
</ul>

How do i compare 2 arrays and their values and produce an action based on the comparison

This each statement is apart of a larger function which gets a children object(array) passed in. The issue im having is that im trying to compare array of values from the children object thats being passed in to a dom element on a page. In short how do i compare 2 arrays? If the values in passed array (Children) are not on the page or found in the dom then add the values to the DOM. If the values are already in the DOM then do nothing.
$.each(children,function(){
for (var i in children){
var the_child = children[i];
var the_child_check = $("#" + the_child.id, self.container);
}
if(self.container.children.length >=0){
self.container.tabs('add', '#' + the_child.id, the_child.label);
}else{
self.container.tabs('remove', '#' + the_child.id);
});
Once i understand how to implement this logic, then i should be able to incorporate this into its proper place into the function.
<div id="tabcontainer">
<ul id="tab1">
<li>tab 1</li>
</ul>
<ul id="tab2">
<li>tab 1</li>
</ul>
</div>
This is a basic example of how the html is constructed. each tab is dynamically generated based on the passed in array object (children)
In your example
This assumes you have set self somewhere prior.
// i gets index, val receives the item of the current iteration
$.each(children, function(i, val) {
// code
if (self.container.find(val)) {
// item exists in dom
} else {
// item does not exist in dom
}
});
http://docs.jquery.com/Utilities/jQuery.inArray
Here is jquery inArray,
$(document).ready(function(){
var arr = [ 4, "Pete", 8, "John" ];
$("span:eq(0)").text(jQuery.inArray("John", arr));
$("span:eq(1)").text(jQuery.inArray(4, arr));
$("span:eq(2)").text(jQuery.inArray("David", arr));
});

Categories