Polymer 1.0, How to implement Infinite nested dom-repeat - javascript

I have following JSON obj,
categoryList = [{
"title": "Computers",
"categories":
[
{
"title": "Laptops",
"categories":
[
{
"title": "Ultrabooks",
"categories":
[
{
"title": "Lenovo",
"categories":
[
{
"title": "i5 intel"
}
]
}
]
},
{
"title": "Dell"
},
{
"title": "Macbooks",
"categories":
[
{
"title": "Air"
},
{
"title": "Pro"
}
]
}
]
},
{
"title": "Desktops"
},
{
"title": "Tablets",
"categories":
[
{
"title": "Apple"
},
{
"title": "Android"
}
]
},
{
"title": "Printers"
}
]
}]
As you can see, each categories could have a child categories so it could literally go on forever. I am trying to display all of them but I can't figure out how I would do this.
This is all I have so far (obviously this only gets the first child in each categories):
<template is="dom-repeat" items="{{categoryList}}" as="category">
<template is="dom-if" if="{{_hasData(category.categories)}}">
<div>{{category.title}}</div>
<template is="dom-repeat" items="{{category.categories}}" as="item">
<div>{{item.title}}</div>
</template>
</template>
</template>

You can use something like recursive code here.
Here's a plunker for same.
<script src="https://polygit.org/components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="https://polygit.org/components/polymer/polymer.html">
<dom-module id="infinite-repeat">
<template>
<template is="dom-repeat" items={{categories}} as="category">
<div>{{category.title}}</div>
<template is="dom-repeat" items="{{category.categories}}" as="item">
<div>{{item.title}}</div>
<template is="dom-if" if="{{_hasData(item.categories)}}">
<infinite-repeat categories={{item.categories}}></infinite-repeat>
</template>
</template>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'infinite-repeat',
properties: {
categories: {
type: Array,
value: function() {
return [{
"title": "Computers",
"categories": [{
"title": "Laptops",
"categories": [{
"title": "Ultrabooks",
"categories": [{
"title": "Lenovo",
"categories": [{
"title": "i5 intel"
}]
}]
}, {
"title": "Dell"
}, {
"title": "Macbooks",
"categories": [{
"title": "Air"
}, {
"title": "Pro"
}]
}]
}, {
"title": "Desktops"
}, {
"title": "Tablets",
"categories": [{
"title": "Apple"
}, {
"title": "Android"
}]
}, {
"title": "Printers"
}]
}];
}
}
},
_hasData: function(item) {
return item && item.length > 0;
}
})
</script>
<infinite-repeat></infinite-repeat>

Related

javascript print nested array to screen

I have a data array, there are multiple objects in this array, and the data object is an array. There may be more than one object in this array. How can I copy these objects under a single array?
const test = []
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
]
[{
"price":10,
"title": "sda"
},
{
"price":20,
"title": "asdas"
},
]
If this is the output I expect, it should be like this. how can I do that
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
{
"price":99,
"title":"aaaaa"
}
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
];
console.log(data.map(e => e.data).flat());
// OR
console.log(data.flatMap(e => e.data));

Loop through Javascript object with children in Angular template

I have the following js object:
{
"id": "1554038371930_ajhnms9ft",
"name": "CPS",
"nodes": [
{
"id": "1554038905938_le34li2cg",
"name": "Consumer Journey",
"nodes": [
{
"id": "1554039157958_kwab8rj5f",
"name": "Average Rating",
"nodes": []
},
{
"id": "1554039174126_p47ugwkbv",
"name": "Product Quality",
"nodes": [
{
"id": "1554039298091_ewdyefkql",
"name": "Performance",
"nodes": []
},
{
"id": "1554039306834_qf54k1dqe",
"name": "Reliability",
"nodes": []
},
{
"id": "1554039320002_vfkenjmct",
"name": "Comfort",
"nodes": []
}
]
},
{
"id": "1554039197951_ajvv8587d",
"name": "Supply & Delivery",
"nodes": []
},
{
"id": "1554735679177_g5tini7ga",
"name": "Behind Product",
"nodes": [
{
"id": "1554736595466_nt4owp9in",
"name": "Influencers",
"nodes": []
},
{
"id": "1554736608593_58yomqpya",
"name": "Brand Confidence",
"nodes": []
}
]
},
{
"id": "1554736413715_jhro1oh0r",
"name": "Economical Value",
"nodes": [
{
"id": "1554736664421_wng97pbz8",
"name": {
"en": "Price"
},
"nodes": []
},
{
"id": "1554736676408_d4kiy2wv8",
"name": "Promotion & Reward",
"nodes": []
}
]
}
]
}
]
}
I want to loop through it in my angular HTML template so I can have the following list:
CPS
Consumer Journey
Average Rating
Product Quality
Performance
Reliability
Comfort
Supply & Delivery
Behind Product
Influencers
Brand Confidence
Economical Value
Price
Promotion & Reward
PS: I have an unknown number of levels!
I tried to implement that but my solution works only if I have a known number of levels:
<div *ngFor="let item of data">
<p>{{ item.name }}</p>
<div *ngIf="item.nodes.length">
<div *ngFor="let subItem of item.nodes">
<p>{{ subItem.name }}</p>
<div *ngIf="subItem.nodes.length">
<div *ngFor="let child of subItem.nodes">
{{ child.name }}
</div>
</div>
</div>
</div>
</div>
you need a recursive component to loop through n levels:
#Component({
selector: 'recursive-list',
template: `
<div *ngFor="let item of data">
<p>{{ item.name }}</p>
<recursive-list *ngIf="item.nodes.length" [data]="item.nodes"></recursive-list>
</div>
`
})
export class RecursiveListComponent {
#Input() data;
}

