admin管理员组

文章数量:1355638

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?

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?

Share Improve this question edited Jul 10, 2016 at 15:20 Troncador asked Jun 30, 2016 at 14:18 TroncadorTroncador 3,5763 gold badges25 silver badges41 bronze badges 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? – T J Commented Jul 4, 2016 at 6:21
  • I can create an interface and control different kinds of widget with the same interface – Troncador Commented Jul 5, 2016 at 6:35
Add a ment  | 

4 Answers 4

Reset to default 3

In OOD is important to favor position 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

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./jquery-1.10.2.js"></script>
<script src="//code.jquery./ui/1.11.4/jquery-ui.js"></script>
<div id='foo'></div>
<div id='bar'></div>

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./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./jquery-1.10.2.js"></script>
<script src="//code.jquery./ui/1.11.4/jquery-ui.js"></script>
<div id='foo'></div>
<div id='bar'></div>

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.

本文标签: javascriptJQuery UI inheritance polymorphismStack Overflow