Aaron Butacov
Aaron Butacov

Reputation: 34347

How to call New variable Class Name in coffeescript without eval

So, I have a standard class that is extended by child classes. In some cases, I'm passing what child class to use through jQuery as a option instead of using the default standard class.

Example: jQuery('img').myPlugin();

Calls

New mainClass(arg1, arg2)

While

jQuery('img').myPlugin({classToUse : 'myExtendedClass'});

Calls

New myExtendedClass(arg1, arg2)

Here's the code that works, but it is ugly in so many ways. How can we do this properly? Here @settings is a simple object, and @settings.classToUse is a string that's passed.

@NewClass = eval("new #{@settings.classToUse}(this.$element, this.settings)")

The following does not work and returns a string error:

@Framer = new @settings['classToUse'](this.$element, this.settings)

A clipped version of the full source code is below. Any errors in the logic are a result of clipping the code as the code in its current state is 100% functional.

You can also see the code compiled here.

class mainClass
  constructor: (@framedObject, @options) ->
  doSomething: ->
    alert('something')

class myExtendedClass extends mainClass
  doSomething: ->
    alert('somethingDifferent')

class anotherExtendedClass extends mainClass
  doSomething: ->
    super
    alert('Woah!')

$ ->
  $.plugin = (element, options) ->
    @settings = {classToUse : 'myExtendedClass'} #built by merging defaults and options
    @init = ->      
      @mainClass = eval("new #{@settings.classToUse}(this.$element, this.settings)")
    @init()
    this
  $.fn.mediaFrame = (options) ->
    return this.each ->
      plugin = new $.plugin this, options

Upvotes: 0

Views: 323

Answers (2)

phenomnomnominal
phenomnomnominal

Reputation: 5515

How about something like:

class Border
  constructor: (@options) ->
class RedBorder extends Border
    constructor: (@options) ->
class BlueBorder extends Border
    constructor: (@options) ->

borders = 
  Default: Border
  Red: RedBorder
  Blue: BlueBorder

$.plugin = (element, options) ->
  @mainClass = new borders[@settings.class || 'Default'](@settings)

Upvotes: 3

robkuz
robkuz

Reputation: 9934

your second approach will fail as you cant instantiate a "String"

 @Framer = new @settings['classToUse'](this.$element, this.settings)

also there seems to be an error as you are using "type" instead of "classToUse"

The easiest way to would seem to simply put the class-object into the hash that you give to jQuery

 jQuery('img').myPlugin({classToUse : redBorder});

In this example assuming that redBorder is the class name.

Upvotes: 0

Related Questions