Rxjs plus minus button with min max and not negative values - rxjs5

How to avoid negative value ?
I've tried with filter but
if the value becomes negative
you should click twice to get
it positive.
const start = 0;
const min = 0;
const max = 3
var plus$ = Observable.fromEvent(this.getNativeElement(this.btnPlus), 'click');
var minus$ = Observable.fromEvent(this.getNativeElement(this.btnMinus), 'click');
var plusOrMinus$ = Observable.merge(plus$.mapTo(1), minus$.mapTo(-1));
plusOrMinus$
.scan((acc,curr) => acc+curr, start)
.filter(x => x > min)
.subscribe(x => console.log(x));
and if I wanted add a max value ?
UPDATE
This do the work for min
it's a little messy ^^
const start = 0;
const min = 0;
const max = 3
const plus$ = Observable.fromEvent(this.getNativeElement(this.btnPlus), 'click');
const minus$ = Observable.fromEvent(this.getNativeElement(this.btnMinus), 'click');
const plusOrMinus$ = Observable.merge(plus$.mapTo(1), minus$.mapTo(-1));
plusOrMinus$
.scan((acc,curr) =>{
if(acc === start){
if(curr > 0){
return acc+curr;
}
}
if(acc > start){
return acc+curr;
}
else{
throw new Error('0 value');
}
},
start)
.catch((e,obs)=> obs.startWith(0))
.subscribe(x => console.log(x));

If i understand your question correctly you want to prevent your inputs (+1/-1) from letting the total go out of bound (min, max). To do so you can use Math.min(nextVal, max) and Math.max(nextVal, min). Combined you will end up with Math.max(Math.min(nextVal, max), min). Next is using this in your .scan() function.
const incStream = Rx.Observable.fromEvent(document.getElementById('button_inc'), 'click').mapTo(1);
const decStream = Rx.Observable.fromEvent(document.getElementById('button_dec'), 'click').mapTo(-1);
const min = 0;
const max = 3;
Rx.Observable.merge(incStream, decStream)
.scan((acc, curr) => Math.max(Math.min(acc + curr, max), min), 0)
.startWith(0)
.distinctUntilChanged()
.subscribe(val => document.getElementById('result').value = val);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.3/Rx.js"></script>
<input type='button' value='+1' id='button_inc' />
<input type='button' value='-1' id='button_dec' />
<input type='text' id='result' />
The .startWith(0) is used to have a 0 value emitted to the stream before your first scan value arrives. .distinctUntilChanged() is used to not update the result with the same value (for instance when reaching max when using +1 multiple times).

Related

Filter & Delete rows of data based off of column value fast! (Google Sheets)

Is there a way to filter the data in column Q off my google sheet faster then reading line one by one. There is daily about 400+ lines it needs to scan through and I need to delete every row of data if the data in column Q is less than 1 right now watching it, it takes about 10+ minutes.
function UpdateLog() {
var returnSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('CancelRawData');
var rowCount = returnSheet.getLastRow();
for (i = rowCount; i > 0; i--) {
var rrCell = 'Q' + i;
var cell = returnSheet.getRange(rrCell).getValue();
if (cell < 1 ){
returnSheet.deleteRow(i);
}
}
{
SpreadsheetApp.getUi().alert("🎉 Congratulations, your data has been updated", SpreadsheetApp.getUi().ButtonSet.OK);
}
}
Try it this way:
function UpdateLog() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const vs = sh.getDataRange().getValues();
let d = 0;
vs.forEach((r, i) => {
if (!isNaN(r[16]) && r[16] < 1){
sh.deleteRow(i + 1 - d++);
}
});
}
This is a bit quicker
function UpdateLog() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const vs = sh.getDataRange().getValues().filter(r => !isNaN(r[16]) && r[16] < 1);
sh.clearContents();
sh.getRange(1,1,vs.length,vs[0].length).setValues(vs);
}

EventListener wont recognise new buttons

