angular foreach problems when adding new items - javascript

I have an angular application with Firebase. I want to change the value of an firebase item. Everytime the total KM changes it needs to be set to the right value. so this is my services:
countKm(){
this.totalKmRef = this.db.list(this.uid + '/rides');
this.totalKm$ = this.totalKmRef.valueChanges();
this.totalKm$.subscribe(res=> this.getAllRides(res));
}
getAllRides(res){
this.rides = res;
this.rides.forEach(ride =>{
this.uniqueRides.push(ride.km);
})
this.totalKm = this.uniqueRides.reduce(this.sum);
localStorage.setItem("totalKm", this.totalKm);
}
sum(a, b){
return a += b;
}
Now for some reason, when i add a ride everything is fine, but the second time everything goes wrong.
for example the first time the foreach runs i get (after firebase has already 5 items):
0{
0: 5,
1: 5,
2: 5,
3: 5,
4: 5,
}
After i run the foreach 1 time my object list is like this:
0{
0: 5,
1: 5,
2: 5,
3: 5,
4: 5,
5: 5,
}
After add a new value the second time and further the foreach does this:
0{
0: 5,
1: 5,
2: 5,
3: 5,
4: 5,
5: 5,
6: 5,
7: 5,
8: 5,
9: 5,
10: 5,
11: 5,
12: 5,
}
Is there some one who can help me? I think it's a wrong configuration in the foreach but can't find out where.
Thanks for you help!

this.uniqueRides.push(ride.km); is just pushing additional items into the array.
Either check to see if the ride is included .includes
this.rides.forEach(ride => {
if(!this.uniqueRides.includes(ride)) {
this.uniqueRides.push(ride.km);
}
})
or clear the array out every time. this.uniqueRides = []

Related

Problem with Mocha test when try to use the 'return' in the function

I am learning the Mocha test for js but have a weird problem an couldn't figure it out. Any big man can help me:
I do this test case:
it("remove all the number larger than 10", () => {
function filter(arr) {
return arr.filter(number => number < 11);
}
assert.equal(filter([1, 3, 3, 5, 10, 29, 3], [1, 3, 3, 5, 10, 3]));
});
But it returns undefined for that filter function, but when I remove the return keyword, it works fine:
it("remove all the number larger than 10", () => {
function filter(arr) {
arr.filter(number => number < 11);
}
assert.equal(filter([1, 3, 3, 5, 10, 29, 3], [1, 3, 3, 5, 10, 3]));
});
Can anyone can explain it to me?
Thanks
You've got a typo, your close paren ) for filter should be immediately after the first array instead of after both arrays.
Also, to compare arrays use assert.deepEqual instead of assert.equal:
it("remove all the number larger than 10", () => {
function filter(arr) {
return arr.filter(number => number < 11);
}
assert.deepEqual(filter([1, 3, 3, 5, 10, 29, 3]), [1, 3, 3, 5, 10, 3]); // SUCCESS
});
(The reason why it was passing when you removed the return keyword is that filter was being passed both arrays, then returning undefined. assert.equal was only being called with one argument so its second argument was implicitly undefined. Since undefined == undefined your test passed.)

AngularJS: How do I check if date exist in array and return id?

I'm trying to check if the current date exists in an array and return id which exists on the same index where date exists.
The below code is not working to check the element, I have already tried includes()
const results = [];
angular.forEach(getEventdate, function(value)
{
results.push({id:value.id,event_date:value.event_date}); });
if(results.some(result => result.event_date === current_date))
{
console.log('date exists!');
}
Sample array:
0: {id: 4, event_date: "2019-01-11"}
1: {id: 6, event_date: "2019-01-11"}
2: {id: 7, event_date: "2019-01-11"}
3: {id: 8, event_date: "2017-06-13"}
4: {id: 9, event_date: "2017-06-14"}
5: {id: 10, event_date: "2017-06-21"}
6: {id: 11, event_date: "2017-06-22"}
7: {id: 12, event_date: "2017-06-23"}
8: {id: 13, event_date: "2017-06-26"}
9: {id: 14, event_date: "2017-06-27"}
I need id if a current date exists in the array
With ES2015+ you can use find to get the id when it's found and undefined otherwise.
const { id } = values.find(item => item.event_date === currentDate) || {};
If you want get the very first occurrence of the date then try using find, or if you want all the occurrences matching the date then try using filter.
e.g. using find
const {id} = results.find(val=>{
return val.event_date === someDateString;
})
Filter will return array of all the occurrences matching that value.
const dates=results.filter(val=>{
return val.event_date === someDateString;
})
You can use $filter.
var d = new Date();
var filteredDate = $filter('date')(d, 'yyyy-M-d');
var foundId = (array.filter(function(item) {
return item.event_date === filteredDate;
})[0] || {}).id;
This will return undefined if the date is not found.
You will need to inject $filter into your controller.

Sonnification javascript only returning a single note

