8

I am implementing the abstract factory and the getitems method works and returns 2 items I mocked, however I am not sure how to render these items in the react component

my code is below

AbstractFactory.tsx

import * as React from 'react';
import { IAbstractFactoryProps } from "./IAbstractFactoryProps";  
import { IAbstractFactoryState } from "./IAbstractFactoryState";  
import styles from './Abstractfactory.module.scss';
import { escape } from '@microsoft/sp-lodash-subset';
import DaoFactory from "./DaoFactory";  
import ICustomerDao from "./ICustomerDao";  
import DataSources from "./DatasourcesEnum";

export default class Abstractfactory extends React.Component<IAbstractFactoryProps, {}> {
  private customerDao: ICustomerDao;

    constructor(props: IAbstractFactoryProps, state: IAbstractFactoryState) {
      super(props);
      this.setInitialState();
      this.setDaos(props.datasource);

      this.state = {
        items: this.customerDao.listCustomers(),
    };
    }

    public render(): React.ReactElement<IAbstractFactoryProps> {
      return (
        <div className={ styles.abstractfactory }>
          <div className={ styles.container }>
            <div className={ styles.row }>
              <div className={ styles.column }>
              {this.state.items}
               </div>
            </div>
          </div>
        </div>
      )
    }

    public setInitialState(): void {
      this.state = {
        items: []
      };
    }

    private setDaos(datasource: string): void {
      const data: any = datasource === "Sharepoint" ? DataSources.SharepointList : DataSources.JsonData;
      this.customerDao = DaoFactory.getDAOFactory(data).getCustomerDAO();

      //Now, its transparent for us a UI developers what datasource was selected
      //this.customerDao.
    }
}

Customer.ts

class Customer{  
    public id: string;
    public firstName: string;
    public lastName: string;
}

export default Customer;

Datasourcesenum.ts

enum DataSources {  
    SharepointList = "SharepointList",
    JsonData = "JsonData"
}

export default DataSources;

DaoFactory.ts

import ICustomerDAO from "./ICustomerDAO";  

import DataSources from "./DatasourcesEnum";

abstract class DAOFactory {

    public abstract getCustomerDAO(): ICustomerDAO;

    public  static getDAOFactory(whichFactory: DataSources): DAOFactory {
        switch (whichFactory) {
          case DataSources.SharepointList:
            return new SharepointListDAOFactory();
          case DataSources.JsonData:
            return new JsonDAOFactory();
          default  :
            return null;
        }
      }
}

export default DAOFactory;
import SharepointListDAOFactory from "./SharepointListDAOFactory";  
import JsonDAOFactory from "./JsonDAOFactory";  

JsonDaoFactory.ts

import DAOFactory from "./DaoFactory";  
import JsonCustomerDAO from "./JsonCustomerDAO";
import ICustomerDao from "./ICustomerDao";

class JsonDAOFactory extends DAOFactory {  
    public getCustomerDAO(): ICustomerDao{
        return new JsonCustomerDAO();
    }
}

export default JsonDAOFactory; 

SharepointListDaoFactory.ts

import DaoFactory from "./DaoFactory";  
import ICustomerDao from "./ICustomerDao";  
import SharepointCustomerDao from "./SharepointCustomerDAO";

class SharepointListDAOFactory extends DaoFactory {  
    public getCustomerDAO(): ICustomerDao{
        return new SharepointCustomerDao();
    }
}

export default SharepointListDAOFactory;

JsonCustomerDao.ts

import ICustomerDao from "./ICustomerDao";  
import Customer from "./Customer";

  class JsonCustomerDAO implements ICustomerDao{
    public insertCustomer(): number {
        // implementation to be done by reader
        return 1;
    }

    public deleteCustomer(): boolean {
        // implementation to be done by reader
        return true;
    }

    public findCustomer(): Customer {
        // implementation to be done by reader
        return new Customer();
    }

    public updateCustomer(): boolean {
        // implementation to be done by reader
        return true;
    }

    public listCustomers(): Customer[] {
        // implementation to be done by reader
        let c1: Customer= new Customer();
        let c2: Customer= new Customer();
        c1.id="3";
        c1.firstName="Andrew";
        c1.lastName="Valencia";
        c2.id="4";
        c2.firstName="Charles";
        c2.lastName="Smith";


        let list: Array<Customer> = [c1, c2 ];
        return list;
    }
}

export default JsonCustomerDAO;

SharepointCustomerDao.ts

import ICustomerDao from "./ICustomerDao";  
import Customer from "./Customer";

 class SharepointCustomerDao implements ICustomerDao {
    public insertCustomer(): number {
        // implementation to be done by reader
        return 1;
    }

    public deleteCustomer(): boolean {
         // implementation to be done by reader
        return true;
    }

    public findCustomer(): Customer {
         // implementation to be done by reader
        return new Customer();
    }

    public updateCustomer(): boolean {
         // implementation to be done by reader
        return true;
    }

    public listCustomers(): Customer[] {
         // implementation to be done by reader
        let c1: Customer = new Customer();
        c1.id="1";
        c1.firstName="Luis";
        c1.lastName="Valencia";
        let c2: Customer = new Customer();
        c2.id="2";
        c2.firstName="John";
        c2.lastName="Smith";
        let list: Array<Customer> = [c1, c2 ];
        return list;
    }
}

