Creating object from a string (dynamically) - javascript

Is there a way in javascript to create an object from a string?
Here is an example :
configuation object:
var formatter = {
telephone : {
length : 10,
formatClass : "telephoneFormatter"
},
email : {
length : 255,
formatClass : "emailFormatter"
}
}
In the fields creation I could use the following method :
function createFormatter(element){
if(formatter[element].formatClass == "telephoneFormatter"){
var formatObj = new telephoneFormatter()
}
if(formatter[element].formatClass == "emailFormatter"){
var formatObj = new emailFormatter()
}
return formatObj;
}
But I would like to create a the object dynamically, something like
function createFormatter(element){
return new formatter[element].formatClass();
}
The constructors are not available as properties of the window object, as presented in the solution to "Dynamic Instantiation In JavaScript". The class files are loaded with the page but I cannot find the object developer's tool in chrome. Thus I do not have a handle currently on the classes.
Why do I need to do that ? The application loads form dynamically, and the field are created from an elaborate JSON. While the form is beeing created, the validation is added depending on the structure of the JSON. We never know what validation must be added to a certain field. To complexify the whole thing the validation is different on the locale.
Can that be done?

you can create a custom factory function which checks the configurationObjects formaterClass and than initializes a class of that type. than pass the configurations object as constructor parameter to initialize the object.
register the available classes so the factory function is not a multi condition block.
var formatterClasses = {
'telephoneFormatter': telephoneFormatter,
'emailFormatter': emailFormatter
}
function formatterFactory(configurationObject)
{
return new formatterClasses[configurationObject.formatClass](configurationObject);
}

Related

How to apply many different rules on an object efficiently and using object oriented techniques using javascript

This is my first pass at this task i have. I need to update my UI based on the field. The field can be of different types. Here I am just checking for a memo or boolean type.
// UI Field Rule set.
var UIFieldRules = {
isMemo: function() {
return this.DataType === DataTypeKVP("Memo");
},
isBoolean: function() {
return this.DataType === DataTypeKVP("Boolean");
},
MapToList: function() {
if (UIFieldRules.isMemo.call(this) || UIFieldRules.isBoolean.call(this)) {
console.log("memo or bool");
console.log(UIFieldRules.isMemo.call(this));
console.log(this);
MAPTOLIST_SELECTOR.prop('disabled', true);
return;
} else {
MAPTOLIST_SELECTOR.prop('disabled', false);
console.log("UI field rules found memo");
}
}
};
I then call this object upon loading all the fields.
UIFieldRules.MapToList.call(field);
This works fine and satisfied the task, but now i need to apply more rules to the fields. (stop me if you heard this one before)
How can I get this set where i can just add a rule to a collection and have them all applied dynamically in javascript?
Update provide example:
function MapToList(field){
isBoolean:function(){}
isMemo : function(){}
execute : function(){
if (UIFieldRules.isMemo.call(this) || UIFieldRules.isBoolean.call(this)) {
console.log("memo or bool");
console.log(UIFieldRules.isMemo.call(this));
console.log(this);
MAPTOLIST_SELECTOR.prop('disabled', true);
return;
} else {
MAPTOLIST_SELECTOR.prop('disabled', false);
console.log("UI field rules found memo");
}
}
}
Then if i want to create more rules (which I do) should I create another object like the one above? Is there a best practice way of doing this in JS?
var rules = [];
rules.push(new MapToList(field));
rules.push(new RegExEnabled(field));
$.each(rules,function(item){
item.execute();
});
Your example approach is exactly fine. Create multiple objects that all implement the same interface, put them in a list, and then call a common method on each of them:
var rules = [MapToList, RegExEnabled];
rules.forEach(function(item){
item.execute(field);
});
However, you might want to notice that you typically you don't need a constructor + new if your object is not stateful or does not have any parameterisation, a simple object literal is enough.
And similarly, if your shared interface boils down to a single execute method, what you actually want is not a list of objects but just a list of functions you can call. It's not Java :-)

Parse.com cloud function - manually modify object fields before sending to client

I'm trying to limit the visibility of some fields of parse User object in cloud function.
I have a "Product" class, with a pointer named "owner" to a the "User" that uploaded the item.
I also have a cloud function called "getProducts", I use query.include("owner") to get the owner data at the same time.
What i want to achieve, is that the output of the "getProduct", will be a list of products, but the "Owner" object will contain only certain fields, such as "firstName" or "facebookId",
I don't want to return to the client other sensitive data even though I'm not presenting it (such as Location, email, family name etc..).
After searching I've seen 2 possible solutions.
1.) Cut the User class into 2 classes, 1 of is "Private" class with ACL just for the user.
2.) The second approach that i prefer, i to edit the fields in the cloud function, but i can't seem to change the "owner" object at the "product" object. i'm getting the error:
"Error: Uncaught Tried to save an object with a pointer to a new, unsaved object. (Code: 141, Version: 1.2.19)"
var output[] = [];
_.each(results, function(result) {
var responseData = {};
var owner = result.get("owner");
//Remove fields from the user object
var itemOwnerId = owner.id;
var itemOwnerFirstName = owner.firstName;
var itemOwnerFacebookID = owner.facebookID;
var itemOwner = new Parse.User();
itemOwner.id = itemOwnerId;
itemOwner.id = itemOwnerId;
itemOwner.firstName = itemOwnerFirstName;
itemOwner.facebookID = itemOwnerFacebookID;
result.set("owner", itemOwner);
responseData.item = result;
output.push(responseData);
});
It seems that calling result.set("owner", itemOwner) isn't good, and throwing me exepction:
rror: Uncaught Tried to save an object with a pointer to a new, unsaved object. (Code: 141, Version: 1.2.19)
What am I doing wrong?
The SDK doesn't allow an object that has been changed to be serialized into a response.
A hack way to work around this would be:
result.dirty = function() { return false; };
This would disable the check and allow you to return the modified object.
If you wanted to re-enable it later, you'd need to store the original value of result.dirty and reassign it later.

