12

Is there a way to have polymorphism in the inheritance of a widget in jQuery UI?

For example I want to do something like:

$.widget('tr.fatherClass', {
  getValue: function() {
    return null;
  }
  ...
});
// sonClass1: extends from the father
$.widget('tr.sonClass1', $.tr.fatherClass, {
  getValue: function() {
    return this._fooFunction1();
  }
  ...
});
// sonClass2: extends from the father
$.widget('tr.sonClass2', $.tr.fatherClass, {
  getValue: function() {
    return this._fooFunction2();//
  }
  ...
});
// create an instance of a "sonClass"
$('#foo1').sonClass1(options);  
$('#foo2').sonClass2(options);  

Then I want to use the method "getValue" without knowing the name of the son class:

$('#foo1').fatherClass('getValue'); // run _fooFunction1() of sonClass1
$('#foo2').fatherClass('getValue'); // run _fooFunction2() of sonClass2

But this is not possible:

jquery.js:250 Uncaught Error: cannot call methods on variable prior to initialization; attempted to call method 'getValue'

In the forum of JQuery, Scott Gonzalez explains that "Creating a widget only creates one widget, not every widget in the prototype chain" link

There is any workaround or solution to do this in an elegant way?

2
  • This is not how jQuery plugins work. You have to handle your logic in same plugin. What real world advantage do you gain from this? Commented Jul 4, 2016 at 6:21
  • I can create an interface and control different kinds of widget with the same interface Commented Jul 5, 2016 at 6:35

4 Answers 4

3

In OOD is important to favor composition over inheritance. But if you still want polymorphism, instead of switching plugins you can create a function as a plugin variable you can overwrite in your application logic

Example:

$.widget('myWidget', {
    getValue: function() {
      if(userfunc != null)
         return userfunc();
      return null;
   }
   userfunc: null
  });

and then you can create different versions for userfunc

userfunc1 = function(){  return 43; }
userfunc2 = function(){  return 38; }

$('#foo').myWidget({userfunc : userfunc1})
value = $('#foo').myWidget('getValue') <= returns 47

$('#foo').myWidget({userfunc : userfunc2})
value = $('#foo').myWidget('getValue') <= returns 38

Hope this helps

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

1 Comment

It doesn't solve my problem, but is a good start point, I going to think about it
2
+50

You can save fatherClass as a data for element with some key like fatherObject it should go in father's _create() method...