Loop through Nested array of Object and replace empty attribute with dynamic values - Javascript

I have a nested object like below. The content attribute in some of the objects are empty. I need to loop through all the objects ,if it has an empty content attribute i need to give a value like Default value to it.
var data = [{
title: "Admin Services",
content: "admin",
links: [{
title: "Report",
content: "",
links: [{
title: "Notifications",
content: "Notify",
links: [{
title: "Send",
content: "",
links: [{
title: "read",
content: "",
links: [],
}]
}]
}]
}, {
title: "Script",
content: "script",
links: [{
"title": "Execute",
content: "",
links: []
}]
}, {
title: "Process",
content: "",
links: []
}]
}];
function checkEmptyContent(data){
data.forEach((item)=>{
if(item.links.length > 0){
checkEmptyContent(item.links)
}
if(item.content === ""){
item.content = "Default Content";
}
});
}
checkEmptyContent(data);
console.log('data',data);
And i got the output like below
[
{
"title": "Admin Services",
"content": "admin",
"links": [
{
"title": "Report",
"content": "Default Content",
"links": [
{
"title": "Notifications",
"content": "Notify",
"links": [
{
"title": "Send",
"content": "Default Content",
"links": [
{
"title": "read",
"content": "Default Content",
"links": []
}
]
}
]
}
]
},
{
"title": "Script",
"content": "script",
"links": [
{
"title": "Execute",
"content": "Default Content",
"links": []
}
]
},
{
"title": "Process",
"content": "Default Content",
"links": []
}
]
}
]
The final requirement is ,not only add the default text but also a counter which is increments like below
[
{
"title": "Admin Services",
"content": "admin",
"links": [
{
"title": "Report",
"content": "Default Content (0)",
"links": [
{
"title": "Notifications",
"content": "Notify",
"links": [
{
"title": "Send",
"content": "Default Content (1)",
"links": [
{
"title": "read",
"content": "Default Content (2)",
"links": []
}
]
}
]
}
]
},
{
"title": "Script",
"content": "script",
"links": [
{
"title": "Execute",
"content": "Default Content (0)",
"links": []
}
]
},
{
"title": "Process",
"content": "Default Content (0)",
"links": []
}
]
}
]
The counter should start with 0 for each of the objects in the array
You can use recursion for this, by repeating the addDefault() function for each nested array. By looping over each object in the array, you can check whether or not it has content, if it doesn't, you can add your "Default Content (0)" string to it:
const data = [{title:"Admin Services",content:"admin",links:[{title:"Report",content:"",links:[{title:"Notifications",content:"Notify",links:[{title:"Send",content:"",links:[{title:"read",content:"",links:[]}]}]}]},{title:"Script",content:"script",links:[{title:"Execute",content:"",links:[]}]},{title:"Process",content:"",links:[]}]}];
const addDefault = (arr, level=0) => {
arr.forEach(obj => {
obj.content = obj.content || `Default Content (${level++})`;
addDefault(obj.links, level);
level = 0;
});
}
addDefault(data);
console.log(data);
I have Modify your logic check it, This Will work for you
function checkEmptyContent(data){
data.forEach((item)=>{
if(!item.content.length){
item.content = "Default Content";
}
if(item.links.length > 0){
checkEmptyContent(item.links)
}
});
}
checkEmptyContent(data);
console.log('data',data);

