I need to programatically create an object that got one pair of property : value like tmpCol["formatter"]=color where color is defined like
var colors = function backgroundColor(cell, formatterParams){}
everything works fine on jsFiddle
But I need to create the object on the fly and outside the javascript. I using Google Script where I create definition of column headers based on data. I tried to define a dummy function var colors = function backgroundColor(cell, formatterParams){} on the server side so the definition would even pass a run. But when I run the page in a browser the function definition seems to me to be a text rather a function. The browser makes a call the get the data using google.script.run the definition is returned by GAS.
Typed definition tmpCol["formatter"]=colors; works but not the one when processed by GAS
The html code on server side looks like
<script>
var colors = function backgroundColor(cell, formatterParams){
var value = cell.getValue();
if ("color" in formatterParams) {
var color = cell.getRow().getData()[formatterParams["color"]];
if (color){
cell.getElement().style.backgroundColor = cell.getRow().getData()[formatterParams["color"]];
}
}
return value;
}
var initialTableData = [{id:0,name:"nahrávají se data"}];
var table = new Tabulator("#zz-test", {
layout:"fitColumns",
responsiveLayout:"hide",
data:initialTableData,
dataTree:true,
selectable:true,
columns:[
{title:"",
field:"name",
headerSort:false,
},
],
});
google.script.run.withSuccessHandler(updateTable).callLibraryFunction("zzlib.getTabulatorData",'A87J8HRS1');
function updateTable(data){
table.deleteColumn("name");
for ( var c = 0; c < data.tableColumns.length; c++){
table.addColumn(data.tableColumns[c]);
}
//test
var tmpCol = {};
tmpCol["title"]="test 1";
tmpCol["field"]="test1";
tmpCol["headerSort"]=false;
tmpCol["formatter"]=colors;
tmpCol["formatterParams"]={color:"color1"};
columns = [
{title:"", field:"name", width:200},
tmpCol,
{title:"Test2", field:"test2", width:200,formatter:colors,formatterParams:{color:"color2"}}
];
// table.deleteColumn("name");
// table.deleteColumn("test1");
// table.deleteColumn("test2");
for ( var c = 0; c < columns.length; c++){
// table.addColumn(columns[c]);
}
console.log(columns);
// test
table.setData(data.tableData);
}
</script>
I need to define formatter for two columns. So inside the for cycle I tried these so far.
for ( var c = 0; c < data.tableColumns.length; c++){
if ("formatter" in data.tableColumns[c]) {
//console.log(eval(data.tableColumns[c]["formatter"]));
//data.tableColumns[c]["formatter"]= new Function("return " + data.tableColumns[c]["formatter"]);
data.tableColumns[c]["formatter"]= var colors = new Function("return " + data.tableColumns[c]["formatter"]);
//eval(data.tableColumns[c]["formatter"]);
//eval("var colors = " + data.tableColumns[c]["formatter"]);
console.log("eval");
}
}
Any idea how to create the object value on the server side and pass it correctly to the browser?
Assuming you have:
var functionString = "function backgroundColor(cell, formatterParams){}";
You can use Function constructor: #Recommended
var colors = new Function("return " + functionString)()
This parses our function inside an anonymous function, we add return so by calling the anonymous function we can get our target function, and in the end we add the call ()
example:
var functionString = "function backgroundColor(cell, formatterParams){ return 'Hey!'}";
var anonymousFunction = new Function("return " + functionString);
var targetFunction = anonymousFunction();
console.log(anonymousFunction);
console.log(anonymousFunction());
console.log(targetFunction);
console.log(targetFunction());
Read more here
or you can use eval: # Not Recommended
eval("var colors = " + functionString);
This one will parse and evaluate your string as a javascript code
However, this is a risky approach, try to avoid it
Read more here
Related
I'm trying to get either options or, ideally, dynamicTable passed from initializeTable to the applyTableFilters function and I'm having problems getting the expected values. I'm using List.js to make a table dynamic and I need to pass or recreate the dynamicTable object so I can go ahead and use it to filter the table.
Here is the function that creates the List.js object from the HTML table:
function initializeTable(options) { // initializes table to be dynamic using List.js functions
var dynamicTable = new List("table-content", options);
dynamicTable.on("updated", function (list) { // writes a message to the user if no results are found
if (list.matchingItems.length == 0) {
document.getElementById("no-results").style.display = "block";
}
else {
document.getElementById("no-results").style.display = "none";
}
});
console.log(dynamicTable);
console.log(options);
console.log(arguments.length);
applyTableFilters.bind();
}
I've tried different methods to pass the variables to the function below. I tried .call, applyTableFilters(args), and .apply, but the problem is that I do not want the function to execute from inside here, only when the click event from the button goes off (not shown in these functions).
This is the function I want to pass the object to and proceed to make the filter functions using it:
function applyTableFilters(dynamicTable) {
var form = document.getElementById("filter-form");
//console.log(options);
//var dynamicTable = new List("table-content", options);
console.log(dynamicTable);
var filters = form.querySelectorAll('input[type="checkbox"]:checked');
dynamicTable.filter(function (item) {
console.log(item);
console.log(item._values);
if (item.values().id == 2) {
return true;
}
else {
return false;
}
//var filterStrings = [];
//console.log(filters);
//for (var i = 0; i < filters.length; i++) {
// var filterVal = filters[i].value;
// var filterString = "(" + item.values().column == filterVal + ")"; // filterVal.contains(item.values().column) ||
// filterStrings.push(filterString);
// console.log(filterVal);
// console.log(filterString);
//}
//console.log(filterStrings);
//var filterString = filterStrings.join(" && ");
//console.log(filterString);
//return filterString;
});
}
I've used:
applyTableFilters.bind(this, dynamicTable/options);
applyTableFilters.bind(null, dynamicTable/options);
applyTableFilters.bind(dynamicTable/options);
Switching between the two since I don't need both passed if one ends up working, etc. I always get a mouse event passed in and that's not even the right type of object I'm looking for. How can I get the right object passed? Also all the values in the first function are not empty and are populated as expected so it's not the original variables being undefined or null. Thanks in advance.
From your initializeTable function return a function that wraps the applyTableFilters function with the arguments you want.
Then assign the returned function to a var to be executed later.
function initializeTable(options) {
var dynamicTable = new List("table-content", options);
// other stuff
return function () {
applyTableFilters(dynamicTable)
}
}
// other stuff
var applyTableFiltersPrep = initializeTable(options)
// later, when you want to execute...
applyTableFiltersPrep()
JSFiddle example
I am making a simple hmtl/js game. I'd like to have all the data of the Game in DataofGame. It is like tennis, it is simpler than tennis: there is only set and match. changeinSet is called on click.
But I think i have a problem with private variable so it doesn't work.
Uncaught TypeError: Cannot read property 'WordsoftheGame' of undefined
//Added
document.getElementById('playboutton').addEventListener('click', newGame);
function newGame() {
var DataofGame = new newGameData();
}
// New game
function newGameData() {
this.pointTeam1 = 0;
this.pointTeam2 = 0;
this.WordsoftheGame = ShuffleListe();
this.ASet = new aSet();
}
//How the set is manage ********************
function aSet() {
var oneWord = DataofGame.ListeMot;
// display the word and delete it from the list
document.getElementById('jouer').innerHTML = oneWord[0];
DataofGame.WordsoftheGame.shift();
this.turn = true;
this.score = 0;
}
function changeinSet() {
DataofGame.ASet.score += 1;
//This is the other team's turn:
DataofGame.ASet.turn = !DataofGame.ASet.turn;
};
//shuffle liste
ListOfWords = ['Artiste', 'Appeler', 'Cheval', 'Choisir', 'Ciel', 'Croire', 'Dormir'];
function ShuffleListe() {
data = shuffle(ListOfWords);
return data;
}
function newGameData(){
this.pointTeam1=0;
this.pointTeam2=0;
this.WordsoftheGame= ShuffleListe();
this.ASet=new aSet();
}
//How the set is manage ********************
function aSet(){
var oneWord=DataofGame.ListeMot;
// display the word and delete it from the list
document.getElementById('jouer').innerHTML=oneWord[0];
DataofGame.WordsoftheGame.shift(); // << DataofGame not assigned yet
this.turn=true;
this.score=0;
}
Here when you're accessing DataofGame, it's not yet assigned because you're inside the constructor when calling aSet().
What you want to achieve is not completely clear, but if it's adding an ASet method to your object, you could write something like this:
function newGameData(){
this.pointTeam1=0;
this.pointTeam2=0;
this.WordsoftheGame= ShuffleListe();
this.ASet = function() {
// your code
};
}
NB your coding style for names is a bit messy, you should use uppercases consistently. The usage is to start constructor names with uppercases, the rest in lower cases.
You can let the function return an object with the data or just set the object.
function newGameData(){
return {
pointTeam1 : 0,
pointTeam2 : 0,
WordsoftheGame : ShuffleListe(),
ASet : new aSet()
}
}
But I would recommend to search for how to work with objects in javascript. Maybe this helps:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
I have a Firebase database set up like this:
>>XXX
>>>>dislike: 0
>>>>like: 1
In my web application, I can retrieve their value into console by:
var fb = new Firebase('https://xxx.firebaseio.com');
fb.child('like').once('value',function(snapshot){
console.log(snapshot.val());
});
fb.child('dislike').once('value',function(snapshot){
console.log(snapshot.val());
});
Now if I want to retrieve these values into the global scope, it will return undefined when I do this:
var fb = new Firebase('https://xxx.firebaseio.com');
var like = fb.child('like').once('value',function(snapshot){
return snapshot.val();
});
var dislike = fb.child('dislike').once('value',function(snapshot){
return snapshot.val();
});
Of course I have a silly solution to this problem, by putting entire script inside these two scopes - but it would be a disasters if I have hundreds of scopes to work with, and if I like to dynamically turn them on and off. Here is my solution:
var likeRef = new Firebase('https://xxx.firebaseio.com/like');
var dislikeRef = new Firebase('https://xxx.firebaseio.com/dislike');
likeRef.once('value',function(likeObj){
dislikeRef.once('value',function(dislikeObj){
var like = likeObj.val();
var dislike = dislikeObj.val();
});
});
Here is another answer suggested by Frank van Puffelen from the source <Passing variable in parent scope to callback function>, and it didn't quite work because seem to only work for script that is adding a new object in an array. Here is my attempt:
var like = 0;
var dislike = 0;
var val = 0;
var fb = new Firebase('https://xxx.firebaseio.com/');
function fb_like() {
fb.child('like').on('value', read_val);
return val;
}
function fb_dislike() {
fb.child('dislike').on('value', read_val);
return val;
}
function read_val(snapshot) {
var val = snapshot.val();
}
fb_like();
fb_dislike();
console.log(like);
console.log(dislike);
As you might expected, the console logs 0 and 0, instead of the values in like and dislike in firabase xxx database.
In fact, I took a step further and use array instead of integer value, and it still won't work:
var like = [0];
var dislike = [0];
var val = [0];
var fb = new Firebase('https://xxx.firebaseio.com/');
function fb_like() {
fb.child('like').on('value', read_val);
console.log('fb_like: ' + val[0]);
return val;
}
function fb_dislike() {
fb.child('dislike').on('value', read_val);
console.log('fb_dislike: ' + val[0]);
return val;
}
function read_val(snapshot) {
val[0].value = snapshot.val();
}
fb_like();
fb_dislike();
console.log('Like: ' + like[0]);
console.log('Dislike: ' + dislike[0]);
The console will logs:
fb_like: 0
fb_dislike: 0
Like: 0
Dislike: 0
This means probably means only adding (pushing) new objects into an array will work on a global scope, changing the value of an object will only effect the local scope.
Then, I realized even adding (pushing) new objects into an array cannot effect the global scope. Here is my attempt:
var like = 0;
var likeObj = [];
var fb = new Firebase('https://xxx.firebaseio.com/');
function fb_like() {
fb.child('like').on('value', read_like);
console.log('fb_like: ' + likeObj[0]);
return likeObj;
}
function read_like(snapshot) {
likeObj.push(snapshot.val());
console.log('likeObj: ' + likeObj[0]);
}
fb_like();
like = likeObj[0];
console.log('Like: ' + like);
As a result, the console logs:
fb_like: undefined
Like: undefined
likeObj: 1
This probably means the read_like() isn't effecting scopes larger than itself, event with array.push command.
<html>
<body>
var el = document.getElementById("tab");
var tab = Table(el, data);
tab.showData();
tab.takeData();
var PieChart=drawPieChart(canvas);
</body>
</html>
<script>
function Table(el, data) {
...
...
return{
showData: function(){
...
...
}
takeData: function(){
var myData=new Array();
for (var i = 0; i < val2; i++) {
myData[i] = document.getElementById('polja' + i).value;
}
}
...
...
};
}
function drawPieChart(canvas){
...
...
return{
getmyData(
);
...
...
};
}
</script>
how can i get myData in function "drawPieChart" except making myData global variable? thx
i was thinking in html make somthing like this PieChart.getMyData(Table.takeData); or something like that
Based on your edit, you can do this:
function Table(el, data) {
var myData = new Array(); // Not global but accessible to every function that gets returned here
return{
// removed unnecessary code
takeData: function(){
for (var i = 0; i < val2; i++) {
myData[i] = document.getElementById('polja' + i).value;
}
},
function drawPieChart(canvas){
// Can access myData here
}
}
}
First, the problems with your code:
You have a block of JavaScript sitting inside <body>. This is not standard, not allowed, and will fail. Specifically, it will be displayed as text on the page, rather than being executed as JavaScript. All JavaScript must be located in one of the following places: an inline <script> tag, an external file that you load with a <script> tag, an event attribute such as onload="...", or an attribute that can run JavaScript, such as href="javascript:..." on <a> elements.
You have a syntax error in the object you're returning from Table(); there is no comma separator between the hash key/value pairs (showData() and takeData()). The comma is required.
You have some uninitialized variables, including val2, data, and canvas. You probably just excerpted your code to omit the relevant initialization, but you should try to present complete self-contained code samples when asking questions on Stack Overflow.
With regard to your question, the object tab you are returning from Table() looks an awful lot like an instance object of a class in any OO language. JavaScript supports the OO paradigm via the prototype pattern, so a sensible approach would be to make Table a full class by defining its prototype. If you do this, you can make tab a full instance of Table by creating it with the new operator, and then you can store the myData array as an attribute on tab. Here's a random demonstration based on your sample code:
http://jsfiddle.net/awytnngu/
HTML:
<div id="tab">
<input id="polja0" value="def1"/>
<input id="polja1" value="def2"/>
<input id="polja2" value="def3"/>
</div>
JS:
function Table(el,data) {
this.el = el;
return this;
}
Table.prototype.showData = function() {
// ...
};
Table.prototype.takeData = function() {
this.myData = new Array();
var val2 = this.el.children.length;
for (var i = 0; i < val2; ++i)
this.myData[i] = document.getElementById('polja'+i).value;
};
Table.prototype.drawPieChart = function(canvas) {
alert(this.myData);
};
var el = document.getElementById('tab');
data = 'whatever';
var tab = new Table(el,data);
tab.showData();
tab.takeData();
canvas = 'whatever';
var PieChart = tab.drawPieChart(canvas);
Just to throw in another possible approach, much simpler than the prototype solution, you can take an OUT parameter on takeData() and then pass it as an argument to drawPieChart():
http://jsfiddle.net/uv8bh6nj/
HTML:
<div id="tab">
<input id="polja0" value="def1"/>
<input id="polja1" value="def2"/>
<input id="polja2" value="def3"/>
</div>
JS:
function Table(el,data) {
return {
showData:function() {
// ...
},
takeData:function(OUT) {
OUT.myData = new Array();
var val2 = el.children.length; // closure
for (var i = 0; i < val2; ++i)
OUT.myData[i] = document.getElementById('polja'+i).value;
}
};
}
function drawPieChart(canvas,myData) {
alert(myData);
}
var el = document.getElementById('tab');
data = 'whatever';
var tab = new Table(el,data);
tab.showData();
var takeDataOUT = {};
tab.takeData(takeDataOUT);
canvas = 'whatever';
var PieChart = drawPieChart(canvas,takeDataOUT.myData);
I'm trying to translate a PHP class into JavaScript. The only thing I'm having trouble with is getting an item out of an array variable. I've created a simple jsfiddle here. I cannot figure out why it won't work.
(EDIT: I updated this code to better reflect what I'm doing. Sorry for the previous mistake.)
function tattooEightBall() {
this.subjects = ['a bear', 'a tiger', 'a sailor'];
this.prediction = make_prediction();
var that = this;
function array_random_pick(somearray) {
//return array[array_rand(array)];
var length = somearray.length;
var random = somearray[Math.floor(Math.random()*somearray.length)];
return random;
}
function make_prediction() {
var prediction = array_random_pick(this.subjects);
return prediction;
}
}
var test = tattooEightBall();
document.write(test.prediction);
Works fine here, you are simple not calling
classname();
After you define the function.
Update
When you make a call to *make_prediction* , this will not be in scope. You are right on the money creating a that variable, use it on *make_prediction* :
var that = this;
this.prediction = make_prediction();
function make_prediction() {
var prediction = ''; //initialize it
prediction = prediction + array_random_pick(that.subjects);
return prediction;
}
You can see a working version here: http://jsfiddle.net/zKcpC/
This is actually pretty complex and I believe someone with more experience in Javascript may be able to clarify the situation.
Edit2: Douglas Crockfords explains it with these words:
By convention, we make a private that variable. This is used to make
the object available to the private methods. This is a workaround for
an error in the ECMAScript Language Specification which causes this to
be set incorrectly for inner functions.
To see the complete article head to: http://javascript.crockford.com/private.html
You never call classname. Seems to be working fine.
Works for me:
(function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
function pickone(somearray) {
var length = somearray.length;
var random = somearray[Math.floor(Math.random()*length)];
return random;
}
var random_item = pickone(this.list);
document.write(random_item);
}());
Were you actually calling the classname function? Note I wrapped your code block in:
([your_code]());
I'm not sure what you're trying to accomplish exactly with the class structure you were using so I made some guesses, but this code works by creating a classname object that has instance data and a pickone method:
function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
this.pickone = function() {
var length = this.list.length;
var random = this.list[Math.floor(Math.random()*length)];
return random;
}
}
var cls = new classname();
var random = cls.pickone();
You can play with it interactively here: http://jsfiddle.net/jfriend00/ReL2h/.
It's working fine for me: http://jsfiddle.net/YznSE/6/ You just didn't call classname(). If you don't call it, nothing will happen ;)
Make it into a self-executing function like this:
(function classname() {
this.list = [];
this.list[0] = "tiger";
this.list[1] = "lion";
this.list[2] = "bear";
function pickone(somearray) {
var length = somearray.length; //<---WHY ISN'T THIS DEFINED??
var random = somearray[Math.floor(Math.random() * length)];
return random;
}
var random_item = pickone(this.list);
document.write(random_item);
})();
var test = tattooEightBall();
document.write(test.prediction);
Should be:
var test = new tattooEightBall(); //forgot new keyword to create object
document.write(test.prediction()); // forgot parens to fire method
and:
this.prediction = make_prediction();
Should be:
this.prediction = make_prediction;