Many() relationships with same model in redux-orm - javascript

What I need is to model Member have a list of followers and followings.

You define the relation the same way you'd define it for non-self-referencing many-to-many.
class Follower extends Model {
static modelName = 'Follower';
static fields = {
id: attr(),
name: attr(),
followers: many('Follower','following')
};
}
const orm = new ORM();
orm.register(Follower);
const session = orm.session(orm.getEmptyState());
session.Follower.create({id: 1, name: 'f1'});
session.Follower.create({id: 2, name: 'f2'});
session.Follower.create({id: 3, name: 'f3', followers: [1,2]});
// returns ['f1', 'f2']
const f3Followers = session.Follower.withId(3).followers.toRefArray().map(f=>f.name);
// returns ['f3']
const f1Following = session.Follower.withId(1)!.following.toRefArray().map(f=>f.name);

Related

Assign object values to class values

so I've encountered a problem with assigning object values to class values. Basically, let's say that I have a class Account and an object with the same properties as the class
class Account {
id: Number;
name: String;
}
const accountObject = {
id: 4216,
name: "Test name"
}
const account = new Account();
//set values from accountObject to account as a class
account.id = accountObject.id;
//...
So is there a way to assign values from an object to a class without doing it manually? I have a lot of properties that I need to be assigned and doing it by hand would solve the issue but if there's a prettier way to do so, I'd really appreciate any help
A simple loop should do the trick:
class Foo {
name = "foo"
age = 1
}
const foo = new Foo()
const bar = {
name: "bar",
age: 100
}
for (let key in bar) {
foo[key] = bar[key]
}
console.log(foo) // prints Foo { name: 'bar', age: 100 }
console.log('----------------------------------');
Object.entries(bar).forEach(
([key, value]) => (foo[key] = value)
)
console.log(foo) // prints Foo { name: 'bar', age: 100 }
class Account {
constructor({
id,
name
}) {
this.id = id;
this.name = name;
}
}
const account = new Account({
id: 4216,
name: "Test name"
});
console.log(account);

how to assign merged type value to a sub type in javascript or typescript

