JonBrave
JonBrave

Reputation: 4280

How to extend returned object in jQuery/JavaScript

I would like to extend/derive from the XML Document returned by jQuery's $.parseXML() function, to add my own properties/functions. I am new to jQuery/JavaScript object inheritance. I have tried to read all over the web but am not "getting" it.

In, say, C# classes I could write something (kept simple) like this:

public class MyXmlDocument : XmlDocument
{
  public MyXmlDocument(string xmlText)
  {
    this.LoadXml(xmlText);
  }

  public string SomeVariable;
  ...

  public XmlNode FindCertainNode()
  {
    return this.SelectSingleNode("certain");
  }
  ...
}

MyXmlDocument xmlDoc = new MyXmlDocument(xmlText);
xmlDoc.AppendChild(...);  // XmlDocument method
XmlNode xmlNode = xmlDoc.FindCertainNode();  // MyXmlDocument method
etc.

I hesitate to show my jQuery/JavaScript attempt because I am quite at sea, but I know people like to see something, so please regard it as "some ideas I have been playing with":

// One approach
function XMLDoc(xmlText)
{
  var parseXML = function (xmlText)
  {
    //var parser = new DOMParser();
    //var xmlDoc = parser.parseFromString(xmlText, "text/xml");
    var xmlDoc = $.parseXML(xmlText);
    return xmlDoc;
  };

  var findCertainNode = function ()
  {
    return this.find('certain');
  }

  return parseXML(xmlText);
}

// Another approach
var XMLDoc = $.extend({}, $.parseXML.prototype, {
  findCertainNode: function () {
    this.find('certain');
  }
});

I am expecting to be able to access existing functionality for the XML document plus my own extensions, along the lines of:

var xmlDoc = new XMLDoc(xmlText);
var $xmlDoc = $(xmlDoc);
$xmlDoc.find('certain');  // jQuery method
$xmlDoc.findCertainNode();  // my additional method

I also know that I am unclear about whether my code should be returning plain JavaScript objects or jQuery ones. I am thinking jQuery ones, so that I can easily call for example jQuery's .find() etc.

It is important to me that the code should all be wrapped inside a single function/object or similar for editing/viewing, as both my attempts do.

If someone could show how they would implement the C# pattern I think that would answer my question, and I should be most grateful.

EDIT: Solution

I am marking @Karol's solution below (https://stackoverflow.com/a/42672481/489865) as the accepted one as he did the most work to answer my question as phrased.

However, I have come to realise that the object returned from $.parseXML()/DOMParser().parseFromString() is not some special "XML document", it's just an element, and as such has no special methods. It is not worth it to derive/inherit from it, and so encapsulation is adequate and simpler. My pattern looks like:

var XMLDoc = function (xmlText) {
  this._xmlDoc = $.parseXML(xmlText);
};

$.extend(XMLDoc.prototype, {
    doc: this._xmlDoc,
    find: function (selector) {
      return $(this._xmlDoc).find(selector);
    },
    findCertain: function () {
      return $(this._xmlDoc).find("certain");
    },
    ...
});

var xmlDoc = new XMLDoc(xmlText);
xmlDoc.find('something');
xmlDoc.findCertainNode();

Upvotes: 1

Views: 259

Answers (2)

Karol Selak
Karol Selak

Reputation: 4774

Try to do sth like this:

function XMLDoc(xmlText) { //constructor
  this._xmlDoc = $.parseXML(xmlText); //'_' is JS convention for private fields
}
XMLDoc.prototype = {
  findCertainNode: function() {
    return $(this._xmlDoc).find('certain');
  }
  /* other methods here */
}

var myXML = new XMLDoc('<a><certain /></a>')
myXML.findCertainNode(); //[<certain />]

Or the same with ES6 syntax:

class XMLDoc {
  constructor(xmlText) {
    this._xmlDoc = $.parseXML(xmlText);
  }
  findCertainNode() {
    return $(this._xmlDoc).find('certain');
  }
}

var myXML = new XMLDoc('<a><certain /></a>')
myXML.findCertainNode(); //[<certain />]

I think the real inheritance from jQuery is impossible, but if you really want to have an ability to use it in C# way, you can do sth like this:

Object.keys(Object.getPrototypeOf($())).forEach(function(key){
  XMLDoc.prototype[key] = function() {
    return $(this._xmlDoc)[key].apply(null, arguments);
  }
})

Or in ES6:

Object.keys(Object.getPrototypeOf($())).forEach(key => {
  XMLDoc.prototype[key] = () => {
    return $(this._xmlDoc)[key](...arguments);
  }
})

Then you can fire all jQuery methods as they were inherited.

And if you'd like to overload some of them, remember to do this overloading after the code above.

Upvotes: 1

NikNik
NikNik

Reputation: 2301

Try with:

var xmlDoc = new XMLDoc(xmlText);
$.extend( xmlDoc, {
  find: function(par){
          // your function
        }
});

Upvotes: 1

Related Questions