inetphantom
inetphantom

Reputation: 2594

Dynamic instantiation in JavaScript [Classname as String]

I am working with Javascript and Appdescriptors in JSON format. What I want to do is creating a instance of a Class, where the classname is saved as string in oModelConf[sModelName].type. If that is not the case I want to take "sap.ui.model.odata.ODataModel"

Related Question offers this solution:

function instantiate(className, args) {
    var o, f, c;
    c = window[className]; // get reference to class constructor function
    f = function(){}; // dummy function
    f.prototype = c.prototype; // reference same prototype
    o = new f(); // instantiate dummy function to copy prototype properties
    c.apply(o, args); // call class constructor, supplying new object as context
    o.constructor = c; // assign correct constructor (not f)
    return o;
}

This is not a very good solution I think.

EDIT It does not work for me because my class is not defined on window, so window[className] is undefined. I do not know where my function is defined in SAPUI5

A second Solution:

eval(`a = new ${oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel"}(sServiceUrl, true);`);

This is not a better solution because we should not use eval().

Are there any better solutions?

EDIT2 Because of the url in pimskies answer I found an other solution:

Since window.sap.ui.model.odata.ODataModel is the same as sap.ui.model.odata.ODataModel and window.sap is the same as window[sap] I could take my string, and replace all . with ][, put the right brackets to front and end.

I will not code that because it is not a going solution.(I should not have coded the evalthing too...)

Upvotes: 0

Views: 1141

Answers (3)

schnoedel
schnoedel

Reputation: 3948

You could use jQuery.sap.getObject to access the class:

var ModelClass = jQuery.sap.getObject(oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel");
var model = new ModelClass();

Edit: An other way (which i would recommend if you use AMD)

If you are using the modern AMD modules and you don't know if the module containing your class has already been loaded, you should use sap.ui.require() to load the module asynchronously. It requires the module to be specified via its unified resource name (the conversion is probably the most ugly part):

var className = oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel";
var urn = className.replace(".", "/"); //Convert to unified resource name
sap.ui.require([urn],function(ModelClass){
  //This function is called when the module is available
  var model = new ModelClass();
  ...
});

Upvotes: 3

Aron Boyette
Aron Boyette

Reputation: 957

What not combine the two? Since window[className] is failing, replace it with oModelConf[className].type || sap.ui.model.odata.ODataModel...

function instantiate(className, args) {
    var o, f, c;
    c = oModelConf[className] || sap.ui.model.odata.ODataModel;
    f = function(){}; // dummy function
    f.prototype = c.prototype; // reference same prototype
    o = new f(); // instantiate dummy function to copy prototype properties
    c.apply(o, args); // call class constructor, supplying new object as context
    o.constructor = c; // assign correct constructor (not f)
    return o;
}

Upvotes: 0

Pimmol
Pimmol

Reputation: 1871

Maybe map the string to a class?

function Foo() {
  console.log('new foo');
}

function Bar() {
  console.log('new bar');
}

var objects = {
    'foo': Foo,
  'bar': Bar
};

var cls = objects.foo || Bar;

new cls();

https://jsfiddle.net/ckd56d9v/1/

Or take a look at this answer: https://stackoverflow.com/a/9804142/5930258

Upvotes: 0

Related Questions