Show Objects Array As a Nested List

In my vue app, I have an array of objects which I want to render as a list. Within each object, there is a 'parent' property which contains info about who the parent is thereby giving us a hierarchical data structure. However, I am unable to show this hierarichal list. I tried creatin a tree by transforming the data but my code seems bugged.
You can see my attempted version here: http://jsbin.com/pewusiyete/edit?html,js,console,output
Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in list">
<a v-bind:href="item.value">{{item.label}}</a>
</li>
</ul>
{{tree}}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
list:[
{
"label":"Parks & Gardens",
"type":"place",
"value":"parks-gardens",
"id":"0CNYF4qh0aaYi2XLGCfG"
},
{
"label":" Art & Craft",
"type":"product",
"value":"art-craft",
"id":"4TfXwraLAJX9K5WeIBT5"
},
{
"label":"Monuments",
"type":"place",
"value":"monuments",
"id":"4mVxy4QEplxTnf6NwpIf"
},
{
"label":"Books",
"type":"book",
"value":"books",
"id":"4oVqbEDhPSYqaTDn4xMV"
},
{
"label":"Sports Academies",
"type":"place",
"value":"sports-academies",
"id":"H7GkAF0Hfdu3OoHBYyQY"
},
{
"label":"Store",
"type":"place",
"value":"store",
"id":"Ki4YjRNe4HmZWOCOpg9K"
},
{
"label":"Tennis Academies",
"parent":"sports-academies",
"type":"place",
"value":"tennis-academies",
"id":"N89adEZwHfSGMQiq1R5f"
},
{
"label":"Toy Stores",
"type":"place",
"parent":"stores",
"value":"toy-stores",
"id":"Oj6QgO0S0Z6AFHvrr2ZH"
},
{
"label":"Electronics",
"type":"product",
"value":"electronics",
"id":"UuztFKZrsw3vcciKaj8k"
},
{
"label":"Tech",
"type":"product",
"value":"tech",
"id":"WuqiVSXxmlCCQ5usAUNZ"
},
{
"label":"Book Stores",
"type":"place",
"parent":"stores",
"value":"book-stores",
"id":"ZmXlJ12jJROGeHjYcwOT"
},
{
"label":" Online Stores",
"type":"commerce",
"value":"online-stores",
"id":"cIRSVPcqSDr6WfuRe4OX"
},
{
"label":"Play Areas",
"type":"place",
"value":"play-areas",
"id":"fEk3dcKprq9Hd8rSgiG3"
},
{
"label":"Toys",
"type":"product",
"value":"toys",
"id":"rJTpw2V9apxe9jQjLTOS"
},
{
"label":"Stores",
"type":"place",
"value":"stores",
"id":"ZmXlJ12jJROGeHjYcwOH"
}
]
},
computed: {
newitem: function () {
return this.list.reduce(function(p,c) {
p[c.value] = c;
c.children = [];
return p;
}, {});
},
tree: function () {
return this.list.reduce(function(p,c) {
console.log(c.parent)
if (c.parent = 'undefined') {
p = c;
} else {
newitem[c.parent].children.push(c);
}
return p;
}, {});
}
}
});
</script>
</body>
</html>
There's a few things wrong with your code, I won't go into too much detail, but at a high level:
if (c.parent = 'undefined') should probably be if (c.parent === undefined).
newitem[c.parent].children.push(c) should probably be this.newitem[c.parent].children.push(c), but even then you shouldn't mutate computed properties.
I think just overall you are not structuring your menu items properly.
First you will need to transform the flat list of items into a tree structure. Then you will need to use recursive components in order to render such a tree.
Here's an example:
const MenuList = {
name: 'menu-list',
template: '#menu-list-template',
props: ['items'],
};
new Vue({
el: '#app',
components: {
MenuList,
},
data: {
list: [
{
"label": "Parks & Gardens",
"type": "place",
"value": "parks-gardens",
"id": "0CNYF4qh0aaYi2XLGCfG"
},
{
"label": " Art & Craft",
"type": "product",
"value": "art-craft",
"id": "4TfXwraLAJX9K5WeIBT5"
},
{
"label": "Monuments",
"type": "place",
"value": "monuments",
"id": "4mVxy4QEplxTnf6NwpIf"
},
{
"label": "Books",
"type": "book",
"value": "books",
"id": "4oVqbEDhPSYqaTDn4xMV"
},
{
"label": "Sports Academies",
"type": "place",
"value": "sports-academies",
"id": "H7GkAF0Hfdu3OoHBYyQY"
},
{
"label": "Store",
"type": "place",
"value": "store",
"id": "Ki4YjRNe4HmZWOCOpg9K"
},
{
"label": "Tennis Academies",
"parent": "sports-academies",
"type": "place",
"value": "tennis-academies",
"id": "N89adEZwHfSGMQiq1R5f"
},
{
"label": "Toy Stores",
"type": "place",
"parent": "stores",
"value": "toy-stores",
"id": "Oj6QgO0S0Z6AFHvrr2ZH"
},
{
"label": "Electronics",
"type": "product",
"value": "electronics",
"id": "UuztFKZrsw3vcciKaj8k"
},
{
"label": "Tech",
"type": "product",
"value": "tech",
"id": "WuqiVSXxmlCCQ5usAUNZ"
},
{
"label": "Book Stores",
"type": "place",
"parent": "stores",
"value": "book-stores",
"id": "ZmXlJ12jJROGeHjYcwOT"
},
{
"label": " Online Stores",
"type": "commerce",
"value": "online-stores",
"id": "cIRSVPcqSDr6WfuRe4OX"
},
{
"label": "Play Areas",
"type": "place",
"value": "play-areas",
"id": "fEk3dcKprq9Hd8rSgiG3"
},
{
"label": "Toys",
"type": "product",
"value": "toys",
"id": "rJTpw2V9apxe9jQjLTOS"
},
{
"label": "Stores",
"type": "place",
"value": "stores",
"id": "ZmXlJ12jJROGeHjYcwOH"
}
]
},
computed: {
treeList() {
// Deep clone the list and add a children property with empty array value to each item
const items = this.list.map(item => Object.assign({}, item, { children: [] }));
// Organize items into a map keyed by item value for easy lookup
const byValue = new Map(items.map(item => [item.value, item]));
// Top level will contain the items which do not have a parent
const topLevel = [];
for (const item of items) {
// Look up the parent item if there is one
const parent = byValue.get(item.parent);
if (parent) {
// Append the item into the parent's children array
parent.children.push(item);
} else {
// The item has no parent
topLevel.push(item);
}
}
return topLevel;
}
}
});
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>
<div id="app">
<menu-list :items="treeList"></menu-list>
</div>
<script type="text/x-template" id="menu-list-template">
<ul v-if="items.length">
<li v-for="item of items">
<a :href="item.value">{{ item.label }}</a>
<menu-list :items="item.children"></menu-list>
</li>
</ul>
</script>

