1
votes

I'm working on creating small, embeddable widgets which have a handle outside of their own JS files.

Page Structure

For example, I have a page which may contain n-number of 'power-widget's in it. 'n' is determined by the web server serving the page. A 'power-widget' is nothing but a div with the name of a device and it's current power consumption on it. The current reading is updated via ajax every 5 secs.

NOTE: Each page can have different 'types' of widgets, though the image below has only one type of widget. screen of what I created without using widgets

The Widget

Each green box is a widget which is initialized on page load and takes the device name, color etc as the parameters. Each type of widget, 'power-widget' in this case, has its own JS and CSS files (along with the HTML structure) which are loaded asynchronously once the page detects that those are required. Hence, the same widget can be rendered on any page within my website.

The Problem

I have written code to detect and load the required JS, CSS and HTML content of each widget and place it in it's desired div. I wrote some code to create a 'class-like' structure for the widget which I can instantiate and write methods (like updating the readings) in.

function PowerStatus(options) {
    this.settings = {
        meterName: '',
        mainDiv: null,
        glow: false,
        meterOn: "#91bd09",
        meterOff: "#bc330d",
        meterMid: "#333333"
    };
    this.settings = $.extend(this.settings, options);
    this.settings.mainDiv = $('#' + this.settings.mainDiv);
    this.bindUIActions();
    this.setMeterName();
}

PowerStatus.prototype.setMeterName = function () {
    console.log(this.settings.mainDiv);
    var div = this.settings.mainDiv.find('.load-name');
    var span = $('span:first', div);
    span.text(this.settings.meterName);
};

PowerStatus.prototype.bindUIActions = function () {
    this.settings.mainDiv.on("click", this.divclick);
};

PowerStatus.prototype.divclick = function () {
    console.log(this);
    console.log('Clicked ' + this.settings.meterName);
};

The page inside which the widgets have to be placed calls the following code

var widget = new PowerStatus({meterName: 'Widget 1', mainDiv: 'widget-power-status-1'});

for all the widgets, thereby getting a handle on each.

In the above code, when I click on the div, it throws a

Uncaught TypeError: Cannot read property 'meterName' of undefined

because the callee (this) being passed is actually a 'div' element and not the PowerStatus object. Any clue what's going on? Is jQuery passing it's selected div? Also, I wanted to know if this is the cleanest way to go about the entire thing. I'm pretty new to JS and would welcome any advice.

1

1 Answers

4
votes

You need to create an object constructor rather than using object literals.

function PowerStatus( opts ) {

  this.init = function( opts ){

  }

}

Then:

var widget = new PowerStatus( opts );
widget.init();