How to get favourite item from list item app . i am using ionic 4 . my json data added localstorage but not get added data properly.
favourite.service.ts
getAllFavoriteItems(){
return this.storage.get("object");
}
isFavorite(favorite) {
return this.getAllFavoriteItems().then(result => {
return result && result.indexOf(favorite) !== -1;
});
}
favoriteItem(favorite) {
return this.getAllFavoriteItems().then(result => {
if (result) {
result.push(favorite);
return this.storage.set("object", result, );
} else {
return this.storage.set("object", [favorite]);
}
});
}
unfavoriteItem(favorite) {
return this.getAllFavoriteItems().then(result => {
if (result) {
var index = result.indexOf(favorite);
result.splice(index, 1);
return this.storage.set("object", result);
}
});
}
favourite.page.ts
ngOnInit() {
this.storage.get("object").then((ids) => {
console.log( 'favouriteIds' ,ids)
this.favouriteIds = ids;
})
// this.favouriteIds = this.favoriteService.getAllFavoriteItems();
// console.log('favitems',this.favitems)
}
favourite.page.html
<ion-content no-padding color="secondary">
<ion-list>
<div class="main">
<ion-item *ngFor="let item of favouriteIds" [routerLink]="['/','details',item.id]"
class="item-native" (click)="showInterstitial()">
<ion-thumbnail slot="start">
<img [src]="item.thumnailUrl">
</ion-thumbnail>
<ion-label>{{item.title}}</ion-label>
<ion-label>{{item.id}}</ion-label>
</ion-item>
</div>
</ion-list>
</ion-content>
full list item in screenshot
Favourite list item in this , but not get properly favourite item
You need to parse it to JSON, once you retrieve from local storage,
this.favouriteIds = JSON.parse(ids);
Related
I am having a problem with ejs templates. I've already worked with it in another project and it worked but in this one it doesn't seem to work all it shows is a blank page and it does not render the cards with the passed data. Here is my "view products" route code and my html code for "viewproducts.ejs".
view products route:
app.get('/viewproducts', function (req, res) {
var names = [];
var prices = [];
var descriptions = [];
var product = [];
var length;
Product.find(function (err, products) {
if (err) {
console.log(err);
} else {
length = products.length;
names = products.map(function (i) {
return i.name;
});
prices = products.map(function (i) {
return i.price;
});
descriptions = products.map(function (i) {
return i.description;
});
}
for (var i = 0; i < length; i++) {
product.push({
name: names[i],
description: descriptions[i],
price: prices[i],
});
}
console.log(product);
});
res.render('viewproducts', { artisanproduct: product });
});
viewproducts.ejs
<body>
<% artisanproduct.forEach((product)=>{ %>
<div>
<div class="card-body">
<div class="row">
<div class="col-lg-3">
<img class="w-100"src="" alt="">
</div>
<div class="col-lg-9">
<h5 class="card-title"><%=product.name%></h5>
<p class="card-text"><%=product.description%></p>
</div>
</div>
<h2><%=product.price%><span>MAD</span></h2>
<button type="submit">BUY</button>
</form>
</div>
</div>
</div>
<%})%>
</body>
You are calling res.render() BEFORE you've collected any data for it. Product.find() is non-blocking and asynchronous. So, to use its result, your code has to be inside its callback or in a function you call from that callback. Change and simplify to this:
app.get('/viewproducts', function (req, res) {
Product.find(function (err, products) {
if (err) {
console.log(err);
res.sendStatus(500); // send error response
return;
}
const product = products.map(item => {
return {
name: item.name,
price: item.price,
description: item.description
};
});
res.render('viewproducts', { artisanproduct: product });
});
});
Summary of changes:
Move res.render() inside the Product.find() callback so it has access to that data.
Build product array in one .map() instead of many.
Send error response when there's an error.
Use const or let instead of var.
Remove unnecessary temporary arrays and temporary variables.
In my app, I have a list where the user can add to and delete elements from it. My problem is, when I click an element (it can be in the middle, at the end etc.), it deletes the first element of the list. And when I refresh the page, I can see the previously 'deleted' elements. Like I haven't deleted anything. Here is my code. What's wrong with it and how should I fix it?
HTML:
<button mat-icon-button>
<mat-icon (click)="deleteWorkItem(row)">block</mat-icon>
</button>
TS:
deleteWorkItem(row: IProduct, index: number) {
let supplierProduct: ISupplierProduct = {
Supplier: {
SupplierId: this.SupplierId
},
Product: {
ProductId: row.ProductId
}
};
this.confirmDialogRef = this._dialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
this.confirmDialogRef.componentInstance.confirmMessage = 'Ürünü silmek istiyor musunuz?';
this.confirmDialogRef.afterClosed().subscribe(result => {
if (result) {
this._service.update('Supplier/DeleteSupplierProduct', supplierProduct).subscribe(response => {
this._customNotificationService.Show('Ürün silindi', 'Tamam', 2);
});
let tempData = this.dataSource.data.slice(0);
tempData.splice(index, 1);
this.dataSource = new MatTableDataSource(tempData);
this.EditIndex = undefined;
this._products = this.dataSource.data;
this.ProductChange.emit(this._products);
}
});
}
You don't seem to pass index into deleteWorkItem method.
You need to declare a template variable within *ngFor as follows:
<div *ngFor="let row of data; let i = index">
...
<button mat-icon-button>
<mat-icon (click)="deleteWorkItem(row, i)">block</mat-icon>
</button>
</div>
I'm currently building an app with Vue.js and firebase and I'm trying to add a filter by tag functionality to my blog component.
I'm doing so:
matters () {
return this.$store.getters.loadedMatters
},
footprints () {
return this.$store.getters.loadedFootprints
},
filteredMatters: function () {
if (this.currentFilter === "all") {
return this.matters;
}
return this.matters.filter((matter) => {
for (let obj in matter.footprint) {
return matter.footprint[obj] === this.currentFilter;
}
});
}
It's working but only with the first string of the array which is stored under my blog post tag
<v-chip v-bind:class="{ active: currentFilter === 'all' }" v-on:click="setFilter('all')" color="primary" small class="mt-3">
All
</v-chip>
<v-chip v-for="footprint in footprints" :key="footprint" v-bind:class="{ active: currentFilter === footprint }" v-on:click="setFilter(footprint)" color="primary" small class="mt-3">
{{ footprint }}
</v-chip>
When I console.log(matter.footprint) I get all arrays from all posts instead of getting the array of the selected post.
return this.matters.filter((matter) => {
console.log(matter.footprint)
for (let obj in matter.footprint) {
return matter.footprint[obj] === this.currentFilter;
}
});
log:
(3) ["Nature", "Ecosystems", "Ecology"]
Matter.vue?9a91:136 ["Writings"]
Matter.vue?9a91:136 ["Chips"]
Matter.vue?9a91:136 ["Analogy"]
Matter.vue?9a91:136 (2) ["Ecology", "Humanitarian"]
Matter.vue?9a91:136 ["Media Interaction Design"]
Matter.vue?9a91:136 Glacier
Matter.vue?9a91:136 ["Bugs"]
Matter.vue?9a91:136 ["Design thinking"]
Matter.vue?9a91:136 undefined
Matter.vue?9a91:136 ["nature"]
Matter.vue?9a91:136 (2) ["arduino", "open source"]
Matter.vue?9a91:136 ["Intelligence Collective"]
What am I doing wrong?
Thank you for your help.
I was inspired by this thread How to filter posts in Vue with components and v-bind:class
filteredMatters: function () {
if (this.currentFilter === "all") {
return this.matters;
}
return this.matters.filter((matter) => {
let footprint = []
for (let obj in matter.footprint) {
footprint.push(matter.footprint[obj])
}
return footprint.some(item => item === this.currentFilter)
});
}
Sorry for my English. I am trying to pre select those checkboxes whos values have been saved in the database. I did it using javascript in vuejs but those selected checkboxes values are not storing in array.
My code is like
role.component.js
getRoleRowData(data) {
this.roleaction = "edit";
this.addrolemodal = true;
console.log(data.role_id);
axios
.post(apiUrl.api_url + "getRolePermissionData", {
role_id: data.role_id
}).then(
result => {
this.permid = result.data;
var list = [];
result.data.forEach(function(value) {
list.push(value.perm_id);
});
var options = list;
for (var i = 0; i < options.length; i++) {
if (options[i]) document.querySelectorAll('input[value="' + options[i] + '"][type="checkbox"]')[0].checked = true;
}
},
error => {
console.error(error);
}
);
this.addrole = data;
},
And role.component.html
<div class="col-md-8">
<b-form-fieldset>
<div class="form" id="demo">
<h6>Permissions</h6>
<span v-for="perm_name_obj in listPermissionData">
<input type="checkbox" class="perm_id" v-bind:value="perm_name_obj.perm_id" name="perm_id" id="perm_name" v-model="checkedPerm_Id"> {{perm_name_obj.perm_name}}<br>
</span>
<span>Checked names: {{ checkedPerm_Id }}</span>
</div>
</b-form-fieldset>
</div>
And the Output
And the Ouput I got
In simple words I want to pre check checkboxes in vuejs of which values are stored in database.
See the following example, using simulation data
var app = new Vue({
el: '#app',
data () {
return {
listPermissionData: [],
checkedPerm_Id: []
}
},
created () {
setTimeout(_=>{
//Here simulates axois to request Permission data
this.listPermissionData = [
{perm_id:1,perm_name:'perm_name1'},
{perm_id:2,perm_name:'perm_name2'},
{perm_id:3,perm_name:'perm_name3'},
{perm_id:4,perm_name:'perm_name4'},
{perm_id:5,perm_name:'perm_name5'}
];
//Here simulates axois to request Selected Permissions (result.data)
var selected = [
{perm_id:2,perm_name:'perm_name2'},
{perm_id:5,perm_name:'perm_name5'}
]
this.checkedPerm_Id = selected.map(o=>o.perm_id)
},1000)
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<div class="form">
<h6>Permissions</h6>
<span v-for="perm_name_obj in listPermissionData">
<input type="checkbox" class="perm_id" v-bind:value="perm_name_obj.perm_id" name="perm_id" id="perm_name" v-model="checkedPerm_Id"> {{perm_name_obj.perm_name}}<br>
</span>
<span>Checked names: {{ checkedPerm_Id }}</span>
</div>
</div>
I solved my problem, here is my code
role.component.js
getRoleRowData(data) {
this.roleaction = "edit";
this.addrolemodal = true;
console.log(data.role_id);
let tempthis = this;
axios
.post(apiUrl.api_url + "getRolePermissionData", {
role_id: data.role_id
}).then(
result => {
this.permid = result.data;
var list = [];
result.data.forEach(function(value) {
//by using tempthis variable we provided the current access to the checkedPerm_Id array which not accessible from out of the function which is getRoleRowData
tempthis.checkedPerm_Id.push(value.perm_id);
list.push(value.perm_id);
});
},
error => {
console.error(error);
}
);
this.addrole = data;
},
I'm still debating the approach but this is what I have so far. The filters work great but the data list is over 2k items, so some sort of limit is going to need to be applied. The issue is that any limit to the view would have to require a new API pull with any filter being set by any methods I've tried.
My question is should I somehow paginate from the API call or pull all data and paginate with vue? Should I perhaps filter in the backend and apply different API calls or should I use what I have below? The filtering works nicely but I am not clear how I could limit whats displayed yet filter through the entire list then return.
My Vue app and components:
Vue.component('filter', {
props: ['list', 'name'],
template: '#filter-template',
watch: {
selected: function(currentValue) {
this.$dispatch('filter-update', [this.name, currentValue]);
}
}
});
Vue.component('products', {
template: '#product-template',
created() {
this.fetchProducts();
},
data:function(){
return {
products:[],
category: 'All',
collection: 'All',
design: 'All'
}
},
events: {
'push-category': function(id) {
this.category = id;
this.filterProducts();
},
'push-collection': function(id) {
this.collection = id;
this.filterProducts();
},
'push-design': function(id) {
this.design = id;
this.filterProducts();
}
},
computed: {
total: function () {
return this.products.length;
}
},
methods: {
fetchProducts: function() {
this.$http.get('api/internal/products', function(products) {
this.$set('products', products);
});
},
filterProducts: function() {
var parent = this;
var catFilter = [];
var collFilter = [];
var designFilter = [];
// Collect all the bad guys
if(this.category == 'All') {
catFilter = [];
} else {
var key = 'Item_Disc_Group';
filter(key, this.category, catFilter);
}
if(this.collection == 'All') {
collFilter = [];
} else {
var key = 'Collection';
filter(key, this.collection, collFilter);
}
if(this.design == 'All') {
designFilter = [];
} else {
var key = 'Fancy_Color_Intensity';
filter(key, this.design, designFilter);
}
// Hide all the bad guys, show any good guys
for (var i = this.products.length - 1; i >= 0; i--) {
var product = this.products[i];
if(catFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else if(collFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else if(designFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else {
product.On_The_Web = "1";
}
};
function filter(key, active, array) {
for (var i = parent.products.length - 1; i >= 0; i--) {
var product = parent.products[i];
if(product[key] != active) {
array.push(product);
}
};
}
}
}
});
new Vue({
el: '#product-filter',
created() {
this.fetchCategories();
this.fetchCollections();
this.fetchDesigns();
},
methods: {
fetchCategories: function() {
this.$http.get('api/categories', function(categories) {
this.$set('categories', categories);
});
},
fetchCollections: function() {
this.$http.get('api/collections', function(collections) {
this.$set('collections', collections);
});
},
fetchDesigns: function() {
this.$http.get('api/designs', function(designs) {
this.$set('designs', designs);
});
}
},
events: {
'filter-update': function(data) {
if(data[0] == "categories") {
this.$broadcast('push-category', data[1]);
} else if (data[0] == "collections") {
this.$broadcast('push-collection', data[1]);
} else {
this.$broadcast('push-design', data[1]);
}
}
}
});
My markup:
<div id="product-filter">
<filter :list="categories" name="categories"></filter>
<filter :list="collections" name="collections"></filter>
<filter :list="designs" name="designs"></filter>
<div class="clearfix"></div>
<products></products>
<!-- Vue Templates -->
<template id="filter-template">
<div class="form-group col-md-2">
<label>#{{ name }}</label>
<select v-model="selected" class="form-control input-small">
<option selected>All</option>
<option value="#{{ option.navision_id }}" v-for="option in list">#{{ option.name }}</option>
</select>
<span>Selected: #{{ selected }}</span>
</div>
</template>
<template id="product-template">
<div class="row mix-grid thumbnails">
<h1>#{{ total }}</h1>
<div v-for="product in products" v-if="product.On_The_Web == '1'" class="col-md-3 col-sm-6 mix category_1">
<a href="/products/#{{ product.id }}">
<div class="mix-inner">
<img class="img-responsive" src="https://s3-us-west-1.amazonaws.com/sg-retail/images/products/#{{ product.No }}.jpg" alt="">
<div class="prod-details">
<h3>#{{ product.No }}</h3>
<p></p>
<span class="price"></span>
</div>
</div>
</a>
<div class="prod-ui">
</div>
</div>
</div>
</template>
</div>
If the query takes more than a few seconds I would implement the server side filtering, but really thats preference for you. If you go with client-side filters, you can use the built in filterBy filter:
<div v-for="product in products | filterBy category in 'Item_Disc_Group' | filterBy collection in 'Collection' | filterBy design in 'Fancy_Color_Intensity'">
Just make the default value '' instead of All so that if no filter is selected then the list won't be filtered at all.
<option value="" selected>All</option>
Then you can also use a pagination filter to further page the results (borrowed from this fiddle):
data:function(){
return {
currentPage: 0,
itemsPerPage: 1,
resultCount: 0
}
},
computed: {
totalPages: function() {
return Math.ceil(this.resultCount / this.itemsPerPage)
}
},
methods: {
setPage: function(pageNumber) {
this.currentPage = pageNumber
}
},
filters: {
paginate: function(list) {
this.resultCount = list.length
if (this.currentPage >= this.totalPages) {
this.currentPage = this.totalPages - 1
}
var index = this.currentPage * this.itemsPerPage
return list.slice(index, index + this.itemsPerPage)
}
}
That would be added last after the filtering:
<div v-for="product in products | filterBy category in 'Item_Disc_Group' | filterBy collection in 'Collection' | filterBy design in 'Fancy_Color_Intensity' | paginate">
You'd also want to add buttons to support pagination, ie:
<ul>
<li v-repeat="pageNumber: totalPages">
{{ pageNumber+1 }}
</li>
</ul>