Is there a way to user pairs for Rxjs5? - rxjs5

Can not find Rx.Observable.pairs in Rxjs5,
what I need just convert an object into Observable and inspect the change for each property.
any ideas?
var a = { aa: "aa", bb: "bb" };
function pairs(obj) {
// List of object's key-value pairs
var keyValuePairs = Object.keys(obj).map(key => ({ key, value: obj[key] }));
// Convert to an Observable and return
return Rx.Observable.from(keyValuePairs);
}
var xxx = pairs(a);
xxx.subscribe(x => {
console.log(x);
})
a.aa = "mm";

You can accomplish this from scratch:
function pairs(obj) {
// List of object's key-value pairs
var keyValuePairs = Object.keys(obj).map(key => ({ key, value: obj[key]}));
// Convert to an Observable and return
return Rx.Observable.from(keyValuePairs);
}

Related

rxjs: subscribing to observable in map

My first observable returns an array of Persons. I want to update each person of that array with a list of clients from second observable. How do I do that? So far I have this:
const json: Person[] = [new Person('Alice'), new Person('Bob')];
const resultsObservable = new Observable<string[]>(subscriber => {
setTimeout(() => {
subscriber.next(['Client1', 'Client2', 'Client3']);
subscriber.complete();
}, 1000);
});
of(json).pipe(
switchMap( dataArray => {
return from(dataArray);
}),
map((x: Person) => {
resultsObservable.subscribe(r => {
x.clients = r;
});
return x;
}),
).subscribe(value => {
console.log(value);
});
}
Person:
export class Person{
name: string;
clients?: string[];
constructor(name: string) {
this.name = name;
}
}
But the problem is that return happens before the values are set, so at the end value of person.clients is undefined. How do I fix this? Or what is a better way to achieve what I'm trying to do?
Ok I think I found what I was looking for:
const result = persons.pipe(
mergeMap(p => resultsObservable.pipe(map(clients => {
p.clients = clients;
return p;
}))),
);
result.subscribe(p => console.log(p));

How can I capture all the values of the dropdown list in Cypress?

I have a dropdown box that displays the list of States. There are around 40 States in the list.
Every time when I scroll down the list, the List displays only 15 to 20 States at a time.
I want to capture all the values of the list and save them in the string array. And then check alphabet sorting.
How can I do it using Cypress? Currently, It captures only the top 15 items from the list.
This is my code:
const verifySortOrdering = (key: string) =>
getSingleSelectList(key).then(dropdown => {
cy.wrap(dropdown).click();
if (dropdown.length > 0) {
const selector = 'nz-option-container nz-option-item';
let NumOfScroll = 1;
const unsortedItems: string[] = [];
const sortedItems: string[] = [];
cy.get(selector).then((listItem) => {
while (NumOfScroll < 7) {
sortAndCheck(selector, unsortedItems, sortedItems);
if (listItem.length < 15) {
break;
}
NumOfScroll++;
}
});
}
});
const sortAndCheck = (selector: string, unsortedItems: any, sortedItems: any) => {
cy.get(selector).each((listItem, index) => {
if (index === 15) {
cy.wrap(listItem).trigger('mousedown').scrollIntoView().last();
}
unsortedItems.push(listItem.text());
sortedItems = unsortedItems.sort();
expect(unsortedItems, 'Items are sorted').to.deep.equal(sortedItems);
});
};
Here's a working example based off of what you provided. Added an additional check to ensure the list has the right amount of options. You may or may not want that. Deep copying the unsorted list so it doesn't get sorted due to a shallow copy. Added validations after the unsortedItems list gets built so we can validate once instead of for every item in the list.
var unsortedItems = new Array()
var expectedListCount = 32
cy.get('#myselect>option').should('have.length', expectedListCount)
.each(($el) => {
unsortedItems.push($el.text());
}).then(() => {
var sortedItems = [...unsortedItems]; // deep copy
sortedItems.sort();
expect(unsortedItems).to.deep.equal(sortedItems)
})
Another example based on your revised sample but I can't verify it without having a working example of your DDL. This builds up the unsortedItem list first and then does the comparison.
const verifySortOrdering = (key: string) =>
getSingleSelectList(key).then(dropdown => {
cy.wrap(dropdown).click();
if (dropdown.length > 0) {
const selector = 'nz-option-container nz-option-item';
let NumOfScroll = 1;
const unsortedItems: string[] = [];
const sortedItems: string[] = [];
cy.get(selector).then((listItem) => {
while (NumOfScroll < 7) {
unsortedListBuilder (selector, unsortedItems, sortedItems);
if (listItem.length < 15) {
break;
}
NumOfScroll++;
}
});
var sortedItems = [...unsortedItems];
sortedItems.sort();
expect(unsortedItems).to.deep.equal(sortedItems);
}
});
const unsortedListBuilder = (selector: string, unsortedItems: any, sortedItems: any) => {
cy.get(selector).each((listItem, index) => {
if (index === 15) {
cy.wrap(listItem).trigger('mousedown').scrollIntoView().last();
}
unsortedItems.push(listItem.text());
});
};

Angularfire2 & Firestore – retrieve all subcollection content for a collection list

