ES6: Can't Deconstruct inside a call constructor - javascript

I'm trying to use ES6 Deconstructing inside a class constructor but get an unknown token error. Here's an example:
// imports/server/a-and-b.js
class A {
constructor(id) {
// make MongoDB call and store inside this variable
let {
firstName: this._FirstName // => Throws here
} = CollectionName.findOne({userId: id});
}
}
export class B extends A {
constructor(id) {
super(id);
}
get FirstName() {
return this._FirstName;
}
}
// imports/server/test.js
import { B } from 'imports/server/a-and-b.js'
const b = new B('123')
const FirstName = b.FirstName;
The same deconstruction will work outside the class:
// another-test.js
// make MongoDB call and store inside this variable
let {
firstName: FirstName // works fine
} = CollectionName.findOne({userId: id});

Your syntax is incorrect. What you are trying to do is not possible. Assuming the findOne method is synchronous you need to do this:
constructor(id) {
// make MongoDB call and store inside this variable
let { firstName } = CollectionName.findOne({userId: id});
this._FirstName = firstName;
}

I found this can be done like so:
constructor(id) {
// make MongoDB call and store inside this variable
({ firstName: this._FirstName } = CollectionName.findOne({userId: id}));
}

Related

Why I got undefined variable?

I have class with property:
public requestLoadPersonal: Personal[] = [];
And one method:
private filterByGender(selectedValue: any): void {
console.log(this.requestLoadPersonal);
this.requestLoadPersonal = this.requestLoadPersonal.filter(
(p: Personal) => {
return selectedValue ? p.gender == selectedValue : true;
}
);
}
In constructor of class I have:
public filterFn = {
name: this.filterByGender
}
Why when I call function this.filterByGender from object filterFn by key. I got undefined message, why variable this.requestLoadPersonal is not available inside:
console.log(this.requestLoadPersonal); ?
Calling as:
this.filterFn['name']({...});
I tried to bind variable:
this.filterFn['name']({...}).bind(this.requestLoadPersonal);
In your constructor you should bind the function to this like this:
constructor() { this.filterFn = { name: this.filterByName.bind(this) }; }
Because just {name: this.filterByName} loses the this context, i.e.
filterByName has this context of some other instance.
However, I'd suggest you simplify everything and make it more straight-forward. Currently it's complex and thus, error-prone.

JSON to Javascript Class

I have a http request that gets this Json object from a nosql database:
let jsonBody = {
birthday : 1997,
firstname: 'foo',
lastname:'bar'
}
Then I want to load this information into the Student model:
class Student{
constructor(){
}
getFullname(){
return this.lastname+' '+this.firstname
}
getApproxAge(){
return 2018- this.birthday
}
}
Normally, I would add this method to this class:
fromJson(json){
this.studentId = json.studentId;
this.birthday = json.birthday;
this.firstname = json.firstname;
this.lastname = json.lastname;
}
I would use it as follow:
let student = new Student()
student.fromJson(jsonBody)
console.log(student.getFullname())
console.log(student.getApproxAge())
This works fine but my problem is I have: 100 proprieties in reality. Will I have to write all proprities one by one in the fromJson method?
And also, if a propriety name has change, let's say: lastname became LastName, I will have to fix it?
Is there a simpler way to just assign these values to the object student dynamically but keep all of its methods??
Something like this:
fromJson(json){
this = Object.assign(this, json) //THIS IS NOT WORKING
}
Just assign to an instance:
static from(json){
return Object.assign(new Student(), json);
}
So you can do:
const student = Student.from({ name: "whatever" });
Or make it an instance method and leave away the assignemnt:
applyData(json) {
Object.assign(this, json);
}
So you can:
const student = new Student;
student.applyData({ name: "whatever" });
It could also be part of the constructor:
constructor(options = {}) {
Object.assign(this, options);
}
Then you could do:
const student = new Student({ name: "whatever" });
And also, if a property name has changed, let's say: lastname became LastName, I will have to fix it?
Yes you will have to fix that.
There is no way in javascript to deserialize json into classes. So I wrote a library ts-serializable that solves this problem.
import { jsonProperty, Serializable } from "ts-serializable";
export class User extends Serializable {
#jsonProperty(String)
public firstName: string = ''; // default value necessarily
#jsonProperty(String, void 0)
public lastName?: string = void 0; // default value necessarily
#jsonProperty(Date)
public birthdate: Date = new Date(); // default value necessarily
public getFullName(): string {
return [
this.firstName,
this.lastName
].join(' ');
}
public getAge(): number {
return new Date().getFullYear() - this.birthdate.getFullYear();
}
}
const user: User = new User().fromJSON(json);
user.getFullName(); // work fine and return string
user.getAge(); // work fine and return number
// or
const user: User = User.fromJSON(json);
user.getFullName(); // work fine and return string
user.getAge(); // work fine and return number
The library also checks types during deserialization.

"new self()" equivalent in Javascript

