I am trying to create an interactive graph using d3.js library. I want to alternate between feeding data into my d3 object from either a stored json file or directly from a dictionary (that gets created upon some user input).
To read from a file I use
d3.json('/path/to/file.json')
Upon user input a dictionary d is created. I tried using
user_file = json.dumps(d)
d3.json(user_file)
to no avail.
I have a workaround -- upon user input, create a user_file.json file with json.dump(d, '/path/to/user_file.json') and read directly from there with d3.json('/path/to/user_file.json'). Other than just feeling less elegant this adds the additional problem that the new json file gets cached.
Any advice? I'm new to javascript so advice on 'best practices' would also be appreciated.
d3.json() normally has two arguments: the url ('/path/to/file.json') and the function that will handle the result which you leave out of your examples. This handler is often an anonymous function declared inside the call to d3.json(), but it can be a named function. I would define a named function to handle the json result, then just use the same function to handle the data created on user input.
function resultHandler(error, data){
... do stuff w/ data ...
}
d3.json('/path/to/file.json', resultHandler);
function userInputHandler() {
... create data ...
resultHandler(null, d);
}
Related
I am trying to use Google Apps Script to create a form, where the fields allow for autocompletion. In other forms I’ve created, I’ve been able to pull an array of options from a google sheet, and use them to populate a drop down list, so I have to think it’s possible to do the same with an autocomplete process.
I’ve blatantly copied this example from w3schools, and it works exactly as needed, as long as I declare the array within the javascript (as done in the example). But what I haven’t been able to figure out is how to populate the array with options pulled from my google sheet.
Here is where I started:
var PMOSupport;
$(function() {
google.script.run.withSuccessHandler(buildDropDowns)
.getPMOSupport();
});
function buildDropDowns(data) {
PMOSupport = data;
console.log(PMOSupport);
}
function autocomplete(inp, arr) {
console.log("ENTER AUTO");
var currentFocus;
inp.addEventListener("input", function(e) {
// all of the remaining code is direct from the w3schools example
// I'm cutting it from here for brevity,
// and because I know this works, when using the declared array below
});
}
var countries = ["Afghanistan","Albania","Algeria","Andorra"];
// this line works fine, when using the array declared above
// autocomplete(document.getElementById("myInput"), countries);
// this line does not work, when trying to use the array populated from the google sheet
autocomplete(document.getElementById("myInput"), PMOSupport);
When I run this, the page creates, and as soon as I type into the entry field, I get a message in the console:
`Uncaught TypeError: Cannot read property 'length' of undefined`
at HTMLInputElement.<anonymous> (<anonymous>:32:28)
When I look into this, it’s saying that the ‘arr’ argument (PMOSupport) isn’t populated. That’s why I added the 2 console.log lines, to see what order things are happening. When I open the page, “ENTER AUTO” logs first, then the State Changes from Idle to Busy and Busy to Idle (while it calls getPMOSupport()), then the PMOSupport array logs in the console (also proving that I am in fact getting the correct data back from the sheet). So clearly, it’s entering function autocomplete() before it calls the google.script.run.withSuccessHandler(buildDropDowns).getPMOSupport() portion, which is why the 'arr' argument is undefined.
I’ve tried various ways of taking that out of the $(function() … }); block, to try to get the PMOSupport array populated before the autocomplete() function runs. Nothing I’ve done seems to be working.
I’m sure this is something simple, and caused by bad habits I’ve picked up over time (I’m not a developer, I just cobble things together for my team). But any help would be appreciated.
You need to call autocomplete AFTER the asynchronous code has returned. So, you need to invoke it from the callback.
function buildDropdowns(data, userObject) {
// probably you should indicate in data which field these data is for, or use
// the userObject parameter in the google.script.run API
autocomplete(document.getElementById("myInput"), data);
}
Alternately (I haven't and won't look at the w3schools code), declare your PMOSupport as a const array initially, and then add the entries from your callback into it (instead of reassigning it). This way, the variable is not undefined, it is just empty at the start. Depending on the implementation of the autocomplete code, this may or may not work for you.
const PMOSupport = [];
....
function buildDropdowns(data) {
PMOSupport.push(...data);
// or
// Array.prototype.push.apply(PMOSupport, data);
}
On the dhtmlx documentation, I see this:
The following method is responsible for specifying the way server side URL is constructed during dynamical loading calls:
<script>
tree.setXMLAutoLoadingBehaviour(mode);
</script>
The following modes variants are available here:
function - is used for calling user-defined handler that should be set as the first parameter of setXMLAutoLoading() method.
So I understand that I need to write a function to add one layer of children to the actual node (the selected node), if it has children. But what I don't understand, is how I should do this, as I have some difficulty finding the right parameters to use, to be able to find the children and add them to the tree.
I am loading a local json file, with .loadJSON("data.json");. Right now, I know I should change the behavior to function and call a function that will load the children of the clicked/expended node. I've named that function loadBranch in the code below.
myTree.setXMLAutoLoadingBehaviour("function");
myTree.setXMLAutoLoading(function (id) { loadBranch(id)});
But I am not able to write a function that will only find and add those children into my dhtmlx tree. Could any of you give me a code snippet that could be used as this function?
Thanks anyway.
PS: My "ultimate" goal is to create a default dhtmlx tree that can load a json dynamically, to compare it's performance with other trees.
Try something like this:
mytree.setXMLAutoLoadingBehaviour("function");
mytree.setXMLAutoLoading (function(id){
// here based on ID you need to load some XML
mytree.loadXML(myFunction(id));
});
I have two MVC Razor views (.cshtml) that have a virtually identical Javascript function within them.
In order to de-duplicate my javascript code I want to extract the Javascript from the views to a single external Javascript file (.js) containing the function (with a parameter that can be used to differentiate the minor differences need for each view).
The Javascript in the views contains Razor syntax to access many asp.net resource file (.resx) text values (e.g. var foo = '#ResourceFileName.Bar';) which the Razor engine unfortunately does not parse for me.
To overcome this I could pass all the resource file text values to the function in the .js file as parameters – but I prefer not to do that as the parameter list would become very large.
The RazorJS package (http://www.nuget.org/packages/RazorJS) will allow me to use Razor syntax within a .js file but this package was last published way back in 2011, which worries me.
What techniques could I use to call the externalised function without a huge long parameter list ?
What techniques could I use to call the externalised function without
a huge long parameter list ?
It doesn't need to be a huge parameter list. A single parameter containing all the necessary resource properties will be enough:
<script>
var args = #Html.Raw(Json.Encode(new
{
foo = ResourceFileName.Foo,
bar = ResourceFileName.Bar,
baz = ResourceFileName.Baz
}));
myFunction(args);
</script>
and then in your function you can access all those properties:
function myFunction(args) {
// you can use args.foo, args.bar and args.baz here
}
So I'm trying to load a javascript remotely using jquery's $.getScript, but I'm puzzled on how I can pass data to the external script.
I've tried setting variables before the call but they aren't available in the script that gets loaded, and when I try to send/retrieve them using the query string, the remote script tries to read the querystring of the base file that it gets called from, not itself. Is there any other way to do this? Or is it possible to have a javascript file read its own querystring rather than the file it's called from (that's loaded in the browser)?
// editor ini
var editor_ini = { page: current_page, action: 'edit' };
var foo = 'bar';
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', function(){});
In the execute.js file, the editor_ini and foo are both unavailable, I get the same result with:
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', { page: current_page, action: 'edit', foo: 'bar' }, function(){});
because the remote script seems to be getting the query string from the original document rather than the one used when calling the file.
If it matters, I was trying to use the query object plugin for jquery for reading the query string.
global variable declared in inline javascript is accessible in external javascript page loaded using $.getScript().
I bet that your var foo='bar' is inside a function, so not visible in global scope. Try:
window.foo = 'bar'
Truly global variables will be accessible to your script. So, if they aren't, then it's probably because your variables that you think are global actually aren't. You can either move them to the top level scope or set them on the window object like Alexei suggested.
There are other ways to share data.
1) You can put an id on the <script> tag that loads the code and then have the code get the .src value from that tag and get the query string off the script's actual URL. I like this option, but I don't know if you can do it using jQuery.getScript() since I don't think it exposes that as an option.
2) You can have the loading script call a function that you provide and return an object with the desired data from that function.
3) Once the new script is loaded, you can call a setXXX() function in that script to set the state that it needs.
4) You can set information into a cookie that the other script can read.
5) You can encode data into a URL hash value that the other script can read.
I'm looking for the "best practice" as to where the JSON should be stored if it's just a string array. Should it be stored in a variable in a script block in the HTML page? Should it be stored in a JavaScript file outside of the HTML for separation? Or should it be stored in the plugin itself?
If it should be an external js file, what's the "best practice" naming scheme for the file? I know the accepted jQuery plugin name is jquery.plugin.js or jquery.plugin-min.js (for the minified file).
Depends, if you need the JSON right away you can store it anywhere to get it executed:
<script> var myJsonObj = { ... }; </script>
If it's a lot of Data and you don't need the data right away, you can always make an ajax call to a file named something like "data.json".
For naming the plugin name, well it's really up to you, but yeah I believe jquery.pluginname.js is the standard way of doing it.
I'll second sktrdie to add the extension .json for a file like this. A gotcha that I ran across when first playing with JSON is that a JSON string is not a valid JavaScript File.
For example, If I call a file with this content:
{
'foos': 'whatever',
'bar': false,
'items': [1,2,3]
}
as the src of a <script> tag, I get this error:
Error: invalid label
Line: 2, Column: 1
Source Code:
'foos': 'whatever',
In the past I've actually hidden JSON strings in <divs> or spans like this:
<div id="jsonStorage" style="display:none">
{'foos': 'whatever','bar': false,'items': [1,2,3]}
</div>
I've also used hidden form fields for this.
If it's part of the plugin, i.e. default config, I'd store it in the plugin file itself. If it's an external config for the plugin, then it depends. It might make sense to store it in a variable in the HTML, i.e.
<script>
var myConfig = {
"foo" : "bar"
};
</script>
This could especially be the case if you need any of the JSON to be generated by your back-end code.
Really, the answer is "it depends" -- can you give more details?