how to call attributes of more than one class in js - javascript

I am studying oojs and I have here the summary of the classes, to demonstrate the problem. Because the classes are large with many attributes and validations. I need the book class to receive the attributes of the Author class (name) and the Category class (category), but in my test I get undefined for my imports in the Book class. What could I have done wrong? I appreciate the help!
class author
export default class Author {
constructor(name){
this.name = name;
}
set name (name){
if(name === '')
throw new Error (`this field cannot be empty`)
this._name = name;
}
get name (){
return this._name;
}
}
class category
export default class Category {
constructor(category){
this.category = category;
}
set category (category){
if(category === '')
throw new Error (`this field cannot be empty`)
this._category = category;
}
get category (){
return this._category;
}
}
class book
import Author from './Author.js'
import Category from './Category.js'
export default class Book{
constructor(name, title, category){
this.name = name;
this.title = title;
this.category = category;
}
set name(name){
if(name instanceof Author)
this._name = name;
}
set category(category){
if(category instanceof Category)
this._category = category;
}
set title (title){
if(title === ' ')
throw new Error (`this field cannot be empty`)
this._title = title;
}
get name(){
return this._name;
}
get category(){
return this._category;
}
get title(){
return this._title;
}
}
test
import Book from './Book.js';
try{
const newBook = new Book(' Anne', 'Design UX/UI', 'Design');
console.log(`saved ${newBook.name} ${newBook.title} ${newBook.category}`)
}catch(err){
console.log(`err ${err}`)
}
//saved undefined Design UX/UI undefined

The arguments to new Book() need to be instances of the Author and Category classes, not strings. So you have to do:
const author = new Author('Anne');
const cat = new Category('Design');
const newBook = new Book(author, 'Design UX/UI', cat);
And when you're printing the properties, you need to access their name properties as well.
console.log(`saved ${newBook.name.name} ${newBook.title} ${newBook.category.category}`)
Alternatively, you could define toString() methods in the other classes:
export default class Author {
constructor(name){
this.name = name;
}
set name (name){
if(name === '')
throw new Error (`this field cannot be empty`)
this._name = name;
}
get name (){
return this._name;
}
toString() {
return this.name;
}
}
export default class Category {
constructor(category){
this.category = category;
}
set category (category){
if(category === '')
throw new Error (`this field cannot be empty`)
this._category = category;
}
get category (){
return this._category;
}
toString() {
return this.category;
}
}

Related

Use setter to validate parameter in constructor

Javascript
Can setter used to validate parameter when creating new object, as seen on this code, the string input on numberOfStudents bypass the setter
class School {
constructor(name, level, numberOfStudents) {
this._name = name;
this._level = level;
this._numberOfStudents = numberOfStudents;
}
get numberOfStudents() {
return this._numberOfStudents;
}
set numberOfStudents(value) {
if (isNaN(value)) {
console.log('Invalid input: numberOfStudents must be set to a Number.');
} else {
return (this._numberOfStudents = value);
}
}
}
const primaryOne = new School('Primary One', 'L1', 'ten');
prints
School { _name: 'Primary One', _level: 'L1', _numberOfStudents: 'ten' }
Please help
You're bypassing the validation because you're assigning to the internal _numberOfStudents property. The setter is only run when you assign to numberOfStudents. So change the constructor to do that:
class School {
constructor(name, level, numberOfStudents) {
this._name = name;
this._level = level;
this.numberOfStudents = numberOfStudents;
}
get numberOfStudents() {
return this._numberOfStudents;
}
set numberOfStudents(value) {
if (isNaN(value)) {
console.log('Invalid input: numberOfStudents must be set to a Number.');
} else {
this._numberOfStudents = value;
}
}
}
const primaryOne = new School('Primary One', 'L1', 'ten');

Want to delete the relation from the relation tree but i dont know where i am wrong

