I want to load multiple files to use in D3.js. Queue.js seems to be a nice tool for that. Since d3.js supports more advanced XHR functionalities in v3, I want to load multiple files with Queue.js and show the loading progress, and abort loading of all files on error.
This is how you check the progress and how to use Queue.js: https://github.com/mbostock/d3/wiki/Upgrading-to-3.0
I don't know how to combine these pieces of code.
This is what I have until now.
JSFiddle
I think it is better that there would be a progress event handler on Queue.js, but I don't know how to implement this.
Example code:
queue()
.defer(d3.json, "file1.json") // https://api.github.com/repos/mbostock/d3")
.defer(d3.json, "file2.json")
.progress(function() { console.log(d3.event.loaded/d3.event.total; }) // or use argument?
.error(function(error) { this.abort(); console.log(error); })
.await(function(data) { console.log(data); });
The object returned by queue() in queue.js doesn't have the methods "progress" and "error". Here is a link to the source code: https://github.com/mbostock/queue/blob/master/queue.js.
As queue.js takes an xhr object and uses 'apply' to execute the function, the following workaround worked for me. It involves using the get() method of an xhr object to execute the function.
Sample code:
queue().defer(d3.json("file1.json")
.on("progress", function({console.log(d3.event.loaded);})
.get, /*First argument*/ "error")
.await(function (error, file1_data) {console.log(file1_data);});
Hope this helps.
Related
I'm a beginner in Ionic and Firebase. To learn using ionic+firebase, I'm writing a RandomQuote app to fetch a random entry from Firebase. A reload() method is called when I click a reload button, and the random quote is displayed as expected.
However, I also want the quote to display when the app is loaded, i.e., before I click the reload button. I call the reload() method in the constructor but it doesn't work. I have tried to search for answers on the web but cannot find anything that I could understand. Not sure if I'm searching the wrong keywords or in the wrong domains.
The following is the reload() method that I put in my FirebaseProvider class and called from my home.ts:
reload(){
this.afd.list('/quoteList/').valueChanges().subscribe(
data => {
this.oneQuote = data[Math.floor(Math.random() * data.length)];
}
)
return this.oneQuote;
}
Can anyone give me some hints? Or any pointer to useful books / materials for beginners will also be highly appreciated. Thank you very much.
Data is loaded from Firebase asynchronously. This means that by the time your return statement runs this.oneQuote doesn't have a value yet.
This is easiest to say by placing a few log statements around your code:
console.log("Before subscribing");
this.afd.list('/quoteList/').valueChanges().subscribe(
data => {
console.log("Got data");
}
)
console.log("After subscribing");
When you run this code, the output is:
Before subscribing
After subscribing
Got data
This is probably not what you expected. But it completely explains why your return statement doesn't return the data: that data hasn't been loaded yet.
So you need to make sure your code that needs the data runs after the data has been loaded. There are two common ways to do this:
By moving the code into the callback
By returning a promise/subscription/observable
Moving the code into the callback is easiest: when the console.log("Got data") statement runs in the code above, the data is guaranteed to be available. So if you move the code that requires the data into that place, it can use the data without problems.
Returning a promise/subscription/observable is a slightly trickier to understand, but nicer way to doing the same. Now instead of moving the code-that-needs-data into the callback, you'll return "something" out of the callback that exposes the data when it is available. In the case of AngularFire the easiest way to do that is to return the actual observable itself:
return this.afd.list('/quoteList/').valueChanges();
Now the code that needs the quotes can just subscribe to the return value and update the UI:
reload().subscribe(data => {
this.oneQuote = data[Math.floor(Math.random() * data.length)];
}
A final note: having a reload() method sounds like an antipattern. The subscription will already be called whenever the data in the quoteList changes. There is no need to call reload() for that.
I have just begun using Cucumber (xolvio:cucumber#0.20.2_1) with Meteor to test my project, and I am having difficulty returning a value from a Meteor.methods stub I created within a step definition.
register-user.js
this.When(/^he clicks the verification link in his email$/, function () {
console.log(this.server.call('_getUser'));
});
registration.js
Meteor.methods({
_getUser: function() {
return Meteor.users.findOne({'emails.address': 'anyemail#email.com'});
});
The log outputs a huge object that looks like the state of the system. I noticed elsewhere that someone suggested
this.server.call('aMethod').then(function(response) {
// you can use the response here
});
But when I do this in my project, cucumber logs Object [object Object] has no method 'then'.
I also tried Meteor.users.findOne({'emails.address': anemail#email.com}); within the step definition, but I am receiving the error Meteor is not defined
Any help or guidance would be greatly appreciated.
EDIT
I realized that when I was logging a huge object, it was because the Meteor method _getUser wasn't returning anything. I then tried Meteor.users.find({}).fetch() and it returned an empty array, even though my meteor-cucumber collection had my user there, which is another issue I'm experiencing.
You don't need to use this or then, the latest version of Chimp is synchronous, so you just do this:
var user = server.call('_getUser')
Just be sure to have registration.js as part of your Meteor app and not part of the test codebase.
So... Meteor.defer(function(){ // stuff }) isn't in the docs:
https://github.com/meteor/meteor/issues/2176
But this links seems to say that it's simply equivalent to
Meteor.setTimeout(function(){ // stuff }, 0);
If that's the case, how does this do, um, anything? It's basically saying "wait for 0 ms and then run the function".
So... it runs the function instantly.
What am I missing here? Is this kind of like Tracker.afterFlush or something? Does it somehow wait for "things" (what kind of things?) to finish before running?
I see Meteor.defer() a lot on SO being used as a bit of a hack on added helper methods to run after the dom is (somewhat) loaded - basically to get the same effect as running code inside of a Template.foo.rendered method.
However, the main (and best) use of Meteor.defer is to run a task asynchronously.
Let's say we have an app where we are sending an email. On the server, it may take several seconds for that to process inside of a meteor method, slowing down your application drastically. However, if you wrap that process in a Meteor.defer the email processing won't block execution, the email still sends (when it gets a chance, not instantly), but everything runs much faster, since the code that follows isn't waiting. There is a great example lesson about deferring execution at Bulletproof Meteor.
You can actually get the same effect with a setTimeout(f,0) - if you have a slow function, you could wrap it in the setTimeout and the rest of the code will complete, and 'defer' the slow process in the timeout, so although it doesn't seem like it, setTimeout(f,0) does actually have a pretty useful purpose!
To see an example of this in action, here's a fiddle, open the console and watch where 'foo' logs.
I faced some issue in my project because of asynchronous callback. Inside onCreated i was making a server Meteor.call and set the response inside reactiveVar. And i was doing something inside onRendered with that reactiveVar. Every time reactiveVar was showing undefined.
So i used Meteor.defer(function(){...}) inside onRendered and it sloved my issue.
Here is some demo with and without using Meteor.defer()
Template.myTemplate.onCreated(function () {
var instance = this;
instance.myTemplateModel = new ReactiveDict();
Meteor.call('all-user', function(err, res){
if(res){
console.log('inside callback');
instance.myTemplateModel.set('users', res);
}
});
});
Template.myTemplate.onRendered(function () {
var instance = this
console.log('rendered start');
Meteor.defer(function(){
console.log(instance.myTemplateModel.get('users'));
});
console.log('render end');
});
Console:
/*Without Meteor.defer()*/ | /*With Meteor.defer()*/
render start | inside callback
undefined | render start
render end | render end
inside callback | [Object, Object, Object]
I am using a "2-step view", where I have a layout template (common for all pages) with yepnope's load (in the html head) of jQuery and some plugins. Something like:
yepnope(['/path/to/jquery.js', '/path/to/jquery.plugin-common.js']);
Sometimes I need another plugin, so within the inner template I do additional (in the html body):
yepnope('/path/to/jquery.plugin-additional.js');
Now that I need to do the actual js magic, can I safely do just:
yepnope({
complete: function(){...}
});
So, the questions are in fact two:
Is the complete callback fired upon the load completion of the global resources stack? So it's safe to "register" this complete callback anywhere assuming that all needed resources have been registered before?
Can I safely call yepnope just with the "complete" callback option? I mean, as long as I'm not "testing" anything and my resources have been registered already...
I have tried it and it worked, but I'm not fully aware if it's internals, so I just want to make sure that I'm not doing something wrong... Thanks in advance.
--
And one last thing. The manual under preload! says:
yepnope({
load: 'preload!jquery.1.5.0.js',
callback: function (url, result, key) {
window.jQuery; // undefined (but it's cached!);
}
});
Can you please explain what is this about? I am completely missing the point here...
I can help on the preload! question.
The idea of preload! is that yepnope will download the file but will not execute it.
It transfers the jQuery file, but it will still be undefined after callback is being called, as it was not injected as a script into the page.
In my opinion, you are doing this wrong. I'm surprised that it work, but maybe your scripts are loaded before the call of the "complete" function. I think you should do that:
yepnope({
load: ['/path/to/jquery.js', '/path/to/jquery.plugin-common.js']
callback: {
"jquery.js": function () {
console.log("jquery loaded!");
},
"jquery.plugin-common.js": function () {
console.log("plugin loaded!");
}
}
});
And for the additional plugin in the html body:
yepnope({
load: '/path/to/jquery.plugin-additional.js'
callback: function () {
$(document).ready(function(){
console.log("plugin-additional loaded!");
});
}
});
Of course, replace console.log() by your code related to each plugin that you can safely execute in this context.
for the last question, i can't say anything, because i didn't succeed to make preload! working, maybe it's buggy, maybe i didn't understand how it work...
For school, i have to develop a Twitter client with ASP.NET.
In the app, i have a list of tweets with a delete link. This link is created with the helper Ajax.ActionLink() and i specified a callback function for OnSuccess event.
This link is okay : the action is performed, the callback is triggered BUT i can't access data sent in the Ajax response.
The callback receive only one argument. Here is the dump of this object :
>> Sys.Mvc.AjaxContext
$0: 0
$1: null
$2: Sys.Net.XMLHttpExecutor
$3: Sys.Net.WebRequest
$4: null
Where is my responseText ? I know that the response has a content (according to Chrome developer tools) and i really want to access it.
Bonus : can Ajax client automatically parse the response as JSON (the action returns JSON properly with the JSON method) ?
Thanks ! ;)
The deadline of this school project is over.
I used get_data on the response.
I'm quite disappointed by the lack of documentation for this trivial need. Even now i know the way, i can't find that on MSDN… Such a pity. :(
Back to my precious Ruby on Rails, i feel better.
Good day and thanks for your help anyway ! :)
Try calling get_object() on your AjaxContext to get a javascript object or get_data() to get the text. An easier method though is to have your OnSuccess function take an argument which will be the object returned.
public ActionResult ReturnJson()
{
return Json(new { TestMessage = "Hello, world!" }, JsonRequestBehavior.AllowGet);
}
And the view...
<script type="text/javascript">
function AjaxSuccess(obj) {
alert(obj.TestMessage);
}
</script>
#Ajax.ActionLink("Say Hi", "ReturnJson", new AjaxOptions() { OnSuccess = "AjaxSuccess" })
If you want to access the responseText within your code you do not want to use AJAX(Asynchronous JavaScript And XML), you want to use SJAX (Synchronous JavaScript And XML).
When using AJAX your code will not wait for the responseText it will just continue to execute so if you try referencing it later in your code it may not work as it might not have processed yet.
When using SJAX your code will wait for the responseText before continuing to execute.
I don't use ASP.NET so I can't help with the code.
Here is how it is done in JavaScript: JavaScript - AJAX / SJAX - Submit Form Data to a Script