Refresh object references of an Array

Im working on a heavily javascript based site with multiple language settings. The languages are stored in an external file, f e app.en.js and app.de.js. Both of these define the lang Object:
lang = {
introText0 : 'Lorem',
introText1 : 'Ipsum',
introText2 : 'Dolor'
}
Now i have a function responsible for changing the language:
function changeLanguage(language) {
delete lang;
if(language === 1) { $.getScript('app.en.js'); }
if(language === 2) { $.getScript('app.de.js'); }
}
So far so good. This works in theory. All over the app are references to the lang Object, replacing every text. Every text that gets referenced is being updated by this change, however, there are arrays that also refer to these, and they don't update properly.
var upgradeItems = new Array();
upgradeItems[0] = new Array(lang.upgradeItem0, 13, 5, true);
I take it that the garbage Collection of JavaScript only actually deletes unreferred properties of an Object, and since these got referred before the changeLanguage() happened, they stay in the app. How do i work around this and 'refresh' these Arrays?

CQ5 AEM: how to get a component by name within a dialog using javascript

I know this will probably a simple question, but I'm new to CQ5 and AEM in general.
I have a cq:Widget node which is a simple textfield.
<rowtitlevalue
jcr:primaryType="cq:Widget"
fieldLabel="Row Title Value"
name="./rowtitlevalue"
xtype="textfield"
disabled="true"/>
Now at the moment within my JavaScript, I'm currently accessing it via
var textfield = panel.findByType('textfield')[1];
which works fine (there's another textfield before this one, hence the 1 in the array.
MY QUESTION:
how do I look for this field using it's NAME attribute within my javascript.
Any help would be appreciated.
Also, I'm using this object to run the following:
if (show != undefined) {
textfield.enable();
textfield.show();
}
else if (show == undefined) {
textfield.disable();
textfield.hide();
}
The JavaScript is located within the Component Based ClientLibs.
And this is the Listener that I have under the checkbox that defines the value of SHOW within the javascript (which is working fine).
<listeners
jcr:primaryType="nt:unstructured"
loadcontent="function(field,rec,path){Ejst.toggleRowTitle(field);}"
selectionchanged="function(field,value){Ejst.toggleRowTitle(field);}"/>
Please let me know if you see any problems with this.
Appreciate it in advance
The CQ.Dialog API defines the getField( String name) method which returns a field with the given name. In case more than one field with the same name exists, it returns an array of those fields.
Thus finding parent of xtype dialog instead of panel as shown below would solve this.
Ejst.toggleRowTitle = function(checkbox) {
var dlg = checkbox.findParentByType('dialog');
var rowTitleField = dlg.getField('./rowtitlevalue');
// perform required operation on rowTitleField
}
i did something like that a few days ago and my solution was to make a js file on the same level of the component and with the same name of the component with the information that i need.
Something like this:
The file will be called rowtitlevalue.js and the content would be:
"use strict";
use(function() {
var data = {};
data.rowtitlevalueData = properties.get("rowtitlevalue");
//more properties if needed...
return {
data: data
}
});
then where i need to use it in javascript, i need the following tags:
<sly data-sly-use.data="rowtitlevalue.js">
<script type="text/javascript">
var myVariable = ${data.rowtitlevalueData};
</script>
</sly>

jquery extension return $.each confusion

I am trying to use a jQuery extension I came across (handsontable). I am having no problem creating the table
var spreadsheet = $("#dataTable").handsontable({
rows: 3,
cols: 15,
minSpareRows: 2
});
However after I create the table I want to call various helper functions I see declared in the javascript for the Handsontable object. The problem is the extension seems to return this.each(function() { ... }); and I don't understand how I can access the underlaying Handsontable object from this. The js for the extension can be found here and I put a small demo together on the following link
http://jsfiddle.net/7JTG2/7/
as you can see I would like get the data of one of the cells when I click a button.
The relevant code is in the end:
$.fn.handsontable = function (action, options) {
if (typeof action !== 'string') { //init
options = action;
return this.each(function () {
if($(this).data("handsontable")) {
instance = $(this).data("handsontable");
...
} else {
...
instance = new Handsontable($(this), currentSettings);
$(this).data("handsontable", instance);
}
});
}
}
That means, the code sets the Handsontable instances as a data attribute to the elements (and returns the selected set to be chainable). Having one element, you can easily extract it with instance = $el.data("handsontable"). If you have a set of elements, you will need to loop over it - e.g. with each().
Looks like you could just use the onChange method of the plugin to capture data every time it is entered automatically. No need for a button. A simple example to add to your code above.
onChange: function(data) {
$("#data").append(JSON.stringify(data));
}

Categories