help me out in deleting particular relation
Person=Alex Relation=Brothers
Expected Output should be
Brothers=John,Joe
Husband=Bern Wife=Julia
The application should add Julia as a spouse for Bern.
now i want to delete the relation between Bern and wife julia and i am not able to do
Person=Bern Relation=Wife
Should return output as:
Wife=Julia
$ run_application
Input: Husband=Bern Wife=Julia
Output: Welcome to the family, Julia!
Input: Person=Bern Relation=Wife
Output: Wife=Julia
import java.util.*;
import java.util.stream.Collectors;
class Person {
private String name;
private Gender gender;
private List<Relation> relations = new ArrayList<>();
Person(String name, Gender gender) {
this.name = name;
this.gender = gender;
}
public String getName() {
return name;
}
public List<Relation> getRelations() {
return relations;
}
public Gender getGender() {
return gender;
}
public void addRelation(Relation relation) {
relations.add(relation);
}
public void deleteRelation(Relation relation) {
relations.remove(relation);
}
}
class Relation {
private TreeRelationType type;
private Person person1;
private Person person2;
Relation(TreeRelationType type, Person person1, Person person2) {
this.type = type;
this.person1 = person1;
this.person2 = person2;
}
public TreeRelationType getType() {
return type;
}
public Person getPerson2() {
return person2;
}
}
enum TreeRelationType {
SPOUSE, PARENT, CHILD
}
enum Gender {
MALE, FEMALE
}
enum RelationType {
FATHER, MOTHER, BROTHER, SON,GRANDCHILDREN, DAUGHTER, AUNT, HUSBAND, WIFE
}
class InvalidInputException extends Exception {
static final long serialVersionUID = -3387516993334229948L;
public InvalidInputException(String message) {
super(message);
}
}
public class FamilyTree {
private Person root;
private Map<String, Boolean> visted = new HashMap<>();
private Gender fetchGender(RelationType type) {
if(RelationType.MOTHER.equals(type)||RelationType.DAUGHTER.equals(type)|| RelationType.WIFE.equals(type))
return Gender.FEMALE;
else
return Gender.MALE;
}
private TreeRelationType fetchTreeRelationType(RelationType type) {
if (RelationType.MOTHER.equals(type) || RelationType.FATHER.equals(type))
return TreeRelationType.CHILD;
else if (RelationType.HUSBAND.equals(type) || RelationType.WIFE.equals(type))
return TreeRelationType.SPOUSE;
else
return TreeRelationType.PARENT;
}
public void addPerson(String name1, RelationType type1, String name2, RelationType type2)
throws InvalidInputException {
TreeRelationType relationType1 = fetchTreeRelationType(type1);
TreeRelationType relationType2 = fetchTreeRelationType(type2);
Gender gender1 = fetchGender(type1);
Gender gender2 = fetchGender(type2);
if (this.root == null) {
Person person1 = new Person(name1, gender1);
Person person2 = new Person(name2, gender2);
this.root = person1;
addRelation(relationType1, person1, relationType2, person2);
} else {
Person person1 = findPerson(this.root, name1);
if (person1 == null) {
throw new InvalidInputException("Invalid Input");
}
Person person2 = new Person(name2, gender2);
addRelation(relationType1, person1, relationType2, person2);
if (TreeRelationType.CHILD.equals(relationType1)) {
for (Relation relation : person1.getRelations()) {
if (TreeRelationType.SPOUSE.equals(relation.getType())) {
person1 = relation.getPerson2();
break;
}
}
deleteRelation(relationType1, person1, relationType2, person2);
}
}
}
public void deleteperson(String name1, RelationType type1, String name2, RelationType type2)
throws InvalidInputException {
TreeRelationType relationType1 = fetchTreeRelationType(type1);
TreeRelationType relationType2 = fetchTreeRelationType(type2);
Gender gender1 = fetchGender(type1);
Gender gender2 = fetchGender(type2);
Person person1 = findPerson(this.root, name1);
if (person1 == null) {
throw new InvalidInputException("Invalid Input");
}
Person person2 = findPerson(this.root, name2);
if (person2 == null) {
throw new InvalidInputException("Invalid Input");
}
deleteRelation(relationType1, person1, relationType2, person2);
if (TreeRelationType.CHILD.equals(relationType1)) {
for (Relation relation : person1.getRelations()) {
if (TreeRelationType.SPOUSE.equals(relation.getType())) {
person1 = relation.getPerson2();
break;
}
}
addRelation(relationType1, person1, relationType2, person2);
}
}
private Person findPerson(Person cur, String name) {
this.visted.put(cur.getName(), Boolean.TRUE);
if (cur.getName().equals(name)) {
this.visted.clear();
return cur;
} else {
for (Relation relation : cur.getRelations()) {
Person person2 = relation.getPerson2();
if (!visted.containsKey(person2.getName())) {
Person person = findPerson(person2, name);
if (person != null) {
return person;
}
}
}
}
return null;
}
private void addRelation(TreeRelationType type1, Person person1, TreeRelationType type2, Person person2) {
Relation relation1 = new Relation(type1, person1, person2);
person1.addRelation(relation1);
Relation relation2 = new Relation(type2, person2, person1);
person2.addRelation(relation2);
}
private void deleteRelation(TreeRelationType type1, Person person1, TreeRelationType type2, Person person2) {
Relation relation1 = new Relation(type1, person1, person2);
person1.deleteRelation(relation1);
Relation relation2 = new Relation(type2, person2, person1);
person2.deleteRelation(relation2);
}
private List<Person> fetchChildren(String name) throws InvalidInputException {
List<Person> children = new ArrayList<>();
Person person = findPerson(this.root, name);
if (person == null) {
throw new InvalidInputException("Invalid Input");
}
for (Relation relation : person.getRelations()) {
if (TreeRelationType.CHILD.equals(relation.getType())) {
children.add(relation.getPerson2());
}
}
return children;
}
private List<Person> fetchParents(String name) throws InvalidInputException {
List<Person> parents = new ArrayList<>();
Person person = findPerson(this.root, name);
if (person == null) {
throw new InvalidInputException("Invalid Input");
}
for (Relation relation : person.getRelations()) {
if (TreeRelationType.PARENT.equals(relation.getType())) {
parents.add(relation.getPerson2());
}
}
return parents;
}
private Person fetchFather(String name) throws InvalidInputException {
Person father = null;
List<Person> parents = fetchParents(name);
for (Person person : parents) {
if (Gender.MALE.equals(person.getGender()))
father = person;
}
return father;
}
private Person fetchMother(String name) throws InvalidInputException {
Person mother = null;
List<Person> parents = fetchParents(name);
for (Person person : parents) {
if (Gender.FEMALE.equals(person.getGender()))
mother = person;
}
return mother;
}
private List<Person> fetchSiblings(String name) throws InvalidInputException {
List<Person> siblings = new ArrayList<>();
Person father = fetchFather(name);
if (father != null) {
List<Person> children = fetchChildren(father.getName());
for (Person person : children) {
if (!person.getName().equals(name)) {
siblings.add(person);
}
}
}
return siblings;
}
private List<Person> fetchBrothers(String name) throws InvalidInputException {
List<Person> brothers = new ArrayList<>();
List<Person> siblings = fetchSiblings(name);
for (Person person : siblings) {
if (Gender.MALE.equals(person.getGender())) {
brothers.add(person);
}
}
return brothers;
}
private List<Person> fetchGrandChildren(String name) throws InvalidInputException {
List<Person> children = fetchChildren(name);
List<Person> grandChildren = new ArrayList<>();
for (Person person : children) {
grandChildren.addAll(fetchChildren(person.getName()));
}
return grandChildren;
}
private List<Person> fetchAunts(String name) throws InvalidInputException {
List<Person> aunts = new ArrayList<>();
List<Person> parents = fetchParents(name);
for (Person person : parents) {
List<Person> siblings = fetchSiblings(person.getName());
for (Person sibling : siblings) {
if (Gender.FEMALE.equals(sibling.getGender())) {
aunts.add(sibling);
} else {
Optional<Person> spouce = Optional.ofNullable(fetchSpouce(sibling.getName()));
if (spouce.isPresent()) {
aunts.add(spouce.get());
}
}
}
}
return aunts;
}
private Person fetchSpouce(String name) throws InvalidInputException {
Person spouce = null;
Person person = findPerson(this.root, name);
if (person == null) {
throw new InvalidInputException("Invalid Input");
}
for (Relation relation : person.getRelations()) {
if (TreeRelationType.SPOUSE.equals(relation.getType())) {
spouce = relation.getPerson2();
break;
}
}
return spouce;
}
public static void main(String args[]) throws InvalidInputException {
FamilyTree tree = new FamilyTree();
tree.addPerson("Dilshada", RelationType.MOTHER, "Laraib", RelationType.SON);
tree.addPerson("Dilshada", RelationType.WIFE, "Mushtaq", RelationType.HUSBAND);
tree.addPerson("Dilshada", RelationType.MOTHER, "Laieba", RelationType.DAUGHTER);
tree.addPerson("Mushtaq", RelationType.FATHER, "Farheen", RelationType.DAUGHTER);
tree.addPerson("Mushtaq", RelationType.BROTHER, "Ashraf", RelationType.BROTHER);
tree.addPerson("Ashraf", RelationType.HUSBAND, "Kulsum", RelationType.WIFE);
tree.addPerson("Mushtaq", RelationType.SON, "Nani", RelationType.MOTHER);
Scanner sc = new Scanner(System.in);
int choice;
do{
System.out.println("1. Add Relation\n2. View Relation\n3. Delete Relation\n4. Exit\n");
System.out.println("Enter Your Choice");
choice = sc.nextInt();
switch (choice) {
case 1:
try {
System.out.println("Enter The {name1}={relationtype1} {name2}={relationtype2}");
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
String inputString = sc.nextLine();
if (!inputString.isEmpty()) {
String[] input = inputString.split(" ");
String name1 = input[0].split("=")[1];
String name2 = input[1].split("=")[1];
RelationType type1 = RelationType.valueOf(input[0].split("=")[0].toUpperCase());
RelationType type2 = RelationType.valueOf(input[1].split("=")[0].toUpperCase());
tree.addPerson(name1, type1, name2, type2);
System.out.println("Welcome to the family, " + name2 + "!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
break;
case 2:
try {
System.out.println("Enter The {name} {relationtype}");
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
String inputString = sc.nextLine();
System.out.println(inputString);
if (!inputString.isEmpty()) {
String[] input = inputString.split(" ");
String relation = input[1];
String name = input[0];
String value = relation.toUpperCase();
if (value.charAt(value.length() - 1) == 'S') {
value = value.substring(0, value.length() - 1);
}
RelationType relationType = RelationType.valueOf(value);
switch (relationType) {
case FATHER:
Optional<Person> father = Optional.ofNullable(tree.fetchFather(name));
if (father.isPresent()) {
System.out.println(relation + "=" + tree.fetchFather(name).getName());
}
break;
case MOTHER:
Optional<Person> mother = Optional.ofNullable(tree.fetchMother(name));
if (mother.isPresent()) {
System.out.println(relation + "=" + tree.fetchMother(name).getName());
}
break;
case BROTHER:
System.out.println(relation + "=" + tree.fetchBrothers(name).stream()
.map(Person::getName).collect(Collectors.joining(",")));
break;
case GRANDCHILDREN:
System.out.println(relation + "=" + tree.fetchGrandChildren(name).stream()
.map(Person::getName).collect(Collectors.joining(",")));
break;
case AUNT:
System.out.println(relation + "=" + tree.fetchAunts(name).stream().map(Person::getName)
.collect(Collectors.joining(",")));
break;
case WIFE:
Optional<Person> spouce = Optional.ofNullable(tree.fetchSpouce(name));
if (spouce.isPresent()) {
System.out.println(relation + "=" + tree.fetchSpouce(name).getName());
}
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
break;
case 3:
try {
System.out.println("Enter The {name1}={relationtype1} {name2}={relationtype2}");
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
String inputString = sc.nextLine();
if (!inputString.isEmpty()) {
String[] input = inputString.split(" ");
String name1 = input[0].split("=")[1];
String name2 = input[1].split("=")[1];
RelationType type1 = RelationType.valueOf(input[0].split("=")[0].toUpperCase());
RelationType type2 = RelationType.valueOf(input[1].split("=")[0].toUpperCase());
System.out.println(name1 +" "+name2+" "+type1+" "+type2);
tree.deleteperson(name1, type1, name2, type2);
System.out.println("Deleted from the family, " + name2 + "!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
break;
case 4:
System.out.println("Existing");
break;
}
}while(choice !=4);
}
}
help me in correcting case 3 in main method of deleting relation

TypeScript generics create instace

I'm trying to create a factory for instantiating my classes with generics. Checked out TypeScript docs and it all works perfectly. In short, this works just fine:
class Person {
firstName = 'John';
lastName = 'Doe';
}
class Factory {
create<T>(type: (new () => T)): T {
return new type();
}
}
let factory = new Factory();
let person = factory.create(Person);
console.log(JSON.stringify(person));
Now define class Person in directory:
export class Person extends BasePerson {
firstName = 'John';
lastName = 'Doe';
}
And when I import Person from other package:
import { Person } from "./directory"
class Factory {
create<T>(type: (new () => T)): T {
return new type();
}
}
let factory = new Factory();
let person = factory.create(Person);
I get error:
Argument of type 'typeof Person' is not assignable to parameter of type 'new () => Person'
How can I get a value of Person instead of typeof Person?
Using TypeScript 3.7.2 and Node v10.13.0.
Could you try this for me please?
import { Person } from "./directory"
class Factory {
create<T>(type: (new () => T)): T {
return new type();
}
}
let factory = new Factory();
let person = factory.create(new Person);
Actual problem here was a parent class of Person -> BasePerson. BasePerson expected an argument in its constructor, so when I tried to call factory.create(Person), Person actually was an typeof because it expected an argument for base class constructor. Problem was solved by deleting the constructor in base class and injecting a property via ioc container, in my case Inversify.

Parent static method to return subclass object

class Vehicle {
constructor (name, type) {
this.name = name;
this.type = type;
console.log(this.constructor.name);
}
getName () {
return this.name;
}
getType () {
return this.type;
}
static create(name, type) {
return new Vehicle(name, type);
}
}
class Car extends Vehicle {
constructor (name) {
super(name, 'car');
}
getName () {
return 'It is a car: ' + super.getName();
}
}
let car = Car.create('Tesla', 'car');
console.log(car.getName()); // It is a car: Tesla
console.log(car.getType()); // car
The above code use ES6 class keyword to define a Vehicle class and a subclass Car from it. How to return Car instance from Vehicle static method.
Try:
let car = new Car('Tesla')
You can pass the ClassName you want to use within your static function create and create an instance from it.
static create(name, type, objClass) {
return new Function(`return new ${objClass ? objClass : 'Vehicle'}('${name}', '${type}');`)();
}
The Function class receives a String with the expression to evaluate, in your case:
new Function(`return new ${objClass}('${name}', '${type}');`)()
Look at this code
class Vehicle {
constructor(name, type) {
this.name = name;
this.type = type;
}
getName() {
return this.name;
}
getType() {
return this.type;
}
static create(name, type, objClass) {
return new Function(`return new ${objClass ? objClass : 'Vehicle'}('${name}', '${type}');`)();
}
}
class Car extends Vehicle {
constructor(name) {
super(name, 'car');
}
getName() {
return 'It is a car: ' + super.getName();
}
}
let car = Car.create('Tesla', 'car', 'Car');
console.log(car.getName()); // It is a car: Tesla
console.log(car.getType()); // car
let superCar = Vehicle.create('Tesla', 'car');
console.log(superCar.getName()); // Tesla
console.log(superCar.getType()); // car
.as-console-wrapper {
max-height: 100% !important
}
See? now is printing the right output.
Resources
Class Function

Extend Property with isDirty

I want to track changes to the properties of my classes in typescript so that I only update the fields in my database which have actually changed. Currently, I am using an array where I add properties when they change and then I iterate through the array to determine what fields changed and need to be updated in the database. However, I would prefer to do this with some sort of isDirty check. My thought is that I would be able to call something like if (property.dirty) then {} to determine if a property has changed.
I remember being able to do something along these lines in vb.net, but it's been a while and I can't remember exactly what we did in that codebase.
Is the desired code below possible?
Current Code
class test{
private _ID: Guid;
private _dirty: Array<{}>;
get ID(): Guid {
return this._ID;
}
set ID(id: Guid) {
if (this._ID != id) {
this._ID = id;
this._dirty.filter(function (f) { return f.Field == "id" }).length > 0 ? this._dirty.filter(function (f) { return f.Field == "id" })[0].Value = id.toString() : this._dirty.push({Field: "id", Value: id});
}
}
get Name(): string {
return this._Name;
}
set Name(name: string) {
if (this._Name != name) {
this._Name = name;
this._DirtyFields.filter(function (f) { return f.Field == "ccseq_name" }).length > 0 ? this._DirtyFields.filter(function (f) { return f.Field == "ccseq_name" })[0].Value = name : this._DirtyFields.push(new EntityField("ccseq_name", name, FieldType.String));
}
}
}
Desired Code
class test{
private _ID: Guid;
get ID(): Guid {
return this._ID;
}
set ID(id: Guid) {
if (this._ID != id) {
this._ID = id;
this._ID.isDirty = true;
}
}
get Name(): string {
return this._Name;
}
set Name(name: string) {
if (this._Name != name) {
this._Name = name;
this._Name.isDirty = true;
}
}
}
In javascript you can add a property to an object so it's not a problem to do this:
this._ID.dirty = true;
Even when Guid doesn't have this dirty member.
The problem of course is typescript which will complain because of that.
To avoid that you can simply do:
private _ID: Guid & { dirty?: boolean };
Edit
Again, javascript already supports it, you can do this:
obj.dirty = true;
For any js type: booleans, strings, arrays and even functions.
But for having support for that in typescript you can do this:
interface Object {
dirty?: boolean;
}
But be aware that you are adding this to **all* of the objects that you have in your code. As you're not actually changing the prototype it won't have any effect in runtime, but typescript-wise it will effect all instances.
The way I solved this was to create a Field class that I then used as properties in my Objects.
Field Class
export class EntityField {
private _Field: string;
private _Value: any;
private _FType: FieldType;
private _isDirty: boolean;
constructor(field: string, value: any, fType: FieldType) {
this._Field = field;
this._Value = value;
this._FType = fType;
this._isDirty = false;
}
markClean(): void {
this._isDirty = false;
}
markDirty(): void {
this._isDirty = true;
}
get isDirty(): boolean {
return this._isDirty;
}
get Field(): string {
return this._Field;
}
set Field(field) {
if (this._Field !== field) {
this._Field = field;
}
}
get Value(): any {
return this._Value;
}
set Value(value: any) {
if (this._Value !== value) {
this._Value = value;
this._isDirty = true;
}
}
get FType(): FieldType {
return this._FType;
}
set FType(fType: FieldType) {
if (this._FType != fType) {
this._FType = fType;
}
}
}
Usage
export class Entity{
public Name: Field
}
Entity test = new Entity()
Entity.Name.isDirty() // Returns False
Entity.Name.Value = "Test";
Entity.Name.isDirty() // Returns True

Categories

Resources