How group objects in array in array from ng-repeat with filter?

How group objects in array in array from ng-repeat with filter ?
I have an array with objects, and I would like group by this objects by their countries.
Sample : I would like to have this result :
Free : Australia, India, United States
Pay : Australia
Not Pay : Australia, India
from :
{
"id": 1,
"offer": [
{
"id": 9806,
"country": {
"name": "Australia"
},
"code_show": [
{
"code": "Free"
},
{
"code": "Pay"
},
{
"code": "Not Pay"
}
]
},
{
"id": 9807,
"country": {
"name": "India"
},
"code_show": [
{
"code": "Free"
},
{
"code": "Not Pay"
}
]
},
{
"id": 9808,
"country": {
"name": "United States"
},
"code_show": [
{
"code": "Free"
}
]
}
],
},
{
"id": 2,
"offer": [
{
"id": 9806,
"country": {
"name": "Australia"
},
"code_show": [
{
"code": "Free"
},
{
"code": "Not Pay"
}
]
},
{
"id": 9807,
"country": {
"name": "Mexico"
},
"code_show": [
{
"code": "Free"
}
]
},
{
"id": 9808,
"country": {
"name": "United States"
},
"code_show": [
{
"code": "Free"
}
]
}
]
}
I tried this with the code :
<ul ng-repeat="(key, value) in offer.code_show | groupBy: 'code_show.code'">
{{ key }}
<li ng-repeat="country in value">
: {{ country.name }}
</li>
</ul>
This might be better done in the controller - mainly cause you'll have a different data structure:
$scope.groupedByCode = {};
$scope.offer.forEach(function(obj) {
obj["code_show"].forEach(function(code) {
if (!$scope.groupedByCode[code]) {
$scope.groupedByCode[code] = [];
}
$scope.groupedByCode[code].push(obj);
});
});
Now you'll have each offer object in a key with the name of the code, then just make the view:
<ul ng-repeat="(key, value) in groupedByCode">
{{ key }}
<li ng-repeat="country in value">
: {{ country.country.name }}
</li>
</ul>

Categories

Resources