Doing a function when another one has loaded using JQuery - javascript

I have two functions that I want to load them one by one. They are like this:
<script>
//first function
load_ajax_select(id);
//second fucntion
fadeIn_that_div();
</script>
I want to know how the second function can be done after the first one has loaded.
Thanks.

Let's assume that load_ajax_select looks something like this:
function load_ajax_select() {
$.get("/some/url", function(stuff) {
$("some selector").html(stuff);
});
}
or
function load_ajax_select() {
$("some selector").load("/some/url");
}
or similar, probably with some other logic. In order for it to make it possible for other things to get notification when it's done, the most flexible thing it can do is return a promise. Depending on what it does, it may be simplest to return the promise it already has from the $.get:
function load_ajax_select() {
return $.get("/some/url", function(stuff) {
$("some selector").html(stuff);
});
}
...or sometimes it's useful to create your own:
function load_ajax_select() {
var d = $.Deferred();
$("some selector").load("/some/url", function() {
d.resolve();
});
return d.promise();
}
...although normally if you have one already, creating your own is an anti-pattern.
Code that doesn't care about knowing when the result occurs can just ignore the return value. But your code that needs to know can use it:
load_ajax_select().then(fadeIn_that_div);
or sometimes you may need
load_ajax_select().then(function() { fadeIn_that_div(); });
...if for some reason you can't call fadeIn_that_div directly via then.

Related

Knockout.js "visible" calling async function - not working

