RxJs getValue for nested BehaviorSubject object - nested

I'm working with angular 4 and RxJS 5, I have an object with the following structure (with nested subjects, in this example only 2 levels):
objs = BehaviorSubject<MyObj[]>;
MyObj = {
prop1: BehaviorSubject<string> = "prop1";
prop2: BehaviorSubject<string> = "prop2";
prop1.subscribe(newValue => prop2 = prop1);
}
So if I try to output the value of objs I got something like the following:
console.log(objs.value) =>
[
{
prop1: BehaviorSubject<string>;
prop2: BehaviorSubject<string>;
},
{
...
}]
so the result doesn't include the values of prop1 and prop2 but I still have BehaviorSubject at the second level.
Is there a way to get the nested objs value like the following?:
objs = [{
prop1: "prop1";
prop2: "prop2"
}, {...}]
I'm wondering if there's a sort of the knockout ko.toJSON (http://knockoutjs.com/documentation/plugins-mapping.html)
Do you think it is generally a bad practice to have nested BehaviorSubjects or people do it everyday :)?

No, there is nothing builtin that does that. You could certainly roll your own method. This might be something you can start with:
function isPrimitive(obj: any) {
return obj !== Object(obj);
}
function desubjectify(obj: any) {
if(isPrimitive(obj)) {
return obj;
}
if(obj instanceof BehaviorSubject) {
return desubjectify(obj.value);
}
let transformed: any = {};
for(let key of Object.keys(obj).filter(key => !key.startsWith('_'))) {
let value = obj[key];
if(value instanceof BehaviorSubject) {
transformed[key] = desubjectify(value.value);
} else {
transformed[key] = desubjectify(value);
}
}
return transformed;
}
Nested behavior subjects seems fishy to me but I wouldn't rule it out immediately with out knowing more details. However, I would recommend you find a good tutorial on ngrx/store and read it. Anytime people start to work a lot with behavior subjects I would recommend this.

Related

Property 'id' does not exist on type 'string | JwtPayload' [duplicate]

This is a situation I have ran into a couple of times, it seems like it should be fairly straightforward, but I can't find a solution that doesn't set the type to any
A function takes one of two different objects as the argument, checks which object has been received, and returns the corresponding field.
This is a simplified version of the problem, but the issue is that the two objects are only distinguishable by their properties(which have no overlap), and I can't access any of the properties, because they're not present on the other type.
type Obj1 = {
message: string
}
type Obj2 = {
text: string
}
const getText = (obj: Obj1 |obj2): string => {
if (obj.message) {
return obj.message
}
return obj.text
}
You have to narrow down the type. You can do so by using the in operator.
const getText = (obj: Obj1 | Obj2): string => {
if ("message" in obj) {
return obj.message
}
return obj.text
}
You can cast the object to either Obj1 or Obj2:
type Obj1 = {
message: string
}
type Obj2 = {
text: string
}
const getText = (obj: Obj1 | Obj2): string => {
if ((obj as Obj1).message) {
return (obj as Obj1).message
}
return (obj as Obj2).text
}
The real answer to this problem according to what the question owner asked is this
But there might be a time you are using your defined type with primitive type in this way the above solution is not going to work as the problem I faced
here is the situation
type Obj1 = {
message: string
}
const getText = (obj: Obj1 |string): string => {
if (obj.message) {
return obj.message
}
return obj.text
}
so this scenario the solution stated above would not be perfect for you, so you might need to use typeof ✌️
const getText = (obj: Obj1 | string): string => {
if (typeof obj !== 'string') {
return obj.message
}
return obj.text
}
I recommend typescript-is.
import { is } from 'typescript-is';
...
const getText = (obj: Obj1 | Obj2): string => {
if (is<Obj1>(obj)) {
return obj1.message;
}
return obj2.text;
};

NodeJS: Finding a Key that has the most key array matches in a string

I am trying to achieve a small amount of javascript code that is able to locate a key that contains another key with the most array element occurrences in a string. It's a little hard to explain but I have given an example below. I have tried several filters, finds, and lengthy code loops with no luck. Anything would help, thanks :)
const object = {
keyone: {
tags: ["game","video","tv","playstation"]
},
keytwo: {
tags: ["book", "sport", "camping", "out"]
}
};
const string = "This is an example, out playstaion, tv and video games are cool!";
// I am trying to locate the key that contains the most tags in a string.
// In this case the result I am looking for would be "keytwo",
// because it's tags have greater occurances inside the string (playstaion, tv, video, game/s).
This should do it, though you might want to consider adding keyword stemming.
const object = {
keyone: {
tags: ["game", "video", "tv", "playstation"]
},
keytwo: {
tags: ["book", "sport", "camping", "out"]
}
};
const string = "This is an example, out playstaion, tv and video games are cool!";
result = {}
for (const [key, value] of Object.entries(object)) {
result[key] = value.tags.reduce((acc, item) => (acc += (string.match(item) || []).length), 0)
}
console.log(result)
Result:
{ keyone: 3, keytwo: 1 }
Edit:
How to count:
let result_key;
let result_count = 0;
for (const [key, value] of Object.entries(object)) {
const result = value.tags.reduce((acc, item) => (acc += (string.match(item) || []).length), 0);
if(result > result_count) {
result_count = result;
result_key = key;
}
}
console.log(result_key, result_count)
Result:
keyone 3