$.widget('tr.fatherClass', {
  _create: function(){
    $(this.element).data( 'fatherObject', $.tr.fatherClass.prototype );
  },
  ...
};

And later retrieve values using...

$('#foo').data('fatherObject').getValue()

or

$('#bar').data('fatherObject').getValue()

$.widget('tr.fatherClass', {
  _create: function(){
    $(this.element).data( 'fatherObject', $.tr.fatherClass.prototype );
  },
  getValue: function() {
    return 'yellow'; // Father likes yellow
  }
});

// extends from the father
$.widget('tr.sonClass', $.tr.fatherClass, {
  getValue: function() {
    return 'blue'; // Son likes blue
  }
});

// extends from the father
$.widget('tr.daughterClass', $.tr.fatherClass, {
  getValue: function() {
    return 'pink'; // Daughter likes pink
  }
});

// This is son
$('#foo').sonClass();

// This is daughter
$('#bar').daughterClass();

// Son's fav color
console.log( $('#foo').sonClass('getValue') );

// Son's FATHER's fav color
console.log( $('#bar').data('fatherObject').getValue() );

// Daughter's fav color
console.log( $('#bar').daughterClass('getValue') );

// Daughter's FATHER's fav color
console.log( $('#bar').data('fatherObject').getValue() );
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id='foo'></div>
<div id='bar'></div>

1 Comment

I did some changes in your answer, but the main idea is exactly what I want
2

There is no way to access over written parent's methods from outside the widget declaration, but if you have written sonClass yourself, you can call same method from parent by using this._super(), implementation in your sonClass will look something like this...

// extends from the father
$.widget('tr.sonClass', $.tr.fatherClass, {
  getValue: function( fromFather ) {
    if ( 'father' == fromFather ) { // If 'father' is passed as argument
      return this._super(); // Get the result from father's method
    } else {
      return this._$input.val();
    }
  }
  ...
});

You can call method from father like this...

console.log( $('#foo').sonClass('getValue', 'father') );

For reference
http://api.jqueryui.com/jQuery.widget/#method-_super

UPDATE

We add new fathersMethod method to father which returns results from father...

$.widget('tr.fatherClass', {
  //Add this to father to get properties from father
  fathersMethod: function(prop) {
    if ( typeof $.tr.fatherClass.prototype[prop] == 'function' )
    return $.tr.fatherClass.prototype[prop]();
  },
  getValue: function() {
    return 'yellow'; // Father likes yellow
  },
  ...
  ...
  ...
});

Now for any son (or daughter) who inherits from father... can call father's methods like this...

$('#foo').sonClass('fathersMethod', 'getValue');

Here's an updated snippet ;-)

$.widget('tr.fatherClass', {
  fathersMethod: function(prop) {
    if ( typeof $.tr.fatherClass.prototype[prop] == 'function' )
    return $.tr.fatherClass.prototype[prop]();
  },
  getValue: function() {
    return 'yellow'; // Father likes yellow
  }
});

// extends from the father
$.widget('tr.sonClass', $.tr.fatherClass, {
  getValue: function() {
    return 'blue'; // Son likes blue
  }
});

// extends from the father
$.widget('tr.daughterClass', $.tr.fatherClass, {
  getValue: function() {
    return 'pink'; // Daughter likes pink
  }
});

// This is son
$('#foo').sonClass();

// This is daughter
$('#bar').daughterClass();

// Son's fav color
console.log( $('#foo').sonClass('getValue') );

// Son's FATHER's fav color
console.log( $('#foo').sonClass('fathersMethod', 'getValue') );

// Daughter's fav color
console.log( $('#bar').daughterClass('getValue') );

// Daughter's FATHER's fav color
console.log( $('#bar').daughterClass('fathersMethod', 'getValue') );
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id='foo'></div>
<div id='bar'></div>

4 Comments

I have clarified a little my question. I have no problem to run code of the father in the son. My problem is that I have many kinds of son and I want to control them in a similar way.
Updated my answer, the idea is to create a new method in father which accepts prop parameter, checks if prop is a method in $.tr.fatherClasss prototype, if yes calls it returns the value.
It doesn't solve my problem, because you have to know that #bar is a daughterClass and #foo is a sonClass. My point is to forget that and invoke them using a interface, like I show in my question. $('#foo').fatherClass('getValue'); $('#bar').fatherClass('getValue'); <--- in this example I don't care if there are sonClass, daughterClass or fatherClass
Added a new answer to address the issue... ( didn't wanna update the answer again ;P )
2

Normally what you're calling here polymorphism is standard inheritance and instantiation behaviour.

$('#foo1').sonClass1(options);  
$('#foo2').sonClass2(options);  

creates two distinct class instances.

foo1.getValue will execute the instantiated classes, here sonClass1, getValue defintion (code block) which is fooFunction1.

foo2.getValue will execute the instantiatedclass's, here sonClass2, getValue definition (code block) which is fooFunction2.

The later calls here

$('#foo1').fatherClass('getValue'); // run _fooFunction1() of sonClass1
$('#foo2').fatherClass('getValue'); // run _fooFunction2() of sonClass2

are calls not to the sonClass1 or sonClass2 getValue method defintions but that of the fatherClass.

You would normally expect in both the above cases for the father's getValue method defintion to be used.

Your error however says it's undefined.

I don't use JQuery but I would suspect it's inheritance mechanism does not instantiate the parent class.

All of us who have been using js have encountered this issue and have resolved it in a variety of ways.

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.