I have a class like the following:
const Module = {
Example: class {
constructor(a) {
this.a = a;
}
static fromString(s) {
// parsing code
return new Module.Example(a);
}
}
}
This works so far, but accessing the current class constructor via the global name Module.Example is kind of ugly and prone to breaking.
In PHP, I would use new self() or new static() here to reference the class that the static method is defined in. Is there something like this in Javascript that doesn't depend on the global scope?
You can just use this inside the static method. It will refer to the class itself instead of an instance, so you can just instantiate it from there.
If you need to access the constructor from an instance function, you can use this.constructor to get the constructor without specifying its name.
Here's how:
const Module = {
Example: class Example {
constructor(a) {
this.a = a;
}
static fromString(s) {
// parsing code
return new this(s);
}
copy() {
return new this.constructor(this.a);
}
}
}
const mod = Module.Example.fromString('my str');
console.log(mod) // => { "a": "my str"
console.log(mod.copy()) // => { "a": "my str" }
console.log('eq 1', mod === mod) // => true
console.log('eq 2', mod === mod.copy()) // => false

ES6: Super class doesn't hold state

I'm trying to figure out what's going on here, as the Parent/Super class does not have data after the initial construction.
// imports/server/a-and-b.js
class A {
constructor(id) {
// make MongoDB call and store inside this variable
// ...
this._LocalVariable = FieldFromMongo;
console.log(`this._LocalVariable: ${this._LocalVariable}`); // => This has a good value, ie: 'Test'
}
get LocalVar() {
console.log(`this._LocalVariable: ${this._LocalVariable}`); // => This has a undefined value when called from child class
return this._LocalVariable;
}
}
export class B extends A {
constructor(id) {
super(id);
this.TEST = 'THIS IS A TEST';
}
get THE_Variable() {
console.log(`super.LocalVar: ${super.LocalVar}`); // => This has a undefined value when called
return super.LocalVar;
}
get GETTHEVAR() {
return this.TEST; // => This returns 'THIS IS A TEST'
}
}
// imports/server/factory.js
import { B } from 'imports/server/a-and-b.js';
class Factory {
constructor() {
this._factory = new Map();
}
BuildInstances(id, cls) {
let instance = this._factory.get(cls);
if (!instance) {
if (cls === 'B') {
instance = new B(id);
this._factory.set(cls, instance);
return instance;
}
}
else {
return instance;
}
}
}
export let OptsFactory = new Factory();
// imports/server/test.js
import { OptsFactory } from 'imports/server/factory.js'
const B = OptsFactory.BuildInstances(id, 'B');
const THE_Variable = B.THE_Variable; // => always undefined
const TEST = B.GETTHEVAR; // => Always returns 'THIS IS A TEST'
Why does class A not keeping state?
This is what I found:
class A {
constructor(id) {
// make MongoDB call and store inside this variable
// ...
this._LocalVariable = FieldFromMongo;
}
get LocalVar() {
return this._LocalVariable;
}
GetThatLocalVar() {
return this._LocalVariable;
}
}
export class B extends A {
constructor(id) {
super(id);
}
get Style1() {
// Reference to Parent get function
return super.LocalVar; // => This has a undefined value when called
}
get Style2() {
// Reference to Parent property
return super._LocalVariable; // => This has a undefined value when called
}
get Style3() {
// Reference to local Property that is declared in Parent
return this._LocalVariable; // => This works
}
get Style4() {
// Reference to Parent without the getter
return super.GetThatLocalVar(); // => This works
}
get GETTHEVAR() {
return this.TEST; // => This returns 'THIS IS A TEST'
}
}
So basically the thing that works is Style3 Style 4 work.

Angular 2 / ES6 / Filter an object object based on a property

I am calling two API to return objects of data. Than run through for each of them and search if it has a value.
I want to check if one of these obj has a vas value matches.
getdata(slug){
this._apiService.getPages().subscribe(data =>{
this.pageobj = data
console.log('this page obj',this.pageobj)
})
this._apiService.getPosts().subscribe(data =>{
this.postsobj = data;
console.log('this post obj',this.postsobj)
})
}
this.pageobj is an object
this.postsobj
in both responses they had a property 'slug'.
I would like to check if in this.postsobj or this.pageobj has an object that contains 'slug' == 'hello-word', if so to return me object and store in var this.content
UPDATE
export class PageSingleComponent implements OnInit {
page: Page;
pageobj:any;
postsobj:any;
pageobjCheck:any
postsobjCheck:any
pageSlug:any;
content =new Array<any>();
constructor( private _apiService: apiService, private route: ActivatedRoute ) { }
getdata(slug){
this._apiService.getPages().subscribe(data =>{
this.pageobj = data
this.content.push(_.filter(this.pageobj, { 'slug':' hello-world' }));
})
this._apiService.getPosts().subscribe(data =>{
this.postsobj = data;
this.content.push(_.filter(this.postsobj, { 'slug':' hello-world' }));
})
}
ngOnInit() {
this.route.params.forEach((params: Params) => {
// Get slug from the rout
let slug = params['pageslug'];
console.log('slug is catcheds', slug)
this.pageSlug = params['pageslug'];
this.getdata(slug)
// Run functions
//
});
}
}
I think you want to use Filter function.
In your callback function passed to map function you want to check whether your response object form array has slug property which is equal to 'hello world'. Your code will like like this:
var content = response.filter(obj => obj && obj.slug === 'hello-world');
I prefer using lodash as below,
this.content =new Array<any>();
this.content.push(_.filter(this.pageobj, { 'slug':' hello-world' });
this.content.push(_.filter(this.postsobj, { 'slug':' hello-world' });
Alternatively you can handle it in the service using takeWhile operator
getPages(){
return this.http.get(...)
.takeWhile(data=>{
if(data.slug ==== 'hello-world'){
return data;
}
})
}

Categories

Resources