Symbol to string with JSON.stringify

I need to convert a Symbol to string in order to create a unique key in Redis, but I can't.
I've already tried to use Object.toString(obj) and String(obj) but I get errors or [Object] results¡.
This is the controller
const name = req.params.name;
let obj;
obj.data.name = {
[Op.like]: '%' + name + '%'
};
}
This is redis controller where I use stringify. I use obj as a parameter.
const hashed = crypto.createHmac('sha256', secretHashKey)
.update(JSON.stringify(obj))
.digest('hex');
I expect an output based on my parameter 'obj' but now it's not getting it so I can't create unique keys for different values.
Maybe a little bit too late, but I hope that somebody else find this useful.
I was looking for something exactly as you: use with Sequelize in a Redis cache.
Mine is TypeScript, convert to JavaScript just by removing the typings.
export function JsonStringifyWithSymbols(object: any, clean?: boolean): string {
return JSON.stringify(object, (_, value) => {
if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
const props = [...Object.getOwnPropertyNames(value), ...Object.getOwnPropertySymbols(value)];
const replacement: Record<string, any> = {};
for (const k of props) {
if (typeof k === 'symbol') {
replacement[`Symbol:${Symbol.keyFor(k)}`] = value[k];
} else {
replacement[k] = value[k];
}
}
return replacement;
}
return value;
});
}
If you're meaning these Symbols you can't convert them to a string.
They're created to be unique and "unreversable", so you can use them also for keep more "secure" various properties or methods. Example:
const a = Symbol('a')
class Foobar {
constructor (_a) {
this[a] = _a
}
}
const foobar = new Foobar('aaa')
console.log(foobar) // output: Foobar { [Symbol(a)]: 'aaa' }
const fake = Symbol('a')
foobar[fake] = 'fake'
console.log(foobar) // output: Foobar { [Symbol(a)]: 'aaa', [Symbol(a)]: 'fake' }
You can't corrupt the original one, unless you have the original Symbol.
Another example (info about the JSON.stringify here):
const a = Symbol('a')
const foobar = {}
foobar[a] = 'aaa'
console.log(foobar) // output: { [Symbol(a)]: 'aaa' }
console.log(JSON.stringify(foobar)) // output: {}
const fake = Symbol('a')
foobar[fake] = 'fake'
console.log(foobar) // output: { [Symbol(a)]: 'aaa', [Symbol(a)]: 'fake' }
Hope these info will help you.

How to refer to parent object from a child method, in ES6?

I have an object with methods in it. I want one of the methods inmy obj to be able to use data in other nodes of my object;
myObj = {
state : { a:1, b:1},
addStuff: (x) => {
return state.a + x
}
}
myObj.addStuff(3)
what are the most elegant ways to do so? One way I know is to use the object name inside of it; return myObj.state.a + x
Are there better ways to accomplish the same? I did try both self and this inside the method but neither worked.
If the fat arrow is not the requirement don't use it.
myObj = {
state : { a:1, b:1},
addStuff: function(x) {
return this.state.a + x
}
}
myObj.addStuff(3)
or
myObj = {
state : { a:1, b:1},
addStuff(x) {
return this.state.a + x
}
}
console.log(myObj.addStuff(3))

Deeply nested data objects in multidimensional object

I have a multidimensional object and using Vue, I am trying to make the inner object reactive.
My object looks like this:
data() {
return {
myObject: {}
}
}
And the filled data looks like this:
myObject: {
1: { // (client)
0: "X", // (index) : (value)
1: "Y"
},
2: {
0: "A",
2: "B"
}
}
If I try using:
let value = "X";
let client = 1;
let index = 1;
let obj = {};
obj[client][index] = value;
this.myObject = Object.assign({}, this.myObject, obj);
It throws an error:
TypeError: Cannot set property '0' of undefined
And if I try below, it overwrites the initial values as it is initially setting the object to {}
let obj = {};
obj[index] = value;
let parentObj = {};
parentObj[client] = obj;
this.myObject = Object.assign({}, this.myObject, parentObj);
What is the proper way of adding the values to the multidimensional object?
In javascript, dim2Thing[1][1] = ... expressions require dim2Thing[1] to exist. This is why you get the error you mentioned. So you can do two expressions, which should work fine:
dim2Thing[1] = dim2Thing[1] || {}
dim2Thing[1][1] = otherThing
For the last block, you mention that it "overwrites the initial values"
I think what's actually happening here is just that Object.assign is not recursive. It only merges top-level keys. So if parentObj has a key that over-laps with this.myObj, then sub-keys will be lost.
Object.assign({ a: { b: 2} }, { a: { c: 3 } }) // returns { a: { c: 3 } }
This is what I interpret your code as trying to do - though I am unfamiliar with vue.js at this time, so I cannot assure it will have the desired result to your webpage:
let value = "X";
let client = 1;
let index = 1;
const newObj = Object.assign({}, this.myObject);
// if you have lodash _.set is handy
newObj[client] = newObj[client] || {}; // whatever was there, or a new object
newObj[client][index] = value
this.myObject = newObj
Just use an array, thats reactive by design.
If you need to get elements from the array in your template or anywhere just add a find method
// temp
late
<div v-for="(value, idx) in myArray">{{find(obj => obj.id === idx)}}</div>
methods: {
find (searchFunction) {
return this.myArray.find(searchFunction)
}
}

Resources