export default SharepointCustomerDao;

Icustomerdao

import Customer from "./Customer";

 interface ICustomerDao {
    insertCustomer(): number;
    deleteCustomer(): boolean;
    findCustomer(): Customer;
    updateCustomer(): boolean;
    listCustomers(): Customer[];
}

export default ICustomerDao;

.tsx

import * as React from 'react';
import { IAbstractfactoryProps } from "./IAbstractFactoryProps";  
import { IAbstractFactoryState } from "./IAbstractFactoryState";  
import styles from './Abstractfactory.module.scss';
import { escape } from '@microsoft/sp-lodash-subset';
import DaoFactory from "./DaoFactory";  
import ICustomerDao from "./ICustomerDao";  
import DataSources from "./DatasourcesEnum";

export default class Abstractfactory extends React.Component<IAbstractfactoryProps, {}> {
  private customerDao: ICustomerDao;

    constructor(props: IAbstractfactoryProps, state: IAbstractFactoryState) {
      super(props);
      this.setInitialState();
      this.setDaos(props.datasource);
    }

    public render(): React.ReactElement<IAbstractfactoryProps> {
      this.state = {
          items: this.customerDao.listCustomers(),
      };

      return null;
    }

    public setInitialState(): void {
      this.state = {
        items: []
      };
    }

    private setDaos(datasource: string): void {
      const data: any = datasource === "Sharepoint" ? DataSources.SharepointList : DataSources.JsonData;
      this.customerDao = DaoFactory.getDAOFactory(data).getCustomerDAO();
    }
}

UPDATE 1

I changed the render method as below

 public render(): React.ReactElement<IAbstractFactoryProps> {
      return (
        <div className={ styles.abstractfactory }>
          <div className={ styles.container }>
            <div className={ styles.row }>
              <div className={ styles.column }>
                  {this.state.items.map( i => (<div>i.id</div>)}
               </div>
            </div>
          </div>
        </div>
      );
    }

and I have these 2 issues

[23:11:06] Error - typescript - src/webparts/abstractfactory/components/Abstractfactory.tsx(34,63): error TS1005: ',' expected.
[23:11:06] Error - typescript - src/webparts/abstractfactory/components/Abstractfactory.tsx(34,30): error TS2339: Property 'items' does not exist on type 'Readonly<{}>'.
9
  • 1
    Where did you get the idea to write React code like this? This code is orders of magnitude more complicated than it needs to be. Commented May 26, 2018 at 18:50
  • why do you think its complicated? for me its easy to understand. Commented May 26, 2018 at 18:57
  • Actually I got confused too. Probably because of the amount of the code. So what do you want to render and how do you want to render it? What output are you waiting for? It's hard to get because of so much code, at least for me Commented May 26, 2018 at 19:07
  • I want to render the 2 customers, id, firstname and lastname, in the chrome debugger I can see the object is filled, but as I am not expert in react, I have no idea how to render an array of objects into a nice looking table Commented May 26, 2018 at 19:19
  • To render array use map() and return associated html or component for each item. See docs Commented May 26, 2018 at 21:49

2 Answers 2

4
+50

** Update ** Okay, then lets leave the listCustomers method as is.

According to your code and the contents of the render method items equals to the customer array right? if so then replace

{this.state.items}

with

{this.state.items.map( i => (<div>i.id</div>)}

for instance.

Sidenote: React re-renders components when their state changes. So whenever you make an update to your customerList, make sure to put it to the state of the component which is rendering them.

Sign up to request clarification or add additional context in comments.

7 Comments

Ijust posted the .tsx with the render method. the way you do it does not convince me at all as I believe it violaated the Single Responsibility principle by adding html to the return value.
What do you mean by adding HTML to the return value violates the Single Responsibility Principle? The whole idea of the render function is that we want to render HTML elements or React Components to the DOM.
@KomolafeTolulope each class should have one single resposability, check SOLID principles, so the TSX is ok to render html, but the Dao classes should only return data and not render html, the logic of rendering should be done in the component only.
@noa-de v please see my update! there is a syntax error.
@LuisValencia these are just TSC errors right? The code itself works? Important to know :)
|
1

If you want to render multiple components with custom jsx you can create a function that takes the object and returns jsx like so:

const myCustomer =({id,name,phone}){
  //Do stuff here
  return(<div><span>{name}</span><span>{phone}</span></div>)
}

then you call it from your component in your render like so:

items.map((customer,i)=> <myCustomer key={i} {...customer}/>)

Note: if you need to keep state for each row you can use a React.Component instead of a function.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.