0

I Need to refactor an IIFE in ES6. In ES6 let and const have a block scope, so I really need an IIFE in ES6? This is the ES5 version of the code:

var oojs = (function(oojs) {
  var createToolbarItems = function(itemElements) {
    var items = [];
    [].forEach.call(itemElements,
      function(el, index, array) {

        var item = {
          toggleActiveState: function() {
            this.activated = !this.activated;
          }
        };

        Object.defineProperties(item, {
          el: {
            value: el
          },
          enabled: {
            get: function() {
              return !this.el.classList.contains('disabled');
            },
            set: function(value) {
              if (value) {
                this.el.classList.remove('disabled');
              } else {
                this.el.classList.add('disabled');
              }
            }
          },
          activated: {
            get: function() {
              return this.el.classList.contains('active');
            },
            set: function(value) {
              if (value) {
                this.el.classList.add('active');
              } else {
                this.el.classList.remove('active');
              }
            }
          }
        });

        items.push(item);
      });
    return items;
  };

  oojs.createToolbar = function(elementId) {
    var element = document.getElementById(elementId);
    var items = element.querySelectorAll('.toolbar-item');

    return {
      items: createToolbarItems(items)
    }
  };

  return oojs;
}(oojs || {}));

What is the best way to translate this code in ES6? I tried many solution but I miss something, and I get an error: oojs is not defined.

Maybe I can use a Class instead? As you can see from the code I'm writing a Toolbar API in a OOP way (I think...)

Thanks for any help

EDIT: Thanks to georg, I try to refactor my code using classes. This is the new ES6 version:

class Toolbar {
  constructor(elementId) {
    this.elementId = elementId;
  }
  get items() {
    const element = document.getElementById(this.elementId);
    return element.querySelectorAll(".toolbar-item");
  }
  createToolbarItems() {
    return [...this.items].map(el => new ToolbarItem(el));
  }
}

class ToolbarItem {
  constructor(el) {
    this.el = el;
  }
  get enabled() {
    return !this.el.classList.contains('disabled');
  }
  set enabled(value) {
    if (value) {
      this.el.classList.remove('disabled');
    } else {
      this.el.classList.add('disabled');
    }
  }
  get activated() {
    return this.el.classList.contains('active');
  }
  set activated(value) {
    if (value) {
      this.el.classList.add('active');
    } else {
      this.el.classList.remove('active');
    }
  }
  toggleActiveState() {
    this.activated = !this.activated;
  }
}

// const toolbar = new Toolbar('myToolbar');
// const toolbarItems = toolbar.createToolbarItems();

EDIT: please check if is the right way to write this code, I'm pretty new to ES6

Thanks again

ufollettu
  • 822
  • 3
  • 19
  • 45
  • "I can use a Class instead" - sure, `Toolbar` and `ToolbarItem` are close candidates. – georg Feb 27 '18 at 14:27
  • @georg can you help me with the syntax? – ufollettu Feb 27 '18 at 14:28
  • *"I get an error: `oojs is not defined`"*: When I run your snippet, there is no such error. – trincot Feb 27 '18 at 14:29
  • @mplungjan “How can I turn this ES5 code into its ES6 equivalent?” is a specific question about a programing problem (SO realm). Definitely off-topic for code review as the code is not implemented as expected. – 301_Moved_Permanently Feb 27 '18 at 14:31
  • @trincot: the error appears when I use (improperly) ES6 – ufollettu Feb 27 '18 at 14:31
  • Your question is on-topic if you have a problem with code, in which case you should post your failing ES6 attempts and ask about that. Your question is off-topic if you have working code that you just want to have reviewed for improvements. – trincot Feb 27 '18 at 14:40
  • related, if not duplicate: [Converting IIFE functions to es6?](https://stackoverflow.com/q/43404555/1048572) – Bergi Feb 27 '18 at 14:59

1 Answers1

3

You can start by factoring out the toolbar item code (var item and below):

class ToolbarItem 
{
    constructor(element) {
      ....
    }
}

Now, decide if you want to keep enabled and activated as properties or refactor them to explicit methods like isEnabled and setEnabled. In the former case it would be,

class ToolbarItem {
   get enabled() {
      ...
   }
   set enabled(value) {
      ...
   }
}

while ordinary methods can be defined like this:

class ToolbarItem {
   isEnabled() {
      ...
   }
   setEnabled(value) {
      ...
   }
}

Once you get this sorted out, replace your item initialization code with items.push(new ToolbarItem(el)) and test.

Hope this helps you getting started, good luck!

georg
  • 211,518
  • 52
  • 313
  • 390
  • Thanks, I'll post a refactoring in first answer EDIT. – ufollettu Feb 28 '18 at 08:39
  • @ufollettu: in your code `createToolbarItems` could be simply `[... itemElements].map(el => new ToolbarItem(el))`. Get used to arrow functions, they're amazing! – georg Feb 28 '18 at 09:15