I have only started js recently, so i hope this makes sense..
I have made a simple dynamic form which starts with a table of 4 rows. After the heading row, the remaining 3 rows have +/- symbols which are to add or delete rows as necessary.
The add row functionality is currently working, however, even after assigning the correct class to the new row, the event listener wont work for the new buttons (even thought i have re-assigned the number of buttons within that class).
After adding the row, i re-assign btnAddRows and when logged to the console it is increasing with each row added. I can't figure out why it wont get captured in the for loop?
Thanks
//select elements on DOM
let btnAddRows = document.querySelectorAll('.btnADD');
let myTable = document.querySelector('#SecProp');
let myTableRows = document.querySelector('.tableRows');
for (let i = 0; i < btnAddRows.length; i++) {
btnAddRows[i].addEventListener('click', function () {
console.log(btnAddRows.length);
btnAddRows = document.querySelectorAll('.btnADD');
const rowNum = Number(btnAddRows[i].id.slice(6));
// console.log(rowNum);
// if (rowNum === myTableRows.length - 1) {
// addTableRow(rowNum);
// } else {
addTableRow(rowNum);
// }
btnAddRows = document.querySelectorAll('.btnADD');
myTable = document.querySelector('#SecProp');
myTableRows = document.querySelector('.tableRows');
});
}
const addTableRow = function (rowNum) {
//insert row into table
const addRw = myTable.insertRow(rowNum + 1);
const newRow = myTable.rows[rowNum + 1];
newRow.className = 'tableRows';
console.log(myTable.rows[rowNum + 1], typeof myTable.rows[rowNum + 1]);
const cell1 = newRow.insertCell(0);
const cell2 = newRow.insertCell(1);
const cell3 = newRow.insertCell(2);
const cell4 = newRow.insertCell(3);
const cell5 = newRow.insertCell(4);
cell1.className = 'column1';
cell2.className = 'coordsColumn';
cell3.className = 'coordsColumn';
cell4.className = 'buttons';
cell5.className = 'buttons';
cell1.innerHTML = `<td> ${rowNum + 1}</td>`;
cell2.innerHTML = '<td ><input type = "text" name="" value = ""/><td>';
cell3.innerHTML = '<td ><input type = "text" name="" value = ""/><td>';
cell4.innerHTML = `<td ><button class="btnADD btn btn-success" id="btnADD${
rowNum + 1
}"> + </button>`;
cell5.innerHTML = `<td ><button id="btnDEL${
rowNum + 1
}" class="btnDEL btn btn-success"> -</button>`;
};

Calculating total in cypress

I am trying to calculate the total price in the following way. However, when I log the total value at the bottom, I always get 0 logged.
I wish to store total in a variable so I can use it later on to compare values.
let total = 0;
cy.get('[cy-data="order-summary-products-product"]').each(
($product, index, $list) => {
const productQuantity = $product.attr("cy-data-product-quantity");
const productPrice = $product.attr("cy-data-product-price");
total += productPrice * productQuantity;
cy.wrap($product)
.find('[cy-data="order-summary-products-modifier"]')
.each(($modifier, index2, $list2) => {
const modifierQuantity = $modifier.attr("cy-data-modifier-quantity");
const modifierPrice = $modifier.attr("cy-data-modifier-price");
total += modifierPrice * modifierQuantity;
});
}
);
cy.log(total) //Always get 0 logged
Cypress has a env() method that you can use globally to store whatever you need.
Cypress.env('totalQuantity') = 0;
cy.get('[cy-data="order-summary-products-product"]').each(
($product, index, $list) => {
const productQuantity = $product.attr("cy-data-product-quantity");
const productPrice = $product.attr("cy-data-product-price");
Cypress.env('totalQuantity') += productPrice * productQuantity;
cy.wrap($product)
.find('[cy-data="order-summary-products-modifier"]')
.each(($modifier, index2, $list2) => {
const modifierQuantity = $modifier.attr("cy-data-modifier-quantity");
const modifierPrice = $modifier.attr("cy-data-modifier-price");
Cypress.env('totalQuantity') += modifierPrice * modifierQuantity;
});
});

Play and Pause interval rxjs

