i'm strugling with counting and incrementing a number in a for. I'm using Angular 2, typescript, Ionic 2 and Firebase.
Here's the deal, i'm queryng something from firebase, since it's a object i can't use .length on it so i declared a counter: number = 0; in the top of my code and inside my snapshot.val() i'm incrementing it, but in the end when i do a console.log it's 0.
Here is my code (i've took away useless code to post here):
firebase.database().ref('MedicoPacientes/' + id).once('value', snapshot => {
for (var key in snapshot.val()) {
//PEGA TUDO DENTRO DO HISTORICO DE UM USUARIO QUE SEJA TRUE
historico.child(key).orderByChild('permissoes').equalTo(true).once('value', snap => {
for (var key in snap.val()) {
this.counter++;
//also tryed this.counter += 1 and this.counter = this.counter +1;
}
});
historico.child(key).orderByChild('permissoes/' + cpf).equalTo(id).once('value', snap => {
for (var key in snap.val()) {
this.counter++;
//also tryed this.counter += 1 and this.counter = this.counter +1;
}
})
}
})
So it's a for inside a for because i need to get a key before getting the registers i need to count.
Algo i'm saving this registers in a variable that is the object (it's the part i've took from the code to post here) and i also tryed iterating this object and incrementing it
in the start of my code i have:
export class MedicoAlertasPage {
counter: number = 0;
Does someone know what i'm doing wrong?
EDIT 1
Here is the complete page code:
export class MedicoAlertasPage {
paciente: any;
semHistorico: boolean;
limit: any;
counter: number = 0;
meuId: any;
contador: number = 15;
alertas: any[] = [];
alertasFiltrado: any[];
constructor(public navCtrl: NavController, public storage: Storage, public loading: LoadingController) {
}
//COPY THE VALUES TO USE IN THE FILTER
inicializaAlertas() {
this.alertasFiltrado = this.alertas;
}
//FILTER ON TYPING
filtraAcompanhamentos(ev: any) {
this.inicializaAlertas();
// set val to the value of the searchbar
let val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.alertasFiltrado = this.alertasFiltrado.filter((item) => {
return (item.nome.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
//LOAD USER HISTORY
ionViewWillEnter() {
let l = this.loading.create({ content: "Aguarde..." });
l.present();
this.storage.get('id').then(id => {
this.storage.get('cpf').then(cpf => {
let historico = firebase.database().ref('/Historico/');
firebase.database().ref('MedicoPacientes/' + id).once('value', snapshot => {
for (var key in snapshot.val()) {
//GET ALL THE DATA THAT IS TRUE
historico.child(key).orderByChild('permissoes').equalTo(true).once('value', snap => {
for (var key in snap.val()) {
this.counter++;
this.alertas.unshift({
chave: key,
data: Moment.unix(Number(key)).format('DD/MM/YYYY'),
hora: Moment.unix(Number(key)).format('HH:mm'),
descricao: snap.val()[key].descricao,
paciente: snap.val()[key].nome
});
}
});
//GET ALL DATA OF A SELECTED USER
historico.child(key).orderByChild('permissoes/' + cpf).equalTo(id).once('value', snap => {
for (var key in snap.val()) {
this.counter++;
this.alertas.unshift({
chave: key,
data: Moment.unix(Number(key)).format('DD/MM/YYYY'),
hora: Moment.unix(Number(key)).format('HH:mm'),
descricao: snap.val()[key].descricao,
paciente: snap.val()[key].nome
});
}
})
}
this.inicializaAlertas();
l.dismiss();
})
});
})
}
}
Change your code to this:
ionViewWillEnter() {
let l = this.loading.create({ content: "Aguarde..." });
l.present();
this.storage.get('id').then(id => {
this.storage.get('cpf').then(cpf => {
let historico = firebase.database().ref('/Historico/');
firebase.database().ref('MedicoPacientes/' + id).once('value', snapshot => {
for (var key in snapshot.val()) {
//GET ALL THE DATA THAT IS TRUE
historico.child(key).orderByChild('permissoes').equalTo(true).once('value', snap => {
for (var key in snap.val()) {
this.counter++;
this.alertas.unshift({
chave: key,
data: Moment.unix(Number(key)).format('DD/MM/YYYY'),
hora: Moment.unix(Number(key)).format('HH:mm'),
descricao: snap.val()[key].descricao,
paciente: snap.val()[key].nome
});
}
//GET ALL DATA OF A SELECTED USER
historico.child(key).orderByChild('permissoes/' + cpf).equalTo(id).once('value', snap => {
for (var key in snap.val()) {
this.counter++;
this.alertas.unshift({
chave: key,
data: Moment.unix(Number(key)).format('DD/MM/YYYY'),
hora: Moment.unix(Number(key)).format('HH:mm'),
descricao: snap.val()[key].descricao,
paciente: snap.val()[key].nome
});
}
this.inicializaAlertas();
l.dismiss();
})
});
}
})
});
})
}
Related
I want remove Data of table 'filter_object' with related table 'filter_link' bevor starting the action of button onClickSync().
The 'filter_link' table contains two foreign key : product_id and object_id.
I tried to delete the data by id in a for loop, but this only deletes the data from the 'filter_object' table without related product. In addition it slows down the deletion when I have several data. Could help me please ?
import template from './sw-vehicles-list.html.twig';
const { Component } = Shopware;
const { Criteria } = Shopware.Data;
Component.register('sw-vehicles-list', {
template,
inject: ['repositoryFactory'],
data() {
return {
repository: null,
showAddButton: true,
isLoading: false,
object: null,
};
},
metaInfo() {
return {
title: this.$createTitle()
};
},
computed: {
filterObjectRepository() {
return this.repositoryFactory.create('filter_object');
},
filterLinkRepository() {
return this.repositoryFactory.create('filter_link');
},
productRepository() {
return this.repositoryFactory.create('product');
},
},
created() {
this.object = this.repositoryFactory.create('filter_object');
this.link = this.repositoryFactory.create('filter_link');
},
methods: {
async onClickSync() {
this.isLoading = true;
await this.removeData();
this.repository.search(new Criteria(), Shopware.Context.api).then((result) => {
if (result.length) {
var i;
var manufacturer = [];
for (i = 0; i < result.length; i++) {
manufacturer.push(result[i]['manufacturer']);
}
var manufacturerFilter = Array.from(new Set(manufacturer));
var j;
for ( j = 0; j < manufacturerFilter.length; j++) {
// some code
}
}
});
},
removeData() {
return this.filterObjectRepository.search(new Criteria(), Shopware.Context.api).then((result) => {
if (result.length) {
var i;
for (i = 0; i < result.length; ++i) {
this.filterObjectRepository.delete(result[i]['id'], Shopware.Context.api).then(this.loadObject);
}
return null;
}
});
},
loadObject() {
this.filterObjectRepository.search(new Criteria(), Shopware.Context.api).then((result) => {
this.result = result;
});
},
}
});
You can use the syncDeleted method of the repository to delete multiple records.
const ids = result.map(record => record.id);
this.filterObjectRepository.syncDeleted(ids, Shopware.Context.api)
If you want filter_link records to be deleted when deleting records from filter_object you'll have to set the foreign keys ON DELETE subclause to CASCADE.
ALTER TABLE `filter_link`
DROP FOREIGN KEY `fk.filter_link.object_id`;
ALTER TABLE `filter_link`
ADD CONSTRAINT `fk.filter_link.object_id` FOREIGN KEY (`object_id`) REFERENCES `filter_object` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
Can someone explain, why I'm getting an error, when I'm removing items from an array? It works once, but then it crashes. Checked - is boolean meaning.
removeCards = () => {
console.clear();
for (let i = 0; i < this.state.cards.length; i++) {
console.log(this.state.cards[i]);
if (this.state.cards[i].checked) {
delete this.state.cards[i];
}
}
this.setState({ cards: this.state.cards });
};
In React, state is immutable. So instead of trying to alter it directly, create a copy of it and then apply that to state -
removeCards = () => {
console.clear();
const newCards = [];
for (let i = 0; i < this.state.cards; i++) {
if (!this.state.cards[i].checked) {
newCards.push(this.state.cards[i];
}
}
this.setState({ cards: newCards });
};
Maybe my trouble in that? That's how i'm chaning states from true to false and in reverse.
myFunc = (props) => {
let num = Number(props);
num--;
let cards = [...this.state.cards];
if (this.state.cards[num].checked) {
cards[num] = { ...cards[num], checked: false };
} else {
cards[num] = { ...cards[num], checked: true };
}
this.setState({ cards });
};
I am trying to create a clothing sales site, I am at the function which calculates the total of the products present in the cart at the localStorage level, but my function returns "null"
I really need help please...
here is the code:
constructor(private productService: ProductService,
private orderService: OrderService,
private httpClient: HttpClient,
private router: Router,
private spinner: NgxSpinnerService,
private toast: ToastrService) {
this.cartTotal$.next(this.cartDataServer.total);
this.cartDataObs$.next(this.cartDataServer);
let info: CartModelPublic = JSON.parse(localStorage.getItem('cart')!);
if (info !== null && info !== undefined && info.prodData[0].incart !== 0) {
// assign the value to our data variable which corresponds to the LocalStorage data format
this.cartDataClient = info;
// Loop through each entry and put it in the cartDataServer object
this.cartDataClient.prodData.forEach(p => {
this.productService.getSingleProduct(p.id).subscribe((actualProdInfo: ProductModelServer) => {
if (this.cartDataServer.data[0].numInCart === 0) {
this.cartDataServer.data[0].numInCart = p.incart;
this.cartDataServer.data[0].product = actualProdInfo;
this.CalculateTotal();
this.cartDataClient.total = this.cartDataServer.total;
localStorage.setItem('cart', JSON.stringify(this.cartDataClient));
} else {
this.cartDataServer.data.push({
numInCart: p.incart,
product: actualProdInfo
});
this.CalculateTotal();
this.cartDataClient.total = this.cartDataServer.total;
localStorage.setItem('cart', JSON.stringify(this.cartDataClient));
}
this.cartDataObs$.next({...this.cartDataServer});
});
});
}
}
AddProductToCart(id: number, quantity?: number) {
this.productService.getSingleProduct(id).subscribe(prod => {
// If the cart is empty
if (this.cartDataServer.data[0].product === undefined) {
this.cartDataServer.data[0].product = prod;
this.cartDataServer.data[0].numInCart = quantity !== undefined ? quantity : 1;
this.CalculateTotal();
this.cartDataClient.prodData[0].incart = this.cartDataServer.data[0].numInCart;
this.cartDataClient.prodData[0].id = prod.id;
this.cartDataClient.total = this.cartDataServer.total;
localStorage.setItem('cart', JSON.stringify(this.cartDataClient));
this.cartDataObs$.next({...this.cartDataServer});
this.toast.success(`${prod.name} added to the cart.`, "Product Added", {
timeOut: 1500,
progressBar: true,
progressAnimation: 'increasing',
positionClass: 'toast-top-right'
})
} // END of IF
// Cart is not empty
else {
let index = this.cartDataServer.data.findIndex(p => p.product.id === prod.id);
// 1. If chosen product is already in cart array
if (index !== -1) {
if (quantity !== undefined && quantity <= prod.quantity) {
// #ts-ignore
this.cartDataServer.data[index].numInCart = this.cartDataServer.data[index].numInCart < prod.quantity ? quantity : prod.quantity;
} else {
// #ts-ignore
this.cartDataServer.data[index].numInCart < prod.quantity ? this.cartDataServer.data[index].numInCart++ : prod.quantity;
}
this.cartDataClient.prodData[index].incart = this.cartDataServer.data[index].numInCart;
this.toast.info(`${prod.name} quantity updated in the cart.`, "Product Updated", {
timeOut: 1500,
progressBar: true,
progressAnimation: 'increasing',
positionClass: 'toast-top-right'
})
}
// 2. If chosen product is not in cart array
else {
this.cartDataServer.data.push({
product: prod,
numInCart: 1
});
this.cartDataClient.prodData.push({
incart: 1,
id: prod.id
});
this.toast.success(`${prod.name} added to the cart.`, "Product Added", {
timeOut: 1500,
progressBar: true,
progressAnimation: 'increasing',
positionClass: 'toast-top-right'
})
}
this.CalculateTotal();
this.cartDataClient.total = this.cartDataServer.total;
localStorage.setItem('cart', JSON.stringify(this.cartDataClient));
this.cartDataObs$.next({...this.cartDataServer});
} // END of ELSE
});
}
here is my CalculateTotal() function:
private CalculateTotal() {
let Total = 0;
this.cartDataServer.data.forEach(p => {
const {numInCart} = p;
const {price} = p.product;
// #ts-ignore
Total += numInCart * price;
});
this.cartDataServer.total = Total;
this.cartTotal$.next(this.cartDataServer.total);
}
and here is the result in the console:
I think it is because your const {numInCart} = p; in private CalculateTotal()
has a an object value
try changing const {numInCart} = p; to const {numInCart} = p.numInCart;
I would like to use a BehaviorSubject to store an Array of objects and have a way to easily update (next?) a single item of that array without having to update the whole array.
I would also like for an easy way to subscribe to changes to an specific item of that array. I know it could be done with filter, but an easier way would be nice...
Is that possible?
I am currently using this version I created (which I don't know if it is the best way or not) that also persists its contents to localstorage:
export class LocalStorageBehaviorSubject<T, Y = T> {
private _data: BehaviorSubject<T>;
public asObservable() {
return this._data.asObservable();
}
public next(data: T) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
localStorage.setItem(this.key, JSON.stringify(data));
this._data.next(data);
}
public nextItem(item: Y) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
if (dados.some(r => r[this.id] === item[this.id])) {
dados = dados.map(r => r[this.id] === item[this.id] ? item : r);
} else {
dados.push(item);
}
if(this.expirationFn !== null) {
dados = this.expirationFn(dados);
}
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeItem(id) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
dados = dados.filter(r => r[this.id] !== id);
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeExpiredData(){
let data = this.loadFromStorage();
if (data) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
this._data.next(data);
}
}
public getValue() {
this.removeExpiredData();
return this._data.getValue();
}
public getItem(id): Y {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
this.removeExpiredData();
return (<any>this._data.getValue()).slice().find(t => t[this.id] == id);
}
constructor(private key: string, private id: string, defaultValue: any = null, private expirationFn: (dados: T) => T = null) {
this._data = new BehaviorSubject<T>(defaultValue);
this.removeExpiredData();
}
private loadFromStorage(): T {
let dadosStr = localStorage.getItem(this.key);
if (dadosStr) {
return JSON.parse(dadosStr);
}
return null;
}
}
I hoped that would be an simpler way...
Thanks
I would also like for an easy way to subscribe to changes to an
specific item of that array. I know it could be done with filter, but
an easier way would be nice...
You can use map operator and inside lambda array.find
Example
const mockStorage = {
values: {},
setItem(key, value) {
this.values[key] = value;
},
getItem(key) {
return this.values[key]
},
clearItem(key) {
this.values[key] = undefined;
}
}
class LocalStorageBehaviorSubject {
constructor(key, defaultValue) {
this.key = key;
this._data = new rxjs.BehaviorSubject(defaultValue);
}
nextItem(item) {
const list = this._data.value;
const itemIndex = list.findIndex(pr => pr.id === item.id);
this._data.next([
...list.slice(0, itemIndex),
{
...(list[itemIndex] || {}),
...item
},
...list.slice(itemIndex + 1)
]);
}
removeItem(id) {
this._data.next(this._data.value.filter(pr => pr.id !== id));
}
getItem(id) {
return this.asObservable()
.pipe(
rxjs.operators.map(values => values.find(pr => pr.id === id) || null),
rxjs.operators.distinctUntilChanged());
}
asObservable() {
return this._data.asObservable().pipe(
rxjs.operators.tap(values => {
if (values && values.length) {
mockStorage.setItem(this.key, JSON.stringify(values));
}
else {
mockStorage.clearItem(this.key);
}
}))
}
}
const localStorageBehaviorSubject = new LocalStorageBehaviorSubject('items', []);
localStorageBehaviorSubject
.getItem(1)
.subscribe(item => {
console.log(item);
})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test'})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test1'})
localStorageBehaviorSubject.nextItem({id: 2, value: 'test2'})
localStorageBehaviorSubject.nextItem({id: 3, value: 'test3'})
localStorageBehaviorSubject.removeItem(2);
localStorageBehaviorSubject.removeItem(1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>
When I update 'classProficienciesChoices' in my state using setState() it is updating not only that property, but also where I derived the 'classProficienciesChoices' info from in the 'classSelected' property, AND ALSO from where I derived the classSelected info from in the 'classesInfo' property.
The same function I update 'classProficienciesChoices' I also update 'classProficiencies', and it updates properly in the one property I tell it to, and not the elements where the information was derived from.
Any insight would be helpful. The Create component has other components nested and none of them have state and only use props passed. There are navigation, selection, and information display components nested.
import React, { Component } from 'react'
import Create from './Create'
class App extends Component {
constructor(props) {
super(props);
const url = 'http://www.dnd5eapi.co/api/';
fetch(url + 'classes')
.then(result => result.json())
.then(result => { this.setState({ classes: result, }, this.getInfo(result)) });
}
state = {
classes: {}, //assigned value from API call in constructor
classesInfo: [], //assigned value from API call in getInfo()
classSelected: {}, //assigned a value derived from classInfo in displayClassInfo()
classProficiencies: [], //assigned a value derived from classSelected in setStartingProficiencies()
classProficienciesChoices: [], //assigned a value derived from classSelected in setStartingProficiencies()
}
getInfo(data) {
let info = []
const url = 'http://www.dnd5eapi.co'
for (var i = 0; i < data.results.length; i++) {
fetch(url + data.results[i].url)
.then(result => result.json())
.then(result => info.push(result))
}
this.setState({ classesInfo: info, })
}
}
setStartingProficiencies(chosenClass) {
const profs = chosenClass.proficiencies.map((prof) => {
return prof;
});
const proChoice = chosenClass.proficiency_choices.map((choices) => {
return choices;
});
this.setState({ classProficiencies: profs, classProficienciesChoices: proChoice, });
}
addProficiency = (proficiencyName) => {
const { classProficienciesChoices } = this.state
// classProficienciesChoices: [
// { choose: 2, type: 'proficiencies', from: [{ name: 'someName', url: 'someUrl' }, { name: 'someName', url: 'someUrl' }] },
// ]
// different classes have more objects in the parent array
let newChoiceArray = classProficienciesChoices.map((choices) => {
return choices
})
for (var i = 0; i < newChoiceArray.length; i++) {
for (var j = 0; j < newChoiceArray[i].from.length; j++) {
if (newChoiceArray[i].from[j].name === proficiencyName) {
let newChoices = newChoiceArray[i].from.filter(function (proficiency) { return proficiency.name !== pIndex })
let newProficiency = newChoiceArray[i].from.filter(function (proficiency) { return proficiency.name === pIndex })
newChoiceArray[i].from = newChoices //I think this is the problem
this.setState(state => ({
classProficiencies: [...state.classProficiencies, newProficiency[0]],
proficienciesChoices: newChoiceArray,
}))
}
}
}
}
displayClassInfo = index => {
const { classesInfo } = this.state
for (let i = 0; i < classesInfo.length; i++) {
if (classesInfo[i].index === index) {
const classSelected = classesInfo.filter(function (cClass) { return cClass.name === classesInfo[i].name })
this.setState({ classSelected: classSelected[0], isClassSelected: true }, this.setStartingProficiencies(classSelected[0]),)
break;
}
}
}
render() {
const { classes, classesInfo, classSelected, isClassSelected, classProficiencies, classProficienciesChoices } = this.state
return (<Create classes={classes} classesInfo={classesInfo} displayClassInfo={this.displayClassInfo} classSelected={classSelected} isClassSelected={isClassSelected} category='classes' classProficiencies={classProficiencies} classProficienciesChoices={classProficienciesChoices} addProficiency={this.addProficiency} />);
}
}
export default App
You call setState four times, of course it will update the state multiple times.
SOLVED!!! Stumbled across turning the array into a string and then back. It breaks the reference and creates an entirely new array. Reference type got me.
setStartingProficiencies(chosenClass) {
const proficiencies = JSON.parse(JSON.stringify(chosenClass.proficiencies))
const proficienciesChoices = JSON.parse(JSON.stringify(chosenClass.proficiency_choices))
this.setState({ classProficiencies: proficiencies, classProficienciesChoices: proficienciesChoices, });
}