2

So I have repeatedly run into this situation: I write a module patterned object, but am unable to invoke one function from within another (prototyped) function.

;(function($,window,documnet,undefined) {
    var id,
        _defaults = { };

    var MyObject = function(element,options) {
        this.el = element;
        this.opt = $.extend({},_defaults,options);
        this.init();   //  works fine
    };

    MyObject.prototype.init = function() {
        var self = this;
        self.id = localStorage.getItem('myobject_id');
        if( self.id !== null ) {
             $('#myobject_id').val(self.id);
        }
    };


    MyObject.prototype.fetch = function() {
        var self = this;
        var data = { 
                    action: 'program_fetch',
                    program_idx: $('#program_idx').val()
                   };

        // assume session is valid and has a uri in opt.callback
        $.post( session.opt.callback, data ).complete(function(r){
            var prog = JSON.parse(r.responseText).program;
            self.id = prog.id;

            $('#myobject_id').val( self.id );  // this works

            self.display();                    // this does not work
        });

    }; /* fetch */


    MyObject.prototype.display = function() {
        var self = this;

        $('#myobject_id').val( self.id );

    };  /* display */


    $.fn.MyObject = function(options) {
        return this.each(function(){
            if(!$.data(this,'plugin_MyObject')) {
                $.data(this,'plugin_MyObject', new MyObject(options));
            }
        });
    };

    window.myobject = new MyObject();

})(jQuery,window,document);

From what I understand, the fetch function ought to be setting the value of the window-attached instance of MyObject, so that when the display() function is called, it has a value to place into the HTML input field, identified by #myobject_id.

What actually seems to happen is there is a race condition during which the value assigned to self.id is viable, but leaving the scope of the .complete(..) callback the value of MyObject.id is no longer valid.

How ought I be invoking these things to achieve persistence in the instance data within my object ?

8
  • That should work. Are you sure the problem isn't the bad selector in MyObject.prototype.display ('$myobject_id' instead of '#myobject_id')? Commented Apr 3, 2013 at 17:32
  • Also, you shouldn't need the window.myobject = new MyObject(); line if you're only ever instantiating MyObject's through the jQuery plugin pattern. Commented Apr 3, 2013 at 17:35
  • See my "Answer" below. It turns out in part at least I was masking the properties of MyObject by using var self = this; within the each function scope. Commented Apr 3, 2013 at 18:46
  • I can't see your answer or where you're doing the var self = this; insode of an each... Commented Apr 3, 2013 at 18:51
  • MyObject.prototype.fetch = function() { var self = this; Commented Apr 3, 2013 at 18:55

2 Answers 2

1
;(function($,window,documnet,undefined) {
var id, 
    _defaults = { };

var MyObject = function(element,options) {
    this.el = element;
    this.opt = $.extend({},_defaults,options);
    this.init();   //  works fine
};

MyObject.prototype.init = function() {

    id = localStorage.getItem('myobject_id');
    if( id !== null ) {
         $('#myobject_id').val(id);
    }
};

    MyObject.prototype.fetch = function() {
    var data = { 
                action: 'program_fetch',
                program_idx: $('#program_idx').val()
               };

    // assume session is valid and has a uri in opt.callback
    $.post( session.opt.callback, data ).complete(function(r){
        var prog = JSON.parse(r.responseText).program;
        id = prog.id;

        $('#myobject_id').val( id );  // this works
        self.display();               // this does not work
    });

}; /* fetch */


MyObject.prototype.display = function() {
    $('#myobject_id').val( id );
};  /* display */


$.fn.MyObject = function(options) {
    return this.each(function(){
        if(!$.data(this,'plugin_MyObject')) {
            $.data(this,'plugin_MyObject', new MyObject(options));
        }
    });
};

})(jQuery,window,document);

In this version I have removed the pattern of using var self = this; within each function scope, as it was masking the object level variables of the same names. (Can't set object properties through this.var?)

There is still the outstanding issue of self.display() not working at all.

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

Comments

0

The simple truth is I didn't know how to structure a class object in JS. Here's a simple model:

;(function($,window) {

    var self;
    var MyClass = function(opt) {
        self = this;
        return self.init(opt);
    }

    MyClass.prototype = {

        init: function(opt) {
            self.opt = $.extend({},opt);
            // other set up stuff
            return self;
        },

        display: function() {

        },

        show: function() {
            self.display();
        }
    }; /* end of prototype */

    $.fn.myclass = function(opt) {
        return new MyClass(opt);
    }

}(jQuery,window));  /* end of clas object */

jQuery().ready(function($) {
    window.myInstance = $().myclass({ /* options here */ });
    $('#some_button').click( window.myInstance.show );
}

On activation of the button #some_button the show method is invoked. It in turn will invoke the display() method. Easy peasy.

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.