Dynamically Setting a JavaScript Object's Method's Source - javascript

I've recently been working on a nice little JavaScript game engine that works a lot like Game Maker, but lets people create basic JavaScript games within a browser. Every instance of every object will have it's own preset methods, which the runner will iterate through and execute. I'm trying to find a way to let the user / creator dynamically edit any of the methods source code. When I say 'preset methods', I mean blank methods stored under specific preset names within the objects / object instances. Here's a basic example:
var newObject = object_add("object_name"); // Adds a new object 'blueprint' and returns the reference.
The function object_add(); creates a JavaScript object, and adds a number of preset methods to it, such as:
create
destroy
step
draw
.. and many more
Each of these methods will have no code in them to start with. I need to let the creator dynamically change any of the methods source code. I could simply overwrite the variable that points towards the method, with a new method, but how can you set method's source code using a string?
I know that something like:
newObject.create = function(){textbox.innerHTML};
definitely wouldn't work. Any ideas?
Many thanks,
Dan.

Looks like you want to use eval function, but it's generally a bad idea.

The answer was found at: Creating functions dynamically in JS
Here's the answer (copied from the other page).
Well, you could use Function, like in this example:
var f = new Function('name', 'return alert("hello, " + name + "!");');
f('erick');
//This way you're defining a new function with arguments and body and assigning it to a variable f. You could use a hashset and store many functions:
var fs = [];
var fs['f1'] = new Function('name', 'return alert("hello, " + name + "!");');
fs['f1']('erick');
//Loading xml depends if it is running on browser or server.
Thanks, #CBroe https://stackoverflow.com/users/1427878/cbroe

Related

j2v8: creating new instance of binded object

Our teams is currently under consideration of which JavaScript Engine Bridge to use. We are choosing between LiquidCore and J2V8.
My question is concerning j2v8. Supposedly, I have to create several instances of some java class in JavaScript, how can one achieve this in j2v8 using standard instantiation annotation (new ClassName())? In liquidcore you can bind some class, that extends JSFuction, with super constructor:
JSFunction(JSContext ctx, final String methodName, final Class<?extends JSObject> instanceClass)
and register property with desired class name like this:
jsBaseContext.getJsContext().property("WebSocket", this);
and then on calling:
var x = new WebSocket();
java method methodName will fire, where we'll get new instanceClass as JSValue object as parameter, already binded and ready to use in javascript.
Since no one is going to discuss this topic, i'll answer myself.
This feature is not currently considered to be added in official J2V8 release, however there is a branch on Mizumi's pull request. So, have a look, if you've faced similar issues.

How can I call a function with an object and array and have it add properties to the object?

