I stated to work with vue.js recently and I don't understand why this behavior happens, using the setTimeout(). With the following code, the function defined in setInterval(function(), time) is launched immediately no matter the value of 'time':
timerOn(){
...
this.avatar.timer.data = setTimeout( this.timerFunction(), 10000);
},
timerFunction(){
...
console.log('Hello!!');
clearTimeout(this.avatar.timer.data);
this.timerOn();
},
But if I use the following code all works fine and the function inside setInterval occurs after the 'time' defined:
timerOn(){
...
var This = this;
this.avatar.timer.data = setTimeout(function() { This.timerFunction()}, 10000);
},
timerFunction(){
...
console.log('Hello!!');
clearTimeout(this.avatar.timer.data);
this.timerOn();
},
Someone can guide me and say why the first method fails?
Thank you.
This executes timerFunction immediately and passes the result as the callback to setTimeout.
setTimeout( this.timerFunction(), 10000)
But, you want to pass a callback to setTimeout and timerFunction does not return a function. I expect what you wanted was
setTimeout( this.timerFunction, 10000)
This passes a reference to the function, timerFunction to setTimeout. The first example, passes the result of timerFunction() to setTimeout.
Related
Using the example from phantomjs works like a charm
https://github.com/ariya/phantomjs/blob/master/examples/rasterize.js?utm_content=bufferda3e0&utm_source=buffer&utm_medium=twitter&utm_campaign=Buffer
However what happens if the url needs to make an Ajax request in order to load it's data? Can I fire a custom event so the pdf is only generated then ?
(I don't want to guess how much time the request will take and set a timeout)
The common solution to this problem is to wait for an element that will appear on the page after AJAX request has finished.
Include the waitFor function from this example and wait for the first function passed as argument to waitFor to return true, then it will run the function passed as the second argument.
page.open("https://example.com/ajaxified/", function (status) {
waitFor(function() {
return page.evaluate(function() {
return document.querySelectorAll(".report").length > 0;
});
}, function() {
page.render("report.pdf");
phantom.exit();
});
});
I have read that nextTick allows codes to be executed at the next action. But this does not work in my code, can someone helps me on this? Please correct me. Thanks.
.vue
.....
methods:{
getUserInfo(){
var vm = this
vm.$http.get('/getAuthUser').then((response)=>{
vm.user = response.data
})
Vue.nextTick(()=>{
vm.$http.get('/getShop/'+vm.user.id).then((response)=>{
vm.shop = response.data.data.shop
})
})
},
}
.....
{{user.id}} does work. where this gives me the following error:
GET http://localhost:8000/getShop/undefined 404 (Not Found)
EDIT#1
if i do something like this it works but this should not be the right way to do in my opinion.
.....
methods:{
getUserInfo(){
var vm = this
vm.$http.get('/getAuthUser').then((response)=>{
vm.user = response.data
vm.$http.get('/getShop/'+vm.user.id).then((response)=>{
vm.shop = response.data.data.shop
})
})
},
}
.....
EDIT#2
If I do something like this it wont work coz vm.user.id is not set.
.....
methods:{
getUserInfo(){
var vm = this
vm.$http.get('/getAuthUser').then((response)=>{
vm.user = response.data
})
vm.$http.get('/getShop/'+vm.user.id).then((response)=>{
vm.shop = response.data.data.shop
})
},
}
.....
I think your understanding of what nextTick does is incorrect. If you read the documentation, it says that the callback you pass to the nextTick function will be executed after the next DOM update.
Let's say you have a property that determines whether an element exists or not in the DOM with a v-if directive. If you change the value of the property so that the element exists in the DOM, you might have to wait for Vue to process the change and update the DOM before you can grab a reference of that element, for example. In that case, you should use Vue.nextTick to make sure by the time you want to query the DOM to get that element, it actually exists.
Your scenario doesn't have anything to do with the DOM.
You have 2 asynchronous HTTP calls that you want to execute one after another, because the second relies on the result of the first. Your original implementation and third one (EDIT#2) are flaky because you don't make sure the first HTTP request is complete before firing the second one, which explains why you get errors about vm.user.id not being set.
Your second implementation (EDIT#1) is more correct because the second HTTP request is fired after the first one completes. Still, I'd suggest a minor modification:
getUserInfo() {
vm.$http.get('/getAuthUser')
.then(response => {
vm.user = response.data;
return vm.$http.get('/getShop/' + vm.user.id);
}).then(response => {
vm.shop = response.data.data.shop;
});
}
The first callback returns a Promise which result is fed into the second then call. I like this approach because it avois having nested thens. I would also suggest you to read the MDN docs on Promises.
I'm in a bit of a pickle with this one. I'm using jQuery DataTables 1.10.6, and I want to make it so that when the user stops typing (like maybe after 950 ms?), the search is performed. I kind of have it working, but since I'm using server-side processing, sSearch (the search parameter) returns null.
I'm guessing it has to do with the unbinding and re-binding, but I don't know how to make it so that sSearch is sent properly.
var delay = function () {
var timer = 0;
return function (callback, ms) {
clearTimeout(timer);
timer = setTimeout(callback, ms);
}
})();
$("div.dataTables_filter input").unbind();
$("div.dataTables_filter input").bind("keyup", function () {
alert(this.value);
delay(function () {
$("#MyTable").dataTable().fnFilter(this.value);}, 1000);
}
DataTables has an option to se delay, you can check it here
I found a deprecated plugin which is a key debounce delay: https://www.datatables.net/plug-ins/api/fnSetFilteringDelay
Even though it's stated that this won't work with 1.10+, there's a comment stating that a line change would allow it to work in 1.10+. So the following line:
anControl.unbind('keyup search input').bind('keyup search input', function() {
...would be replaced with:
anControl.off('keyup search input').on('keyup search input', function() {
I was also able to set the filtering delay timer in the calling argument. Works like a charm.
I have a view that contains a model. The view listens for an event from the model and will perform an action once the event is triggered. Below is my code
window.Category = Backbone.Model.extend({})
window.notesDialog = Backbone.View.extend({
initialize: function() {
this.model.bind("notesFetched", this.showNotes, this);
},
showNotes: function(notes) {
//do stuffs here
}
})
I want to test this using Jasmine and below is my test (which doesn't work)
it("should show notes", function() {
var category = new Category;
var notes_dialog = new NotesDialog({model: category})
spyOn(notes_dialog, "showNotes");
category.trigger("notesFetched", "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})
Does anyone know why the above test doesn't work? The error I get is "Expected spy showNotes to have been called with [ '[]' ] but it was never called."
I was doing something similar where I had a view, but I couldn't get the spy to work properly unless I added it to the prototype, and before I created the instance of the view.
Here's what eventually worked for me:
view.js
view = Backbone.View.extend({
initialize: function(){
this.collection.bind("change", this.onChange, this);
},
...
onChange: function(){
console.log("Called...");
}
});
jasmine_spec.js
describe("Test Event", function(){
it("Should spy on change event", function(){
var spy = spyOn(view.prototype, 'onChange').andCallThrough()
var v = new view( {collection: some_collection });
// Trigger the change event
some_collection.set();
expect(spy).toHaveBeenCalled()
});
});
I would test initially with the toHaveBeenCalled() expectation and change to the toHaveBeenCalledWith() after you get that working...
Update 5/6/2013: Changed update() to set()
Try to amend your existing test code as follows:
it("should show notes", function() {
var category = new Category;
spyOn(NotesDialog.prototype, "showNotes");
var notes_dialog = new NotesDialog({model: category})
category.trigger("notesFetched", "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})
In your original code, the instance of the method you are calling is one defined in the bind closure, whereas the one you are spying on is in the notes_dialog instance. By moving the spy to the prototype, you are replacing it before the bind takes place, and therefore the bind closure encapsulates the spy, not the original method.
Using a spy means to replace the function you spying on. So in your case you replace the bind function with the spy, so the internal logic of the original spy will not call anymore. And thats the right way to go cause you dont wanna test that Backbones bind is work but that you have called bind with the specific paramaters "notesFetched", this.showNotes, this.
So how to test this. As you know every spy has the toHaveBeenCalledWith(arguments) method. In your case it should looks like this:
expect(category.bind).toHaveBeenCalledWith("notesFetched", category. showNotes, showNotes)
So how to test that trigger the "notesFetched" on the model will call your showNotes function.
Every spy saves the all parameters he was called with. You can access the last one with mostRecentCall.args.
category.bind.mostRecentCall.args[1].call(category.bind.mostRecentCall.args[2], "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
mostRecentCall.args[1] is the the second argument in your bind call (this.showNotes). mostRecentCall.args[2] is the the third argument in your bind call (this).
As we have test that bind was called with your public method showNotes, you can also call the your public method showNotes directly, but sometimes the passed arguments can access from outside so you will use the shown way.
Your code looks fine, except do you have the test wrapped in a describe function, as well as an it function?
describe("show notes", function(){
it("should show notes", function(){
// ... everything you already have here
});
});
Total guess at this point, but since you're not showing the describe function that's all I can think it would be. You must have a describe block for the tests to work, if you don't have one.
You are pretty close ;)
spyOn replaces the function with your spy and returns you the spy.
So if you do:
var dialog_spy = spyOn(notes_dialog, "showNotes");
category.trigger("notesFetched", "[]");
expect(dialog_spy).toHaveBeenCalledWith("[]");
should work just fine!
The setTimeout() function in Sencha Touch does not work. It executes the code immediately as setTimeout is called. Has anybody had experience / has a workaround for this bug?
Why not use Ext.Functions.defer; (Short: Ext.defer)
// this syntax is sometimes useful for deferring execution of an anonymous function:
Ext.defer(function(){}, millisecs, scope);
// defer the answer 100ms with the current scope
Ext.defer(function() {
alert('Anonymous');
}, 100, this);
Defer is the variant of SetTimeout function in Sencha
Ext.Function.defer(function () {
alert('Anonymous');
}, 5000);