I title is a littble bit wired I know that :(
I got 2 components, studentBasicComponent and studentContactorComponent. so for each component, I create models for data binding (the code I pasted is simplified, in face there are quite a few properties)
export default interface StudentBasic {
id: Number,
name: String,
birth: Date,
gender: String
}
export default interface StudentContactor {
name: String,
phone: String
}
export type Student = StudentBasic & StudentContactor;
Short question is:
If I have const student: Student = { ... }, how can I assign it to const basic:StudentBasic and const contractor:StudentContactor as simple as I can?
For detail, we retrieve data from the server with a single request, so what I get from the api is something like.
export default defineComponent({
components: {
"student-basic": studentBasicComponent,
"student-contactor": studentContactorComponent,
},
props: {
id: {
type: String,
required: true
},
}
setup(props) {
const studentBasicData: StudentBasic = reactive( {
id: 0,
name: "",
birth: moment(),
gender: "",
});
const contactor: StudentContactor = reactive({
name: "",
phone: "",
});
onMounted(async() => {
const data: Student = await getStudent(props.id);
// Here, how to assign value to studentBasicData and studentContactor
});
return {
studentBasicData,
studentContactor,
}
},
})
So after I get the whole data const data: Student = await getStudent(props.id); , how can I assign to studentBasicData and studentContactor?
I don't want to manually set value for each property by studentBasicData.name = data.name
(using Vue 3 + Typescript)

Update object array without adding new properties from another object

Is it possible to update only the existing property values of an object without adding new properties from another object?
Here is my example.
form = {name: '',email: ''};
data = {name: 'sample', email: 'sample#gmail.com', datofbirth: '6/2/1990' };
form = {...form, ...data};
console.log(form);
Result:
{"name":"sample","email":"sample#gmail.com","datofbirth":"6/2/1990"}
Expected Result:
{"name":"sample","email":"sample#gmail.com"}
I dont want the dateofbirth or any new property added on my form object.
Not sure this is what you want, hope it helps
const form = { name: '', email: '' };
const data = {
name: 'sample',
email: 'sample#gmail.com',
datofbirth: '6/2/1990',
};
Object.keys(form).forEach(key => {
if (data.hasOwnProperty(key)) {
form[key] = data[key];
}
});
console.log(form);
Only add the keys you want in the spread rather than the whole object
form = { ...form, name: data.name, email: data.email };
Iterate over all the keys in form and generate a new object using Object.assign and spread syntax.
const form = {name: '',email: ''},
data = {name: 'sample', email: 'sample#gmail.com', datofbirth: '6/2/1990' },
result = Object.assign(...Object.keys(form).map(k => ({[k] : data[k]})));
console.log(result);

How to load mobx state from json?

I want to store my mobx state in browser localStorage, so, if i use this approach https://stackoverflow.com/a/40326316
I save store with toJS, but don't know how to apply it. With extendObservable I get following error Error: [mobx] 'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead
Thanks in advance.
My approach is:
class MyStore {
...
public async load() {
const cached = await browser.storage.local.get("cache");
const data = JSON.parse(cached["cached"]);
Object.keys(data).forEach(x => {
(this as any)[x] = (data as any)[x];
});
...
}
But i think this is anitpattern.
Are you sure extendObservable doesn't work.
I've used something like this in my code.
class MyStore {
async load() {
const cached = await browser.storage.local.get("cache");
mobx.extendObservable(this, cached);
}
}
Edit:
This seems to be not working, you need to access the properties after extendObservable in order to reload them, you could use autorun but just use another method.
I've implemented load function based on a simple forEach;
Try the following.
load = async () => {
const { cache } = await JSON.parse(localStorage.getItem("cache"));
Object.keys(cache).forEach(key => {
this[key] = cache[key];
});
};
CodeSandbox
https://codesandbox.io/s/late-snow-xppx0?ontsize=14&hidenavigation=1&theme=dark
If you have a class, and "raw" json data, what i'm doing is to accept raw data in the constructor & then update the class properties.
For example, my raw data looks like this:
{
users: [
{ id: 1, firstName: 'foo', lastName: 'bar', customer: { id: 1, name: 'bla' } },
{ id: 2, firstName: 'foo2', lastName: 'bar2', customer: { id: 2, name: 'customer' } },
];
}
class User {
id;
#observable firstName;
#observable lastName;
customer;
constructor(rawUser) {
this.id = rawUser.id;
this.firstName = rawUser.firstName;
this.lastName = rawUser.lastName;
this.customer = new Customer(rawUser.customer);
}
}
class UsersStore {
#observable users = [];
constructor(rawUsers) {
this.users = rawUsers.map(rawUser => new User(rawUser));
}
}
Then when I'm restoring the data I'm just using
const usersStore = new UsersStore(rawData.users);
The cool thing in this approach is the nesting handling, each "level" handles its part.

Store data from new class instance in an array

I want to create 4 new users,
let JonSnow = new User({ id: 1, name: 'Jon Snow', status: Status.user });
let AryaStark = new User({ id: 2, name: 'Arya Star', status: Status.user });
let SansaStark = new User({ id: 3, name: 'Sansa Stark', status: Status.user });
let JoffreyBaretheon = new User({ id: 4, name: 'Joffrey Baretheon', status: Status.user });
In my User class I have a allUser function,
allUsers() {
let users: IUser[] = [];
let user: IUser = {
id: this.id,
name: this.name,
status: this.status
}
users.push(user);
users.forEach((user) => console.log(user));
return users;
}
If I call the the function like so,
JonSnow.allUsers();
AryaStark.allUsers();
SansaStark.allUsers();
JoffreyBaretheon.allUsers();
It calls the allUsers function 4 times, as expected.
How would I store all 4 new users into one array? So I would only need to call the function once to show all users?
You can have a module/namespace variable (don't export it so it won't be accessible from outside), like so:
let users: IUser[] = [
new User({ id: 1, name: 'Jon Snow', status: Status.user }),
new User({ id: 2, name: 'Arya Star', status: Status.user }),
new User({ id: 3, name: 'Sansa Stark', status: Status.user }),
new User({ id: 4, name: 'Joffrey Baretheon', status: Status.user })
]
and then you have a simple method:
allUsers(): IUser[] {
return users.slice(0);
}
Notice that I cloned the users array so that who ever gets a reference to it won't be able to change this inner array, but it's not a must.
But there's no real need to have this method in all classes, you can make it static.
But you can also then make this array a static member of the User class, so:
class User {
private static users: IUser[] = [];
constructor() {
User.users.push(this);
}
static allUsers(): IUser[] {
return User.users.slice(0);
}
}
The you can get all users: User.allUsers().
It seems like you are just trying to convert a bunch of User instances into a single array of IUser objects.
What I would do is provide a User class method that returns an IUser object:
public toIUser():IUser {
return {
id: this.id,
name: this.name,
status: this.status
}
}
Then simply map your instances using that function:
let allUsers = [JonSnow, AryaStark, SansaStark, JoffreyBaretheon].map(user => user.toIUser());
console.log("all users:", allUsers);
Playground example here.
PS: I would avoid using static variables as your solution.
Declare static User variable as an array:
User.users = []
In User constructor add the current object to the array:
User.users.push(this)
Then in allUsers return the array:
allUsers() {
return User.users
}

Categories