i'm trying to implement play and pause button using Rxjs library.
const play$ = fromEvent(playerImplementation, PLAYER_EVENTS.PLAY).pipe(mapTo(true));
const pause$ = fromEvent(playerImplementation, PLAYER_EVENTS.PAUSE).pipe(mapTo(false));
const waiting$ = fromEvent(playerImplementation, PLAYER_EVENTS.WAITING).pipe(mapTo(false));
let counterTime = 0;
const currentTime$ = interval(30).pipe(
map(()=>counterTime += 30));
const player$ = merge(play$, pause$, waiting$).pipe(
switchMap(value => (value ? currentTime$ : EMPTY)));
// DIFFERENCE IN RESULTS
currentTime$.subscribe((v)=> console.log("Regular Count " + v)); // get correctly 30,60,90,120...
player$.subscribe((v)=>console.log("Condition Count" + v)); // get wrongly 30,150,270, 390
can anyone help in understanding why there is a difference between the results?
It happened because I used several subscribers for one observable (player$ observable). I solve this by using ReplaySubject instead of Observable and by using multicasting in order to handle the event in several subscribers, without changing the value.
const play$ = fromEvent(playerImplementation, PLAYER_EVENTS.PLAY).pipe(mapTo(true));
const pause$ = fromEvent(playerImplementation, PLAYER_EVENTS.PAUSE).pipe(mapTo(false));
const waiting$ = fromEvent(playerImplementation, PLAYER_EVENTS.WAITING).pipe(mapTo(false));
let timeCounter = 0;
const source = Observable.create((obs : Observer<number>)=> {
interval(30).pipe(
map(() => timeCounter += 30)).subscribe(obs);
return () => {};
});
// Cast the observable to subject for distributing to several subscribers
const currentTime$ = source.pipe(multicast(()=> new ReplaySubject(5))).refCount();
const player$ = merge(play$, pause$, waiting$).pipe(
switchMap(value => value ? currentTime$ : EMPTY));

Animation doesn't show steps-in-between

I have created a simple function that would "animate" the cell backcolor at a tap, it works perfectly fine:
Color nOldColor = _grid.BackgroundColor;
for (int i = 0; i <= 100; i += 5)
{
double f = (double)i / (double)100;
Color nNewColor = PCLHelper.BlendColors(nOldColor, Color.Red, f);
_grid.BackgroundColor = nNewColor;
_label1.BackgroundColor = nNewColor;
await Task.Delay(5);
}
_grid.BackgroundColor = nOldColor;
_label1.BackgroundColor = nOldColor;
Now I wanted to do the same with an Animation, but the animation doesn't show the steps "in-between" but rather (as it looks to me) switches to the final color:
private async void animateButtonTouched()
{
int repeatCountMax = 100;
Color nOldColor = _grid.BackgroundColor;
var repeatCount = 0;
_grid.Animate("changeBG", new Animation((val) =>
{
double f = (double)repeatCount / (double)100;
Color nNewColor = PCLHelper.BlendColors(nOldColor, Color.Red, f);
_grid.BackgroundColor = nNewColor;
_label1.BackgroundColor = nNewColor;
}),
5, //duration. I've also tried it with 100. Nothing helped
finished: (val, b) =>
{
repeatCount++;
}, repeat: () =>
{
return repeatCount < repeatCountMax;
});
What am I doing wrong?
"You are making it more difficult than it needs to be." Trademark pending 🍣
The Animate callback is providing the stepping value (or keyframe value). This is a double from 0 to 1 that is called ever X milliseconds (i.e. the length of a single animation frame, 16 default) over the course of X milliseconds (250 default).
So in this example the ShiftToColor gets called 125 times (2000 / 16) with a value that is evenly divided from 0 to 1, thus steps of .008.
var orgColor = aFormsElementInstance.BackgroundColor;
aFormsElementInstance.Animate("changeBG", new Animation((val) =>
{
Color ShiftToColor(Color From, Color To, double pct)
{
var r = From.R + ((To.R - From.R) * val);
var g = From.G + ((To.G - From.G) * val);
var b = From.B + ((To.B - From.B) * val);
return new Color(r, g, b);
}
Device.BeginInvokeOnMainThread(() =>
{
aFormsElementInstance.BackgroundColor = ShiftToColor(orgColor, Color.Red, val);
});
}), 16, 2000);
Results in:

Resources