Without starting a war on whether or not I should use eval()
, I am trying to make a constructive discussion on how I can avoid (if possible) using eval()
in the following scenario?
I am loading remote html templates into an SPA, to save calls I am loading json that looks like the following:
{
"template":"",
"contentScript":"",
"viewModel":""
}
Where template is html, contentScript is combined script files and viewModel is a single script file.
ContentScript
When the json request is received (either from server or localdb) I create an anonymous function (so all variables are locally scoped to this template script) for the contentScript that looks like:
(function(event, view)
{
// js content here
});
where the event object is a shared object that the contentScript and viewmodel communicate over using a pub/sub pattern and the view object is the DOM element that is the template.
the only way I can see to get this pattern working is by using the following code:
var script = 'function(event, view) {' + json.contentScript + '});';
views[name].script = eval(script);
where views[name] is a collection of all the templates in the SPA so I can get them and rebind them easily given a name.
each time the view is rendered I can then simply call (to execute the script):
views[name].script.apply(window, [ views[name].eventObj, views[name].view ]);
ViewModel
The view model is a slightly different case as I need the properties on that object to be visible for binding, so it cannot be an anonymous function. To achieve the desired result I am creating the viewModel object as an object literal like:
var viewmodel =
{
init: function(event, view)
{
this.event = event;
this.view = view;
},
... other stuff
}
When the viewModel json is received I run a regex over it to ensure the init signature matches what is expected and then eval()
it like:
eval(json.viewModel);
views[name].model = observable(viewmodel); // viewmodel var is available from eval'ing the contentScript
views[name].model.init(views[name].eventObj, views[name].view);
new Function
I have also tried using Function('script as string')
which is also frowned upon. However this does not support both cases, as it creates an anonymous function around my anonymous function which requires an extra step of inspecting arguments to pass the variable down to my anonymous function. More importantly, it also hides the properties of the object literal preventing data binding from working.
Conclusion
I cannot see any issues with what I am doing here but am curious as to how this could be achieved using other means. I have spent considerable time trying different ideas and none allow both scenarios to work effectively.