I have been trying to use a node.js script to turn some data into music. The script is only returning a single note for some reason:
The orignal script on github: https://github.com/wbkd/from-data-to-sound had res.concat(scribble.scale('c', but the threw an error Invalid Scale name.
const scribble = require('scribbletune');
// example data
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
const min = Math.min(...data);
const octaves = [...Array(5)].map((d, i) => i + 1); // [1, 2, 3, 4, 5]
// creates array of notes like 'c1', 'd1', 'e1', 'gb1', 'ab1', 'bb1', 'c2', ...
const notes = octaves.reduce((res, octave) =>
res.concat(scribble.scale('c1 major', 'whole tone', octave, false))
, []);
const midiData = scribble.clip({
notes: data.map(value => notes[value - min]),
pattern: 'x',
noteLength: '1/16',
});
// write the MIDI file 🎵🎵🎵
scribble.midi(midiData, 'data-sonification.mid');
From scribbletune doc:
each x implies a note on event
scribbletune docs/core/clip
Since you're passing only 1 'x' as a pattern in scribble.clip, it only plays 1 note. In order for all the notes to be played, you can try something like this:
const midiData = scribble.clip({
notes: data.map(value => notes[value - min]),
- pattern: 'x', // only play 1 note
+ pattern: 'x'.repeat(data.length), // repeat this pattern for each note in data
noteLength: '1/16',
});

Replace javascript swich statement

I have a switch in javascript that I need to put it different.
How can I write this in a better way to avoid the switch?
var types = {
Int: 2,
Short: 3,
Long: 4,
Double: 5,
Decimal: 6,
String: 1,
Guid: 10,
Variant: 11,
};
switch (data.columnTypeId) {
case types.String:
case types.Guid:
case types.Variant:
self.GetStrings(data);
break;
case types.Int:
case types.Decimal:
case types.Short:
case types.Long:
case types.Double:
self.GetNumbers(data);
break;
default:
}
What about doing the same map, but map a function reference instead?
var columnTypes = {
2: self.GetNumbers,
3: self.GetNumbers,
4: self.GetNumbers,
5: self.GetNumbers,
6: self.GetNumbers,
1: self.GetStrings,
10: self.GetStrings,
11: self.GetStrings,
0: self.GetDefault //Guessing the default value would be 0
};
columnTypes[data.columnTypeId](data);
or with a safe check:
if (columnTypes.indexOf(data.columnTypeId) !== -1) {
columnTypes[data.columnTypeId](data);
} else {
self.GetDefault(data);
}
Or as #dandavis pointed out in a comment:
columnTypes[data.columnTypeId || self.getDefault](data);

Javascript array indexed by string

I have the below javascript function I want to optimise for my web app.
function DisplayToolTip(str) {
switch (str) {
case "a":
this.tooltip(xvalue,yvalue,text);
break;
case "b":
this.tooltip(xvalue,yvalue,text);
break;
case "c":
this.tooltip(xvalue,yvalue,text);
break;
default: break;
}
}
The switch statement may change i.e. json may need to add in a case "d" but the function exists so dont know how to update the above.
Normally in c# I would use a dictionary, so key would be "a" and value would be an object with properties xvalue,yvalue,text or value would be a string "this.tooltip(xvalue,yvalue,text);".
This way I could update the dictionary and the execution speed of 'DisplayToolTip' would be relatively the same no matter how many elements.
How do you create an array of objects indexed or quickly found using a string value in javascript?
Objects in javascript are like dictionaries.
var dictionary = {
a : ["xvalue","yvalue","text1"],
b : ["xvalue","yvalue","text2"]
}
console.log(dictionary["b"][2]); // will give you text2.
Demo
EDIT: Updated answer to contain arrays (as that is what the question is).
You can use the switch statement itself, with fall-through:
switch (str) {
case "a": case "b": case "c":
this.tooltip(xvalue,yvalue,text);
break;
default: break;
}
(But, as Qantas commented, the default case isn't necessary here.)
Or, it the browser supports it, you can use the indexOf method of arrays:
if (["a", "b", "c"].indexOf(str)) ...
I would do something like this:
var tooltipSettings={
a: {xvalue: 1, yvalue: 1, text: 'string a'},
b: {xvalue: 2, yvalue: 2, text: 'string b'},
c: {xvalue: 3, yvalue: 3, text: 'string c'}
};
function DisplayToolTip(str) {
if(tooltipSettings[str])
{
var settings=tooltipSettings[str];
this.tooltip(settings.xvalue, settings.yvalue, settings.text);
}
}
You could use a dictionary, witch is basically an plain object.
Javascript allows you to access an object property by string like you would access an array property like this:
var obj = {
test: 'text',
b: 4
}
console.log(obj['test'], obj.test);
console.log(obj['b'], obj.b);
So your code would look like this:
var pairs = {
'a': {
xvalue: 1,
yvalue: 1,
text: '1111'
},
'b': {
xvalue: 2,
yvalue: 2,
text: '2222'
}
};
function DisplayToolTip(str) {
var prop = pairs[str];
if (typeof prop !== 'undefined')
return this.tooltip(prop.xvalue, prop.yvalue, prop.text);
throw 'undefined prop ' + str;
}

Categories

Resources