I've been trying to understand async, promises, etc. and I think I have a basic understanding of it, but I'm not getting the results I expect.
I have a HTML table, with the following:
<table data-bind="visible: viewPrincipal()">
viewPrincipal() is a function that should return true or false. This does work at the most basic level if viewPrincipal() just consists of return false or return true. But what I'm trying to do is call an async function to get the true or false value from there.
function viewPrincipal() {
console.log("Seeing if person is in principal group");
return IsCurrentUserMemberOfGroup("Principal Members", function (isCurrentUserInGroup) {
console.log(isCurrentUserInGroup);
return isCurrentUserInGroup;
});
}
The console.log works, and returns a true or false as I'd expect it to. But I want the parent viewPrincipal() function to return that true or false value, and all I get is "undefined".
I understand why this is happening - the IsCurrentUserMemberOfGroup() function is taking a bit of time to complete - but I don't know how to fix it. I know how to chain functions together, but when I'm trying to use something like knockout.js to determine if a table should be visible or not, I don't know how to chain.
Can anyone help?
The best way is to use an observable bool, and let your a-sync function change it's value. Let the magic of two-way-bindings do the rest.
Example:JSFIDDLE
function vm() {
this.viewPrincipal = ko.observable(false);
};
var vm = new vm();
ko.applyBindings(vm);
function fakeAsync() {
setTimeout(() => {
vm.viewPrincipal(true);
}, 1500);
}
fakeAsync();
I am a bit lost with your approach, but I'll try to help.
First, please double-think whether you really want to implement access control on the client side. Simply hiding an element if the user does not have sufficient rights is pretty dangerous, since the (possibly) sensitive content is still there in the DOM, it is still downloaded, all you do like this is not displaying it. Even a newbie hacker would find a way to display it though - if nothing else he can simply view it using the F12 tools.
Second, is that triple embedding of functions really necessary? You have an outermost function, that calls a function, which, in turn, calls the provided callback. You could clear this up by using computed observables:
function viewModel() {
var self = this;
var serverData = ko.observable(null);
this.viewPrincipal = ko.computed(function() {
var srvDataUnwrapped = serverData(); // access the inner value
if (!srvDataUnwrapped) {
return false;
}
// Do your decision logic here...
// return false by default
return false;
});
// Load the permission details from the server, this will set
// a variable that the viewPrincipal depends on, this will allow
// Knockout to use its dependency tracking magic and listen for changes.
(function() {
$.ajax(url, {
// other config
success: function (data) {
serverData(data);
}
);
})();
};
var vm = new viewModel();
and then in your view:
<table data-bind="visible: viewPrincipal">
note the lack if ()'s here, it is an observable, so Knockout will know how to use it.
If this seems overly complicated to add to your already existing code, then you could simply define an observable instead, and set the value of that inside your callback:
function viewModel() {
// other stuff ...
this.viewPrincipal = ko.observable(false);
// Call this wherever it fits your requirements, perhaps in an init function.
function checkPrincipal() {
IsCurrentUserMemberOfGroup("Principal Members", function (isCurrentUserInGroup) {
viewPrincipal(isCurrentUserInGroup);
});
};
};
With this approach, the markup would be the same as in the previous one, that is, without the parentheses:
<table data-bind="visible: viewPrincipal">
Doing it this way will simply set the inner value of an observable inside the callback you pass to IsCurrentUserMemberOfGroup, and because Knockout is able to track changes of observables, the value change will be reflected in the UI.
Hope that helps.

Anonymous function on page load

I'm trying to get better with JavaScript and learn how to utilize my code in functions and keep everything clean. I'm trying to run a function on page-load...
var setColors = function(){
this.init = function(){
$.getJSON('js/colors.json', function(colors) {
$.each(colors, function(i, colors) {
$('<li>', {
text: colors['color'],
'name' : colors['color'],
'data-hex' : colors['hex'],
'data-var' : colors['var']
}).appendTo('#picker');
})
});
}
}
(This is not a color-picker, just a list of colors)
I want setColors() to be executed as soon as the page starts. I read that an anonymous function runs automatically, but this one isn't, I also tried...
$(function(){
setColors();
});
Below the setColors() function and that isn't working ether (The page is just blank). What am I doing wrong and how do I get my function to run on page load? I'm trying to learn so an explanation would be great.
Anonymous functions are not run immediately, you're thinking of Immediately Invoked Function Expressions which happen to often use an anonymous function.
To fix your code:
a) get rid of the this.init function wrapper within the "object" - you're not using it and this.foo only makes sense if you're using new to instantiate an object:
function setColors() {
return $.getJSON(...);
}
Note that returning the $.getJSON() result allows you to register additional deferred object handlers, register error handlers, etc.
b) call the above function in a document.ready handler (which you must do, since the AJAX callback modifies the DOM).
$(setColors);
NB: the latter is a legal way of calling this handler - jQuery will automatically register any function that you pass this way as a document.ready handler. It's similar to writing:
$(function() { setColors() })
but without the extra (useless) function wrapper.
To have that run once the DOM is initialized, you can put it in a ready listener (jQuery):
$(document).on('ready', function() {
setColors();
});
If you want the function to run automatically as soon as it is encountered in the js, after the } that ends the function, add ();
Something like:
function setColors() {
// Code
}();
setColors doesn't return the next function, or call it at the end. YOu could change it to look like:
var setColors = function(){
this.init = function(){
$.getJSON('js/colors.json', function(colors) {
$.each(colors, function(i, colors) {
$('<li>', {
text: colors['color'],
'name' : colors['color'],
'data-hex' : colors['hex'],
'data-var' : colors['var']
}).appendTo('#picker');
})
});
}
init(); // <--- change
}
Which would do the trick for you. You don't even need to "return it" either since the init function itself doesn't return anything, so you could just call it.

What's a simple way to define multiple jQuery.Callbacks() prerequisites?

What's the simplest way to define multiple jQuery.Callbacks() prerequisites?
// simple pubsub example
var pubsub=(function() {
var callbacksObj={};
return function(id){
if(!id) throw 'callbacks requires an id';
return (callbacksObj[id] = callbacksObj[id] || $.Callbacks('unique memory'));
};
})();
function fn1(){
console.log('fn1');
};
function fn2(){
console.log('fn2');
};
function fn3(){
console.log('fn3');
};
// subscribing
pubsub('foo').add(fn1);
pubsub('bar').add(fn2);
pubsub('foo','bar').add(fn3); // adding a function with multiple dependencies
// publishing
pubsub('foo').fire() // should only log 'fn1';
pubsub('bar').fire() // should log both 'fn2' AND 'fn3' since both have fired
I can see wrapping each added function in another function that checks each id's fired() state, though this seems like a common enough scenario that perhaps there's a simpler way I'm missing.
I think deferred is what you're looking for:
http://api.jquery.com/category/deferred-object/
it looks like this:
$.when(some_promise).then(some_callback)
And you can have:
$.when(some_promise, another_promise).then(some_callback)
In this case some_callback will only be called if some_promise and another_promise have been resolved.
deferred basically just adds a level of abstraction to your asynchronous functions, making it easier to express the dependencies. I suppose your example would look like:
// simple pubsub example
var pubsub=(function() {
var callbacksObj={};
return function(id){
if(!id) throw 'callbacks requires an id';
return some_assynchrnous_function(id); // like $.ajax
};
})();
function fn1(){
console.log('fn1');
};
function fn2(){
console.log('fn2');
};
function fn3(){
console.log('fn3');
};
// subscribing
var foo = pubusb('foo'); // should return a deferred/promise
var bar = pubsub('bar');
$.when(foo).then(fn1);
$.when(bar).then(fn2);
$.when(foo, bar).then(fn3);
I'm not entirely sure if this is correct for jQuery, but you get the idea. I didn't find the jQuery API to make very much sense to me so I wrote my own :3
I find it useful to be able to make 'empty' deferred objects, then attaching a done handler to it, then passing the deferred object along to something that will eventually end up resolving it. I'm not sure if jQuery can do this.
It may seem a little daunting at first, but if you can wrap your head around it you can get so much awesomeness from this. Dependencies is a big one but scoping is also great, you can add multiple done handlers on multiple levels, one handler may handle the actual data, one handler may just be interested in when the handler finishes so you can show a loading bar etc.

