I have a javascript object that needs to be displayed in paged format. For example, from the below object, I need to display this as pages based on the value of perPage variable.
{
"fruits":[
{
"from":"Shanghai",
"to":"Houston",
"createdOn":"2019-02-20 17:02:45",
"threadId":"1234564534"
},
{
"from":"Mumbai",
"to":"Texas",
"createdOn":"2019-02-22 17:02:45",
"threadId":"223455678"
}
],
"vegetables":[{
"from":"Barcelona",
"to":"Milan",
"createdOn":"2019-01-20 10:02:45",
"threadId":"45673456"
}],
"paper":[{
"from":"Kualalumpur",
"to":"Singapore",
"createdOn":"2019-02-01 12:02:45",
"threadId":"234222345"
},
{
"from":"Singapore",
"to":"Vancover",
"createdOn":"2019-01-20 11:02:45",
"threadId":"6756434343"
}],
"books":[{
"from":"Jibooty",
"to":"Ahmedabad",
"createdOn":"2019-02-10 17:02:45",
"threadId":"23456789"
}],
"toys":[{
"from":"Shanghai",
"to":"Houston",
"createdOn":"2019-02-20 14:02:45",
"threadId":"123434343"
}],
"electronics":[{
"from":"Somalia",
"to":"Angora",
"createdOn":"2019-02-20 17:02:45",
"threadId":"667676767"
}]
}
If the value of perPage is 5, this should shown as below
<div class="page">
fruits
vegetables
paper
books
toys
</div>
<div class="page">
electronics
</div>
and if the value of perPage is 2, there will be three div's with the class page. fruits and vegetables will be displayed in the first div, paper and books will be displayed in the second div, toys and electronics will be displayed in the third div.
I have prepared a basic code for this in vue js, but it failed in some cases. Can someone have a look at this and let me know where it went wrong ?
<div class="wrapper">
<div v-for="(eachWidget, widgetName, index) in widgetData">
<div v-bind:class="((index != 0) && ((index%perPage) == 0))?'page':''" >
<div class="widget">
<p>{{ widgetName}}</p>
<p class="card" v-for="(eachItem, index) in eachWidget">{{eachItem.from}}</p>
</div>
</div>
At first I calculated pages count based on items length and perpage number.
After that, for each page I list items and check index of item in v-if:
new Vue({
el: "#app",
data: {
perpage: 5,
items: {
"fruits": [{
"from": "Shanghai",
"to": "Houston",
"createdOn": "2019-02-20 17:02:45",
"threadId": "1234564534"
}, {
"from": "Mumbai",
"to": "Texas",
"createdOn": "2019-02-22 17:02:45",
"threadId": "223455678"
}],
"vegetables": [{
"from": "Barcelona",
"to": "Milan",
"createdOn": "2019-01-20 10:02:45",
"threadId": "45673456"
}],
"paper": [{
"from": "Kualalumpur",
"to": "Singapore",
"createdOn": "2019-02-01 12:02:45",
"threadId": "234222345"
}, {
"from": "Singapore",
"to": "Vancover",
"createdOn": "2019-01-20 11:02:45",
"threadId": "6756434343"
}],
"books": [{
"from": "Jibooty",
"to": "Ahmedabad",
"createdOn": "2019-02-10 17:02:45",
"threadId": "23456789"
}],
"toys": [{
"from": "Shanghai",
"to": "Houston",
"createdOn": "2019-02-20 14:02:45",
"threadId": "123434343"
}],
"electronics": [{
"from": "Somalia",
"to": "Angora",
"createdOn": "2019-02-20 17:02:45",
"threadId": "667676767"
}]
}
},
computed: {
length() {
return Object.keys(this.items).length
},
pages() {
return Math.ceil(this.length / this.perpage)
}
}
})
// just to silent vue
Vue.config.productionTip = false;
Vue.config.devtools=false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label>per page:</label>
<input type="number" v-model="perpage" min="1" :max="length">
<ul v-for="n in pages">
<li v-for="(item, title, index) in items"
v-if="index >= perpage * (n-1) && index < perpage * n">
{{ title }}
</li>
</ul>
</div>
hope to help
Related
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;
}
I have a JSON file with hierarchical data:
[
{
"id": 0,
"label": "Gap Inc.",
"value": "Gap Inc",
"checked": false,
"children": [
{
"id": 0,
"label": "Banana Republic",
"value": "Banana Republic",
"checked": false
},
{
"id": 1,
"label": "Gap",
"value": "Gap ",
"checked": false
},
{
"id": 2,
"label": "Hill City",
"value": "Hill City",
"checked": false
},
{
"id": 3,
"label": "Old Navy",
"value": "Old Navy",
"checked": false
}
]
},
{
"id": 1,
"label": "Home Depot",
"value": "Home Depot",
"checked": false,
"children": []
},
{
"id": 2,
"label": "TJX",
"value": "TJX Companies",
"checked": false,
"children": [
{
"id": 0,
"label": "TJ Maxx",
"value": "TJ Maxx ",
"checked": false
},
{
"id": 1,
"label": "Marshalls",
"value": "Marshalls",
"checked": false
},
{
"id": 2,
"label": "Home Goods",
"value": "Home Goods",
"checked": false
}
]
}
]
I am using it to create a set of nested HTML lists with checkboxes:
<ul class="list-unstyled">
<li *ngFor="let parent of accountList; let q = index">
<div class="form-check">
<input id="parent-{{q}}"
class="form-check-input"
type="checkbox"
[(ngModel)]="parent.checked"
(click)="selectChildren(parent, $event)"
[indeterminate]="selectedChildren.length">
<label for="parent-item" class="form-check-label">
{{parent.label}}
</label>
</div>
<ul class="list-unstyled pl-4">
<li *ngFor="let child of parent.children; let i = index;">
<div class="form-check">
<input id="child-{{i}}"
class="form-check-input"
type="checkbox"
[(ngModel)]="child.checked"
(click)="selectChild(child, $event)">
<label for="child-{{i}}" class="form-check-label">
{{child.label}}
</label>
</div>
</li>
</ul>
</li>
</ul>
What's supposed to happen
If you click a parent checkbox, it checks all the children.
If you click only one child, its parent is set to indeterminate.
What DOES happen
If you click a parent checkbox, it checks all the children.
If you click only one child, ALL parents are set to indeterminate.
I assume I screwed up something somewhere. I think I have mapped the indeterminate attribute to the length of any selected children (here selectedChildren instead of only the children of the given parent. Not sure how to fix that...
Here is the typescript:
selectedChildren = [];
selectChildren = function(data, event) {
const parentChecked = !data.checked;
data.children.forEach((child, key2) => {
child.checked = parentChecked;
});
};
selectChild = (data, event) => {
if (this.selectedChildren.indexOf(data.id) === -1) {
this.selectedChildren.push(data.id);
data.checked = true;
} else {
this.selectedChildren.splice(this.selectedChildren.indexOf(data.id), 1);
data.checked = false;
}
};
[
{
"category": "Beauty",
"subcategories": [
{
"name": "Baby Care",
"items": [
{
"name": "soap",
"price": 10.00
},
{
"name": "cream",
"price": 20.00
},
{
"name": "dipers",
"price": 8.00
},
{
"name": "Dress",
"price": 13.00
}
]
},
{
"name": "Drug Store",
"items": [
{
"name": "Bandage",
"price": 5.00
},
{
"name": "stringe",
"price": 6.50
},
{
"name": " Pain Relief",
"price": 8.00
},
{
"name": "First Aid Kit",
"price": 14.99
},
{
"name": "Cold Relief",
"price": 6.50
}]
},
{
"name": "Health and Personal Care",
"items": []
},
{
"name": "Household Supplies",
"items": [{
"name": "Air Freshener",
"price": 1.25
},
{
"name": "All Purpose Cleaner",
"price": 2.99
},
{
"name": "Disinfecting Wipes",
"price": 8.99
}
]
}
]
},
{
"category": "Pantry Items",
"subcategories": [
{
"name": "Beverages",
"items": [
{
"name": "Apple Juice",
"price": 5.99
},
{
"name": "Banana-Orange Juice",
"price": 1.99
},
{
"name": "Cranberry Juice",
"price": 4.99
},
{
"name": "Strawberry Lemonade",
"price": 2.50
}
]
},
{
"name": "Canned Food",
"items": [
{
"name": "Pickels",
"description": "Assorted pickles",
"price": 1.99
},
{
"name": "Tomatoe Sauce",
"price": 1.59
}
]
}
]
},
{
"category": "Perishables",
"subcategories": [
{
"name": "Bread and Bakery",
"items": [
{
"name": "Baguette",
"price": 3.00
},
{
"name": "Pie",
"price": 5.00
},
{
"name": "Brownies",
"price": 2.50
}
]
},
{
"name": "Cheese",
"items": [
{
"name": "Feta Cheese",
"price": 7.54
},
{
"name": "Emental Cheese",
"price": 8.74
},
{
"name": "Swiss Cheese",
"price": 5.89
}
]
}
]
}
]
Am working on this project that require fetching items from a JSON file according to categories, when a particular subcategory is clicked, it should display only items from that subcategory but my code is working for only one subcategory but I don't know how to make it dynamic to work for every subcategory
$('#subcategory1').click(function() {
$.getJSON("list.json",
function(data) {
console.log(data);
let output = '';
$.each(data[0].subcategories[0].items, function(index, product) {
output += `
<div class="col-md-3">
<div class="items">
<div class='photo'>
<img src="${product.imagelink}">
</div>
<div class="info">
<h4>${product.name}</h4>
<h5>$${product.price}</h5>
</div>
<div class="info">
<p>
Add to cart
</p>
</div>
</div>
</div>
`;
});
$('#images').html(output);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="category1">
<li>Baby Care</li>
<li>Drug Store</li>
<li>Health and Personal Care</li>
<li>Household Supplies</li>
</ul>
There might be better ways to do what you are looking for. But you can give a try to check below things.
Changed your html to below
<ul id="category1">
<li>Baby Care</li>
<li>Drug Store</li>
<li>Health and Personal Care</li>
<li>Household Supplies</li>
</ul>
<div id="subItems"></div>
Changed your js code a bit to below
var selectedSubCategoryObj = null
$('#subcategory1').click(function() {
$.getJSON("list.json",
function(data) {
console.log(data);
let output = '';
selectedSubCategoryObj= $(this)
$.each(data[0].subcategories, function(index, product) {
if($(selectedSubCategoryObj)[0].innerHTML == product.name){
$.each(product.items, function(index, eachItem) {
output += `
<div class="col-md-3">
<div class="items">
<div class='photo'>
<img src="${eachItem.imagelink}">
</div>
<div class="info">
<h4>${eachItem.name}</h4>
<h5>$${eachItem.price}</h5>
</div>
<div class="info">
<p>
Add to cart
</p>
</div>
</div>
</div>
`;
})
$('#subItems').html(output);
}
});
});
});
Once cross check if its similar to what you are looking for.
i'm trying to sum up a couple of properties in an object.
I'm using a VueJS filter, in combination with the ES5 reduce function to add up the numbers to get a total.
Well, it's not working at this moment. Somebody care to help me out?
new Vue({
el: '.app',
data: {
products: [{
"pid": "37",
"pname": "Reprehenderit",
"price": "4.29",
"amount": "1"
}, {
"pid": "45",
"pname": "Sit",
"price": "1.00",
"amount": "4"
}, {
"pid": "67",
"pname": "Omnis",
"price": "7.00",
"amount": "2"
}],
}
});
Vue.filter('subtotal', function (list, key1, key2) {
return list.reduce(function(total, item) {
return total + item.key1 * item.key2
}, 0)
})
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<div class="app">
Product example: {{ products[0].pname }}
<br><br>
Total: {{ products | subtotal 'price' 'amount' }}
</div>
Looks like your event handler is being initialized after the vue is already constructed. If your events aren't attached when they're called they'll be ignored.
Also, you can't reference your object properties like that product.variable you'll need to use product[variable]
Vue.filter('subtotal', function (list, key1, key2) {
return list.reduce(function(total, item) {
return total + item[key1] * item[key2]
}, 0)
})
new Vue({
el: '.app',
data: {
products: [{
"pid": "37",
"pname": "Reprehenderit",
"price": "4.29",
"amount": "1"
}, {
"pid": "45",
"pname": "Sit",
"price": "1.00",
"amount": "4"
}, {
"pid": "67",
"pname": "Omnis",
"price": "7.00",
"amount": "2"
}],
}
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<div class="app">
Product example: {{ products[0].pname }}
<br><br>
Total: {{ products | subtotal 'price' 'amount' }}
</div>
You could get the value of key like this:
return total + item[key1] * item[key2]
Also, you should set the filter before the vue instance.
I have a list with items and have applied filter on those items by value from text box. I want to get new filtered list with parent and its children if parent has at least one filtered item.If doesn't, that parent should not be displayed.
For an example: If I enter "3D" in the text box I don't want to get "Day parts" and "Week parts" listed below as they don't have children anymore after filtering.
<div ng-controller="Ctrl">
<input type="text" data-ng-model="inputValue.name"/>
<ul data-ng-repeat="condition in conditions">
<div data-ng-click="setHeadingStatus(condition)">
<div>
{{condition.name}}
</div>
<li ng-repeat="item in condition.items | filter:inputValue">
<div class="custom-typeahead-list-title">{{item.name}}</div>
<div class="custom-typeahead-list-desc">{{item.description}}</div>
</li>
</div>
</ul>
function Ctrl($scope , $filter){
$scope.countryCode = 1;
$scope.conditions = [
{
"id": 1,
"name": "Experiences",
"expanded": false,
"items": [
{
"id": 1,
"name": "3D"
},
{
"id": 2,
"name": "Imax"
},
{
"id": 3,
"name": "D-Box"
},
{
"id": 4,
"name": "THX"
}
]
},
{
"id": 2,
"name": "Day parts",
"expanded": false,
"items": [
{
"id": 1,
"name": "Early Bird"
},
{
"id": 2,
"name": "Matinee"
},
{
"id": 3,
"name": "Last Night"
}
]
},
{
"id": 3,
"name": "Week parts",
"expanded": false,
"items": [
{
"id": 1,
"name": "Monday"
},
{
"id": 2,
"name": "Wednesday"
},
{
"id": 3,
"name": "Weekend"
}
]
}
]
}
Here is the example of it
http://jsfiddle.net/KJ3Nx/48/
You can put an ng-show on the div that displays each block, and set the expression to the filtered length;
<div data-ng-show="(condition.items | filter:inputValue).length > 0" data-ng-click="setHeadingStatus(condition)">
Updated fiddle