I have a Javascript testing application that uses Selenium Web Driver. When setting up the code ready to test I am always using code similar to the following that sets up properties before testing a page. In this case it is the topic page so I have this code to set up a topic object and then add properties to it:
var topic = this;
topic.topicName = element(by.id('topicName'));
topic.topicVersion = element(by.id('topicVersion'));
.....
.....
topic.description = element(by.id('description'));
topic.topicHeader = element(by.id('topicHeader'));
topic.topicFooter = element(by.id('topicFooter'));
Is there a way that I could simplify this set up so as to avoid my having to code many times the call to the element(by.id()). Ideally I would like to just pass in an object and an array of the different fields and have some code execute the element(by.id( and add the properties to the object? Note that the property names I would like to have are those that match the element Ids.
Some hints on how I could do this would be much appreciated.
You can do this :
['topicName', 'topicVersion', ...].forEach(function(k){
topic[k] = element(by.id(k));
});

Can I build my jQuery promise pipe chain without using eval()?

I need a promise pipe chain which for this example looks like this:
populateOfferSettings().pipe(populateSegmentationSettings).pipe(populateHousehold).pipe(viewReady);
This is generated dynamically and could contain many functions, provided as an array. I've figured out a way of doing this but it relies on eval(). User input isn't a factor here as this function is only used by developers to manage presenting views so I don't feel too bad about using it (I understand the pitfalls), but I'd feel better not doing so.
Here's my code:
//Array of functions (generally provided as a function parameter)
var requiredFunctions = [
'populateOfferSettings',
'populateSegmentationSettings',
'populateHousehold'
];
//Start building code string to evaluate later, starting with first required function
var code = requiredFunctions[0] + '()';
//Process each required function after first
$.each(requiredFunctions.slice(1), function (index, functionName) {
//Add function to code string using pipe()
code += '.pipe(' + functionName + ')';
});
//Add viewReady() to code string as this should always be at the end
code += '.pipe(viewReady);';
//Evaluate code string
eval(code);
Is there another way of handling piping of functions that would eliminate the need for eval() without making this much more verbose? It seems like there should be but I'm finding it difficult to get my head around jQuery's promise functionality, especially as I'm currently limited to jQuery 1.7.1 before the documentation and functionality of these things were changed.
Per conversation below with #AnthonyGrist:
var code = requiredFunctions[0]();
for (var i=1; i<requiredFunctions.length; i++)
code = code.pipe(window[requiredFunctions[i]]);
if the requiredFunctions are strings, and defined in window scope.
And code = code.pipe(requiredFunctions[i]); if they are functions.
Was also thinking about using code = code.pipe(new Function(requiredFunctions[i])) but that's practically the same as window approach. (only the scopes will change, sheesh...)

how would i implement something like jquerys .data() in pure javascript?

A project I am working on for works wants a pure JavaScript version of the .data() implementation of jQuery.
I wanted to replicate this.
I did a search and Where is jQuery.data() stored? shows where in jQuery it is stored.
I was hoping that i could just attach a datasegment to an HTML element for accessing later.
Since jQuery is Javascript, I can look there, but it makes use of the jQuery objects, which is what I am trying to abstract. I figured there was some sort of way to associate a hash table like dataset with JavaScript and attach it to an object.
http://jsfiddle.net/npXQx/
shows you can create a .data in the object and then it is preserved. You can access it twice, and the data is there.
This example shows a simple string assignment and a function and it being called multiple times.
var item = document.getElementById("hi");
console.log(item);
item.data = {getType: function(){return this.TYPE},TYPE:"winner"};
var out = item.data.getType();
console.log("out", out);
var two = document.getElementById("hi")
console.log("should say 'winner': ", two.data.getType());

pulling an array of objects

I currently have a validation script that has a selection of <input> elements stored in objects with properties such as "id", "type" "isRequired" and"isValid". I currently have this setup() function that does the following:
function setup(obj) {
obj.getElement().onkeyup = function() {validate(obj)}
}
In order to run this setup() function on all of my input objects I need to execute the following addEvents() function
function setEvents() {
setup(firstName)
setup(lastName)
setup(email)
setup(dateOfBirth)
}
I'm helping create a system that has multiple pages of nothing but forms so I'd prefer if I didn't have to type this for each object. Is there a way I can collect an array of all the objects that are based on a specific object template? This way I could loop through the array and apply a setup to each object in a single function. If not, are there alternatives?
(p.s. I've been asking so many object-oriented(oh, I crack myself up sometimes) questions lately because this is my first time messing with objects)
---Edit---
the object template I'm referring to looks something like this:
function input(id,isRequired,type) {
this.id = id
this.isRequired = isRequired
this.type = type
}
this is then followed by a
firstName = new input('firstName',true,'alpha')
As I said in my comment, you could add the element to an array when you create it:
var inputs = [];
var firstName = new input('firstName',true,'alpha');
inputs.push(firstName);
This is not ver convenient yet. But you could create another object which manages all this:
var InputManager = {
elements: [],
create: function(/* arguments here */) {
var n = new input(/* arguments here */);
this.elements.push(n);
return n;
},
setup: function() {
for(var i = this.elements.length; i--;) {
(function(obj) {
obj.getElement().onkeyup = function() {validate(obj)};
}(this.elements[i]));
}
}
};
with which you can do:
var firstName = InputManager.create('firstName',true,'alpha');
// etc.
InputManager.setup();
Something along these lines. I think this would be a quite object oriented way. If you have a collection of objects, you often have another object which handles the functions that should be performed on all those objects.
As with most javascript questions, the easiest way to do this is with a library such as jQuery. If you have a unique way to differentiate these objects with a css selector (e.g., they all have the class "validate" or they're the only input[type="text"] fields on the page or something), then you can do a simple selection like $('.validate') to get an array of all these objects. You can get this array using javascript of course but it's a tad more complicated. Once you have the array you can loop over the elements or you can do a simple bind like $('.validate').change(validate); which will call the validate() method whenever a dom element with the class 'validate' changes.
Edit: So obviously I don't know the entirety of what you're trying to accomplish, but if you're new to web programming, just note also that no matter what you're doing on the client side (ie in the browser), all validation should also be done on the server side. Javascript validation is generally used to just be user-friendly and not to actually validate your inputs, since I could easily just turn javascript off or redefine validate as function validate() {} and bypass javascript validation for whatever reason.
2nd Edit: So I'm not sure if this answer was 100% what you're looking for but it's good to know regardless.
Judging by your examples you are not using jQuery. And for that reason alone, I'm going to up vote you. On the same note, after you get really comfortable with JS and how you can do things, really consider using a framework or saving your scripts so you don't have to reinvent the wheel for each project.
You can actually use the DOM to your advantage!
All the forms in your page can be referenced with document.forms[index]. Alternatively you can also reference a named form with document.formName.
Look at this jsfiddle for an example using the latter.
UPDATE
Reading your update and the fact that you needed a way of creating the input objects and setup the validation. I updated my fiddle with a different approach.
Used the id to hold the validation info regarding the element then the addValidation function reverts the id to it's basic form so you can still use it normally throughout your application.
The only requirement is that you addValidation the first thing after page load. So the ID get revamped first.
The solution is also JS safe, meaning if the user doesn't have JS, apart from no validation, no other things will happen.
I think your problem is that the obj in the onkeyup scope is undefined.
function setup(obj) {
//obj is desired
obj.getElement().onkeyup = function() {validate(obj) //obj is undefined because onkeyup is the new scope of this function
}
instead you could do this:
function setup(obj) {
obj.getElement().onkeyup = function() {validate(this)
}

Categories

Resources