I try to retrieve datas in a subcollection based on the key received on the first call.
Basically, I want a list of all my user with the total of one subcollection for each of them.
I'm able to retrieve the data from the first Payload, but not from pointRef below
What is the correct way to achieve that?
getCurrentLeaderboard() {
return this.afs.collection('users').snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data()
const id = a.payload.doc.id;
const pointRef: Observable<any> = this.afs.collection('users').doc(`${id}`).collection('game').valueChanges()
const points = pointRef.map(arr => {
const sumPoint = arr.map(v => v.value)
return sumPoint.length ? sumPoint.reduce((total, val) => total + val) : ''
})
return { id, first_name: data.first_name, point:points };
})
})
}
I tried to put my code in a comment, but I think it's better formated as a answer.
First you need subscribe your pointRef and you can change your code like this.
getCurrentLeaderboard() {
return this.afs.collection('users').snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data()
const id = a.payload.doc.id;
const pointRef: Observable<any> = this.afs.object(`users/${id}/game`).valueChanges() // <--- Here
const pointsObserver = pointRef.subscribe(points => { //<--- And Here
return { id, first_name: data.first_name, point:points };
})
})
}
....
//Usage:
getCurrentLeaderboard.subscribe(points => this.points = points);
And if you going to use this function alot, you should start to denormalize your data.

dc.numberDisplay showing count for single group, not count of number of groups

I have data that looks like this:
var records = [
{id: '1', cat: 'A'},
{id: '2', cat: 'A'},
{id: '3', cat: 'B'},
{id: '4', cat: 'B'},
{id: '5', cat: 'B'},
{id: '6', cat: 'C'}
];
I want to create a dc.numberDisplay that displays the count of the number of unique categories, 3 in the example data above (A, B, & C).
This is what I'm currently doing:
var ndx = crossfilter(data); // init crossfilter
// create dimension based on category
var categoryDimension = ndx.dimension(
function (d) {
return d.category;
}
);
// Group by category
var categoryGroup = categoryDimension.group();
var categoryCount = dc.numberDisplay('#category-count'); // An empty span
categoryCount
.group(categoryGroup)
.valueAccessor(
function (d) { return d.value; }
);
The problem is that the numberDisplay displays 2 instead of 3. When debugging, I found that when the valueAccessor is called, d is the count of the number of elements of category A instead of the count of the number of categories.
How can I solve this problem?
UPDATE: Thanks to Nathan's solution, here is a working code snippet (ES2016 style)
const categoryDimension = claims.dimension(
(d) => {
return d.cat;
}
);
const categoryGroup = categoryDimension.groupAll().reduce(
(p, v) => { // add element
const cat = v.cat;
const count = p.categories.get(cat) || 0;
p.categories.set(cat, count + 1);
return p;
},
(p, v) => { // remove element
const cat = v.cat;
const count = p.categories.get(cat);
if (count === 1) {
p.categories.delete(cat);
} else {
p.categories.set(cat, count - 1);
}
return p;
},
() => { // init
return {
categories: new Map()
};
});
categoryCount
.group(categoryGroup)
.valueAccessor(
(d) => {
return d.categories.size;
}
);
You will need to use groupAll() since the number-display only looks at the top group. Then provide custom reduce functions to track unique categories. Finally, when DC.js pulls the value from the top group (there is only one) - just return the number of categories (which is the number of keys in the p object).
var categoryGroup = categoryDimension.groupAll().reduce(
function (p, v) { //add
if(p[v.cat]) {
p[v.cat]++;
} else {
p[v.cat] = 1;
}
return p;
},
function (p, v) { //remove
p[v.cat]--;
if(p[v.cat] === 0) {
delete p[v.cat];
}
return p;
},
function () { //init
//initial p - only one since using groupAll
return {};
}
);
console.debug("groups", categoryGroup.value());
dc.numberDisplay('#category-count')
.group(categoryGroup)
.valueAccessor(
function (d) { return Object.keys(d).length; }
);

Filter Parse.Object properties that should get saved to the server

I have this Parse.Object that I want to save to the server, but I'd like to whitelist the attributes of this object that get saved.
Parse.Object.extend('someObject', {
defaults: {
foo: 1,
bar: 2,
computedProperty: function() {
return this.get('foo') + this.get('bar')
}
},
get: function(attr) {
var value = Parse.Object.prototype.get.call(this, attr)
return _.isFunction(value) ? value.call(this) : value
}
})
As you can see, this object has a computed property among its attributes. I would like to filter out the computedProperty when I save this Parse.Object. Is that possible?
So, we've figured out a way to filter the list of attributes that get saved.
If you wanna do it, you have to override a private, undocumented method on the Parse.Object called _getSaveJSON, so the complete model above would be:
Parse.Object.extend('someObject', {
defaults: {
foo: 1,
bar: 2,
computedProperty: function() {
return 1+2
}
},
get: function(attr) {
var value = Parse.Object.prototype.get.call(this, attr)
return _.isFunction(value) ? value.call(this) : value
},
_getSaveJSON: function() {
var model = this
var json = _.clone(_.first(this._opSetQueue))
Parse._objectEach(json, function(op, key) {
json[key] = op.toJSON();
});
var whitelistedAttributes = ['foo', 'bar']
return _.pick(json, whitelistedAttributes)
}
})

Resources