How to redefine JS function keeping previous in chain

This is common task coming from object oriented programming, I would like to change behavior of JavaScript program by overriding existing function with possible calling it as well. I remember Windows introduced that as writing hooks and chaining them. So what I want, I have a web page which calls some onload hook which finally calls function initFields. I want to redefine this function however keep previous implementation. If I simply define my JS function as
function initFields() {
// do some stuff ...
// I do not know how to call super.initFields() here
}
I read something like you can write
initFields.prototype = function() {
// do some stuff ...
// but still have no idea how to call the original one
};
Can somebody help?
One option is
var initFieldsInitial = initFields;
function initFields() {
// your stuff
initFieldsInitial.apply(this, arguments);
}
You could try the wrap() function from the underscore.js library.
http://documentcloud.github.com/underscore/#wrap
var initFields = function() {
// do something
console.log('initFields');
}
initFields = _.wrap(initFields, function(initial) {
// do some stuff
console.log('wrapper');
initial();
});
$(document).ready(function() {
initFields();
});

How do I update the JavaScript this-pointer inside an object to point to another object?

I'm having some trouble with JavaScript and the passing of a function as parameter of another function.
let's say we are inside a class and do something like that:
this.get('target').update(this.onSuccess, this.onFail);
'target' is a JavaScript-object that has a method called update()
I'm calling this method and pass tow methods of the caller-class along as parameters
inside that update-method some stuff happens and when it's done that method should either call the onSuccess-method or the onFail-method. this looks something like:
update: function(onSuccess, onFail) {
if(true) {
onSuccess();
} else {
onFail();
}
}
until now, everything works pretty fine! but inside those success/fail-methods, that are defined in the caller-class (the one that calls above update-method), I'm using a this-pointer:
onFail: function() {
alert('Error: ' + this.get('target').error);
}
that this-pointer causes some issues. it doesn't point to the class where the method initially was defined but to the 'target'-object.
what I need to do now is to update the this-pointer right before the onSuccess / onFail calls inside the 'target'-class to make the methods work again. but this doesn't work due to a 'invalid assignment left-hand side'-error.
what is the best practice for a scenario like that? any ideas? thx in advance!!!
cheers
You have two options when calling update():
javascript function call()
javascript function apply()
the main difference being how you pass parameters to it. But they both allow scope/context injection.
Your code should look something like this:
this.get('target').update.call(this, this.onSuccess, this.onFail);
You can create a function that "binds" a function to a certain object (using a closure) and than pass these bound functions to the handler:
function bind(obj, fun) {
return function() {
return fun.apply(obj, arguments);
};
};
update(bind(this, this.onSuccess), bind(this, this.onFail));
To redirect this, you need a bind() (or similar) method in the Function class, as found in almost all JavaScript libraries:
if(!Function.prototype.bind){
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
}
}
}
Now do something like this:
update: function(onSuccess, onFail) {
if(true) {
onSuccess.bind(this)();
} else {
onFail.bind(this)();
}
}
The mechanism is explained here: Binding Scope in JavaScript

Categories

Resources