0

I have two methods getTargetComponentById and getTargetComponentByName which perform a lookup on an object based on a particular key and returns an object. The two methods work fine seperated, but I would like to combine them to cut down on duplicated code. What would be the best way of combining them:

  getTargetComponentById(componentId: string): IComponentTarget[] {
    const targetComponents = [];
    const website = this.website.getValue();
    for (let i = 0; i < website.pages.length; i++) {
      for (let j = 0; j < website.pages[i].components.length; j++) {
        if (website.pages[i].components[j].componentId === componentId) {
          targetComponents.push({
            activePageIndex: i,
            activeComponentIndex: j,
          });
        }
      }
    }
    return targetComponents;
  }

  getTargetComponentByName(componentName: string, activeWebsite = null): IComponentTarget[] {
    let website: IWebsite;
    if (activeWebsite === null) {
      website = this.website.getValue();
    } else {
      website = activeWebsite;
    }
    const targetComponents = [];
    for (let i = 0; i < website.pages.length; i++) {
      for (let j = 0; j < website.pages[i].components.length; j++) {
        if (website.pages[i].components[j].componentName === componentName) {
          targetComponents.push({
            activePageIndex: i,
            activeComponentIndex: j,
          });
        }
      }
    }
    return targetComponents;
  }
2
  • getTargetComponentById(componentId: string, activeWebsite = null), const website = activeWebsite || this.website.getValue();, then you only have to find a way how to distinguish an id from a name. Commented Jun 4, 2020 at 8:50
  • 2
    This better fits codereview.stackexchange.com Commented Jun 4, 2020 at 8:52

4 Answers 4

1

You could declare the property to use as an extra input parameter.

getTargetComponentByProperty(property: 'componentName' | 'componentId', value: string, activeWebsite ?= null): IComponentTarget[] {
  const website: IWebsite = activeWebsite ? activeWebsite : this.website.getValue();
  const targetComponents = [];
  for (let i = 0; i < website.pages.length; i++) {
    for (let j = 0; j < website.pages[i].components.length; j++) {
      if (website.pages[i].components[j][property] === value) {
        targetComponents.push({
          activePageIndex: i,
          activeComponentIndex: j,
        });
      }
    }
  }
  return targetComponents;
}
Sign up to request clarification or add additional context in comments.

Comments

1

I like this

getTargetComponent(arg: string|number, activeWebsite ?= null): IComponentTarget[] {
  const website = activeWebsite || this.website.getValue();
  if (''+arg===arg)
      console.log("arg is a string")
  else
      console.log("arg is a number")

 //well, you can use
 const field=(''+arg===arg)?'componentName':'componentId'
 //and use components[j][field]==arg
}

Comments

1

You could use bracket notation instead of dot notation property accessor to generalize the statement website.pages[i].components[j].componentName === componentName. Try the following

getTargetComponent(component: string, activeWebsite ?= null): IComponentTarget[] {
  const website: IWebsite = activeWebsite ? activeWebsite : this.website.getValue();
  const targetComponents = [];
  for (let i = 0; i < website.pages.length; i++) {
    for (let j = 0; j < website.pages[i].components.length; j++) {
      if (website.pages[i].components[j][component] === component) {        // <-- bracket notation here
        targetComponents.push({
          activePageIndex: i,
          activeComponentIndex: j,
        });
      }
    }
  }
  return targetComponents;
}

Comments

1

You can expose two different interface methods that internally use only one method for logic. I think this is the most elegant way of doing it. If you are using angular (and therefore typescript) you can also enter the two methods as public and the core method as private.

  public getTargetComponentById(id: string): IComponentTarget[] {
    return getTargetComponentBy(id, null, 'componentId');
  }

  public getTargetComponentByName(name: string, activeWebsite = null): IComponentTarget[] {
    return getTargetComponentBy(name, activeWebsite, 'componentName');
  }

  private getTargetComponentBy(componentKey: string, activeWebsite = null, prop: string): IComponentTarget[] {
    let website: IWebsite;
    if (activeWebsite === null) {
      website = this.website.getValue();
    } else {
      website = activeWebsite;
    }
    const targetComponents = [];
    for (let i = 0; i < website.pages.length; i++) {
      for (let j = 0; j < website.pages[i].components.length; j++) {
        const aComp = website.pages[i].components[j];
        if (website.pages[i].components[j][prop] === componentKey) {
          targetComponents.push({
            activePageIndex: i,
            activeComponentIndex: j,
          });
        }
      }
    }
    return targetComponents;
  }

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.