Why do I get "Uncaught TypeError: Illegal invocation" when I post this functions returned object into an ajax post:
base.serialize = function()
{
var data
, depth = 0;
step = function(level, depth)
{
var array = [ ]
, items = level.children("li");
items.each(function()
{
var li = $(this)
, item = $.extend({}, li.data())
, sub = li.children("ol");
if (sub.length)
{
item.children = step(sub, depth + 1);
}
array.push(item);
});
return array;
}
data = step(base.$el, depth);
return data;
};
What I'm trying to do is to convert an HTML tree with data values to an array, to save sort order to database:
/*
* ------------------------------------------------------
* Liveflex Treeview
* ------------------------------------------------------
*/
var tree = $(".dd-list").liveflex_treeview({
handle : 'div.dd-handle'
, opencollapse : '.opencollapse'
, itemMoved : function(e)
{
var sort_array = e.serialize();
// Save order
$.post('/url_fetch/sort_posts', { 'sort_array' : sort_array }, function(data)
{
console.log('Data:' + data);
});
}
});
You're trying to post an object containing DOM elements. But DOM elements have cyclic properties (they all points to the window, for example) and sometimes contains properties you can't fetch. They can't be serialized as JSON (or by any naive function just recursively serializing the properties).
Your solutions might be :
to replace the DOM elements with some kind of representation related to your application
to use a special function to serialize the DOM elements (see this related question)
Related
In three.js, I am trying to add gui by custom values. but it gives me error.
this is my code
var arm = document.getElementById('arm');
var model_arr = [];
model_arr['narm'] = (arm)? arm:0;
function init(){
...create scene, camera, load obj,mtl render it etc.
initGUI();
}
function initGUI() {
initGUICalled = true;
if (typeof model_arr !== 'undefined' && model_arr.length > 0) {
params = {
Arm: (model_arr['narm'])? model_arr['narm']:20.75,
resetval: function() { resetBody(); }
};
}
// Set up dat.GUI to control targets
lower = gui.addFolder( 'Lower Measurement' );
let ArmCtrl = lower.add( params, 'Arm', 18.75, 22.75 ).step( 0.21 ).name("Arm in Inch").listen();
ArmCtrl.onChange( function ( value ) {
mesh.morphTargetInfluences[ 0 ] = (value - 20.75)/2.1;
} );
lower.close();
gui.close();
}
function resetBody(){
initGUICalled = true ;
params.Arm = 20.75;
mesh.morphTargetInfluences[ 0 ] = 0;
}
I am trying to give value from model_arr object. So for this I have tried.
let ArmCtrl = lower.add( params, 'Arm', 18.75, 22.75 ).step( 0.21 ).name("Arm in Inch").listen();
ArmCtrl.onChange( function ( value ) {
mesh.morphTargetInfluences[ 0 ] = (value - model_arr['narm'])/2.1;
} );
and got error
Uncaught TypeError: folder.add(...).step is not a function
at new_women_xl_initGUI
I have check these reference
Saving parameters with dat.gui seems broken?
Uncaught TypeError: $(...).steps is not a function
but not get luck.
With model_arr, you're flip-flopping between using it as an array and as an object:
// Here you initialize it as an array
var model_arr = [];
// Here you're accessing it as an object, not adding any values to the array
model_arr['narm'] = (arm) ? arm : 0;
// The array's length is still 0, so params never gets a value
if (model_arr.length > 0) {
params = {
Arm: xxx
};
}
// Now when you try to access params.Arm, it doesn't exist
let ArmCtrl = lower.add( params, 'Arm', 18.75, 22.75 )
If you want to use an array, stick to an array throughout the lifetime of the variable. If you want to create an object, start with a new variable so you don't confuse the two.
If you want to add a value at the end of an array, you could use the .push() method:
var narm = (arm) ? arm : 0;
// Add value to the end of the array
model_arr.push(narm);
// Now the array's length is 1
I have data from a questionnaire (20K rows) that I need to share with the store managers (report) of our shops (400 shops). I managed to write a script that sends a pdf of my sheet to a list of e-mail addresses. But I'm stuck on writing the loop for the filter, since I can't get the setVisibleValues(values) function to work for FilterCriteriaBuilder. The setHiddenValues(values) function works, but I can't figure out how to combine that with the loop.
Sample of my Google Sheet
See below for my current code:
/**
* Filtersheet by location
*/
function FilterSheet() {
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data')
spreadsheet.getRange('F1').activate();
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues(['Amsterdam, Rotterdam'])
.build();
spreadsheet.getFilter().setColumnFilterCriteria(6, criteria);
};
/**
* Send pdf of currentspreadsheet
*/
function SendPdf() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Adres');
var blob = DriveApp.getFileById(ss.getId()).getAs("application/pdf");
blob.setName(ss.getName() + ".pdf");
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = spreadsheet.getRange(startRow, 1, numRows, 2);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = 'I hearby send you the overview of your data'
var subject = 'Overview of data';
MailApp.sendEmail(emailAddress, subject, message,{
attachments:[blob]});
}
}
getValues() returns the values of all range's cells no matter if they are shown or hidden.
Use a loop and isRowHiddenByFilter(rowPosition) to reap out all the filtered values. You could use Array.prototype.push to add the values to a new array or use Array.prototype.splice to modify the array holdin the values returned by getValues()
Related
How to use in Google Sheets setValue only for range of filtered rows (getRange for not hidden cells)?
I managemed to solve the problem.
This script takes a google spreadsheet with 2 sheets,one with Data and one with a combination EmailAdresses.
It sends a filtered list (filter column F) of sheet Data to the corresponding salon (location) in sheet Emailadresses (var mode email). Additionally, it has the option to "store" the pdf's in your google drive (var mode store)
*/
function construct() {
// settings:
//var mode = "store";
var mode = "email";
// get list of all salons and email
var salonList = SpreadsheetApp.getActive().getSheetByName('EmailAdressen');
// set endvar for loop
var endRow = salonList.getLastRow();
// loop trough the rows to get the Salon name and the corresponding email
for(i=1;i<=endRow;i++){
var salonName = salonList.getRange(i,2).getValue();
var email = salonList.getRange(i,1).getValue();
// create an array with all salons that should be hidden (we cant pick which one to show, so we have to go the other way around...)
var filterArray = [];
// create array with all salons to hide
for(c=1;c<=endRow;c++){
// get value from email list, check if it is not the current selected one and if so add it to the list to filter out
salonFilterName = salonList.getRange(c,2).getValue();
if(salonFilterName != salonName) {
filterArray.push(salonFilterName);
}
} // end for c
// filter the list with the array we just created
var spreadsheet = filterList(filterArray);
if(mode == "email"){
// export to PDF
var pdf = exportToPdf(spreadsheet);
// email to email address belonging to this salon
emailToAddress(email, pdf);
} // end if
if(mode == "store"){
StorePdf(spreadsheet, salonName);
}
} // end for i
return;
}
function filterList(salonNameArray) {
// select data sheet
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data');
// first remove all existing filters to make sure we are on a clean sheet
if(spreadsheet.getFilter()){
spreadsheet.getFilter().remove();
}
// create the filter
spreadsheet.getRange('F:F').createFilter();
// set criteria for filter with array passed from construct
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(salonNameArray).build();
// apply filter
spreadsheet.getFilter().setColumnFilterCriteria(6, criteria);
return spreadsheet;
}
function exportToPdf(ss) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data');
var blob = DriveApp.getFileById(ss.getId()).getAs("application/pdf");
blob.setName(ss.getName() + ".pdf");
return blob;
}
function StorePdf(ss, salonName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data');
var blob = DriveApp.getFileById(ss.getId()).getBlob();
blob.setName(salonName + "_" + Utilities.formatDate(new Date(), "GMT+1", "ddMMyyyy")+".pdf");
DriveApp.createFile(blob);
return;
}
function emailToAddress(email, pdf) {
MailApp.sendEmail(email, 'Type here the subject', 'Type here the body',{
attachments:[pdf]});
return;
}
var playersRef = firebase.database().ref("team_mapping/");
playersRef.orderByChild("score").limitToFirst(7).on("child_added", function(data) {
}
Using this query, I can sort it in ascending order. But, I wanted to sort in descending order. Can any body suggest me with some way to do this. Any help will be appreciated.
Thanks in Advance!!
just use reverse() on the array , suppose if you are storing the values to an array items[] then do a this.items.reverse()
ref.subscribe(snapshots => {
this.items = [];
snapshots.forEach(snapshot => {
this.items.push(snapshot);
});
**this.items.reverse();**
},
You can limit to the last 7 which will give you the highest scores since the query is in ascending order. Then all you have to do is reverse the last 7 you get for them to be in descending order.
var playersRef = firebase.database().ref("team_mapping/");
var playersData = [];
var pageCursor;
playersRef.orderByChild("score").limitToLast(7).on("child_added", function(data) {
playersData = [data] + playersData;
}
UPDATE
Here is an example of how you could paginate by score.
const query = firebase.database().ref("team_mappings").orderByChild('score');
var snapshots = [];
function reversedChildren(snapshot) {
var children = [];
snapshot.forEach(function (child) { children.unshift(child); });
return children;
}
function addPlayerToLeaderBoard(snapshot) {
var key = snapshot.key;
var place = snapshots.indexOf(snapshot) + 1;
var score = snapshot.child('score').val();
$('#leaderboard').append(`<li><b>${key}: ${score}</li>`);
}
function parsePage(snapshot) {
var children = reversedChildren(snapshot);
children.forEach(function (child) {
players.push(child);
addPlayerToLeaderBoard(child);
});
pageCursor = children[children.length - 1];
}
function reloadPlayers() {
players = [];
pageCursor = null;
query.limitToLast(5).once('value').then(parsePage);
}
function loadMorePlayers() {
query.endAt(pageCursor).limitToLast(5).once('value').then(parsePage);
}
reloadPlayers();
$('#reload').on('click', reloadPlayers);
$('#load_more').on('click', loadMorePlayers);
Unfortunatelly, there is not a shortcut for this yet. However, if you are using Listview or Recyclerview as UI, you could simply solve this issue by reversing the UI,by reversing Listview or Recyclerview
For Recyclerview you could reverse as follows:
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager)
For Listview:
listView.setStackFromBottom(true);
I need to get the longitude and latitude of a location from a text file through AJAX then create a map using that information. This is what I have done:
function createMap(){
var request;
if (window.XMLHttpRequest)
{
request = new XMLHttpRequest();
}
if (request)
{
var number = Math.floor( (Math.random() * 3) + 1 );
var url = "text_" + number + ".txt";
request.open("GET", url,true);
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
var syd=new google.maps.LatLng(-33.884183, 151.214944);
var woll=new google.maps.LatLng(request.responseText);
function initialize()
{
var mapProp = {
center:syd,
zoom:6,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("outputAJAX"),mapProp);
var myTrip=[syd,woll];
var flightPath=new google.maps.Polyline({
path:myTrip,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2
});
flightPath.setMap(map);
}
initialize();
}
}
request.send();
} else {
document.getElementById("outputAJAX").innerHTML = "<span style='font-weight:bold;'>AJAX</span> is not supported by this browser!";
}}
However, the map didn't show up. Do you guys have any suggestion?
A google.maps.LatLng object takes two Numbers as its arguments:
LatLng(lat:number, lng:number, noWrap?:boolean) Creates a LatLng object representing a geographic point. Latitude is specified in degrees within the range [-90, 90]. Longitude is specified in degrees within the range [-180, 180]. Set noWrap to true to enable values outside of this range. Note the ordering of latitude and longitude.
This won't work (you are only passing one argument, a string):
var woll=new google.maps.LatLng(request.responseText);
Assuming request.responseText is a comma separated string containing two numeric values, this should work:
var coordStr = request.responseText;
var coords = coordStr.split(",");
var woll = new google.maps.LatLng(parseFloat(coords[0]),
parseFloat(coords[1]));
proof of concept fiddle
I have data in the form of an object, and I'm trying to bind only some attributes of the object to my selection as data.
The object looks something like this:
var data = {'attr1': 100,
'attr2': "foo",
'attr3': 200,
...
'attr20': 34}
I have the attribute names I'm interested in stored in an array:
keys = ['attr1', 'attr3', 'attr20']
I want to bind the values (100, 200, 34). I'm doing the following:
var selection = d3.select('ul')
.selectAll('li')
.data(keys, function(key){ return data[key]})
.enter()
.append('li')
.text(function(d){return d})
And instead of getting "100" "200" and "34" as text outputs, I get "attr1", "attr2", and "attr3". I would have expected the key function to return the values of data, but it's only returning the keys.
Any suggestions on how I can bind only some attributes of the data object, when I know those keys?
I know my use is a little "backwards"... I made a jsfiddle here to show the output: http://jsfiddle.net/ChwLM/1/
You will need to filter change the data before setting it – http://jsfiddle.net/ChwLM/3/.
In d3, when you pass a function as the second argument, the following is how it gets called:
for (i = -1; ++i < m;) {
keyValue = key.call(groupData, nodeData = groupData[i], i);
if (node = nodeByKeyValue.get(keyValue)) {
updateNodes[i] = node;
node.__data__ = nodeData;
} else if (!dataByKeyValue.has(keyValue)) { // no duplicate data key
enterNodes[i] = d3_selection_dataNode(nodeData);
}
dataByKeyValue.set(keyValue, nodeData);
nodeByKeyValue.remove(keyValue);
}
groupData is ['attr1', 'attr3', 'attr20']. What you are changing with your function is the key of the data, not the value. With this – nodeData = groupData[i] – the value is getting set before you can change it. Here's the relevant piece from the fiddle above:
keys = ['attr1', 'attr3', 'attr20'];
filtered = [];
for (var i = 0, l = keys.length; i < l; ++i) {
filtered.push(data[keys[i]]);
}
And then you can pass filtered in to .data.