How to unsubscribe from amplify within subscribe function? - javascript

amplify.subscribe("WorkTypesReceived", function () {
var workTypesList = amplify.store("ExpenseWorkTypesFor" + JobNo_);
amplify.unsubscribe("WorkTypesReceived");
});
getDropdownExpenseWorkTypes(JobNo_);
My getDropdownExpenseWorkTypes calls a function that publishes "WorkTypesReceived" when it is complete. But since I call this entire function more than once on a single page, it exponentially explodes (multiple subscriptions to the same topic). I'd like to remove the subscription once it's been published once (and so goes into the subscribe function once).
The line amplify.unsubscribe("WorkTypesReceived") doesn't seem to work, and the documentation says I need a second parameter being the callback function. But I'm inside the callback function so unsure how to proceed.

If you add a name to your callback you can use that to unsubscribe from it...
amplify.subscribe( "WorkTypesReceived", function storeWork() {
var workTypesList = amplify.store( "ExpenseWorkTypesFor" + JobNo_ );
amplify.unsubscribe( "WorkTypesReceived", storeWork );
});

Related

How to add action function to Disposable returned from subscribe on an Observable?

You have an Observable, then you subscribe to it. The return value is a Disposable. How do you add a function to be invoked when that Disposable instance is disposed?
clickStream.subscribe(....).dispose();
When dispose() is invoked I want to call a debug function, for example, console.log('Disposing ....'). In a real app, I would want to do some non-rxjs clean-up and UI notification actions. Probably simple thing, but I don't see it in the API. Thx.
I wonder if finally would work for your use case (documentation). According to the documentation, Invokes a specified action after the source observable sequence terminates gracefully or exceptionally. Note that this is not exactly the same as a callback being called when dispose is called but I thought that might be enough for your needs, and you can use it for clean-up actions.
UPDATE
Also close to what you want, but not quite so, you could use the using operator (documentation). It allows to create an object with a dispose method which would be called when the subscription to the associated observable is disposed of.
UPDATE 2
Looking at the source code, finally actually executes the action when the subscription to its observable is disposed. This includes termination or manually calling dispose() on the subscription. That seems very close to what you want to achieve.
Best is to test. Please keep us updated of the results.
Disposables are tied to event sources. The principle is that an event source is interacting with the non-Rx world, and might need to do some clean-up when no one is subscribed any more.
If you could put a hook into the Disposable that is returned from a call to subscribe then it wouldn't be of much use: you know when you called dispose() so you could just handle the clean-up logic there, and if some other code called dispose() it might be on a Disposable further down the chain, which may not affect your subscription.
It sounds like you are trying to make use of side-effects, which isn't necessarily in the spirit of the RxJS API. If you need to close down some network connection or something like that, then maybe you should be using a custom Observable, which creates a Disposable to clean itself up.
A simple example of this (simplified implementation of Observable.fromEvent) might look like this:
function fromEvent(obj, evt){
var subject = new Rx.Subject();
function listener(e){
subject.onNext( e );
}
return Rx.Observable.create( function( observer ){
var disp = subject.subscribe( observer );
obj.addEventListener( evt, listener );
return Rx.Disposable.create(function(){
// All the clean-up code goes here
obj.removeEventListener( evt, listener );
disp.dispose();
})
});
}
var events$ = fromEvent( button, 'click');
var count = 0;
var unsub = events$.subscribe( function(){
console.log('click');
count++;
if( count > 5){
unsub.dispose();
}
})

How to call another javascript function within a javascript function after previous codes have been executed?

I got this seemingly simple problem, yet I cannot find the correct way of execution.
I have 2 select tags, the first one is COLOR and the second one is SIZE. The second one is dependent on the first one.
To retrieve the price of the products (which is from the database), I intend to call a function within another function. The code stated below.
function checksizes(id)
{
var color=document.getElementById('colors').value;
$("#sizediv").show();
$("#sizediv").load('sizes.php?id='+id+'&color='+color);
var size = document.getElementById('size2').value;
alert(id+size+color);
confirmprice2(id,size,color);
}
function confirmprice2(id,size)
{
$("#price").show();
$("#price").load('price.php?id='+id+'&size='+size);
}
The alert is to check whether the invoked values to be passed on the next function are correct.
Code is working, but returning different results. It seemed that the function checksizes() passes values which are from the previous select (from the size). It calls the second function even before it finishes executing this: $("#sizediv").load('sizes.php?id='+id+'&color='+color);
Help is much appreciated. Thank you!
That's because .load() is asynchronous. It basically forks off another thread to continue its work while the calling code continues what it was doing. If you have code which needs to happen in response to .load() then it needs to be placed in a callback function, not after the function. Something like this:
function checksizes(id) {
var color=document.getElementById('colors').value;
$("#sizediv").show();
$("#sizediv").load('sizes.php?id='+id+'&color='+color, function () {
var size = document.getElementById('size2').value;
alert(id+size+color);
confirmprice2(id,size,color);
});
}
Passing this function as a parameter to .load() will invoke this function after .load() completes.
The load function is an asynchronous function. When the function is "finneshed" does not mean that the result is loaded.
You need the completed Callback for that. See http://api.jquery.com/load/
function checksizes(id)
{
var color=document.getElementById('colors').value;
$("#sizediv").show();
$("#sizediv").load('sizes.php?id='+id+'&color='+color, function(){
var size = document.getElementById('size2').value;
alert(id+size+color);
confirmprice2(id,size,color);
});
}
function confirmprice2(id,size)
{
$("#price").show();
$("#price").load('price.php?id='+id+'&size='+size, function(){
alert('price is loaded');
});
}
As from the jQuery documentation, $.load does indeed not finish before it returns. You should use the callback function:
$( "#result" ).load( "ajax/test.html", function() {
alert( "Load was performed." );
});
http://api.jquery.com/load/
In your case, everything in the checksizes function under the load function call should be placed in the callback.

jquery - how to continue the execution of one function once another function has returned a value

I currently have a function called showAuthorInfo which performs an animation, and then executes some other code logic once the animation is finished:
self.showAuthorInfo = function(){
var authorID = $authorLink.attr('data-author-id'); //PL-INT - determine what info needs be captured here
var isActive = $modalInfoWindow.hasClass('active');
self.$modalInfoWindow.animate({ 'bottom': '0px' },200,function(){
self.$modalInfoWindow.addClass('active');
self.loadAuthorInfo(authorID);
})
}
however, because I will want to show and hide this modal window via various function calls, executing different callbacks each time the animation is completed, I'd like to wrap the animation into a function. The question is, can I use the above function to call a custom function where the animation happens, and have that animation function return a value to this function, whereon it can then proceed?
I would break the function up into multiple functions, but I feel like that could get complicated, especially because I would have to pass on certain function-specific parameters that wouldn't apply to all cases (for example, in the code above, if I were going to call an animation function, and then a loadAuthorInfo function, the animation function would have to accept authorID so it could pass it on to loadAuthorInfo, even though the animation function only needs authorID if it is called by showAuthorInfo).
Any recommendations here?
Example of what I'd rather NOT do:
self.showAuthorInfo = function(){
var authorID = $authorLink.attr('data-author-id'); //PL-INT - determine what info needs be captured here
var callback = self.displayAuthorContent();
self.animateInfoWindow(authorID,callback);
}
self.animateInfoWindow = function(authorID,callback){
self.$modalInfoWindow.animate({ 'bottom': '0px' },200,function(){
//create conditional where if there's an authorID, pass it to the callback function, otherwise just call the callback function without parameters
})
}
Mheavers, you've tagged your question with promise, which means you are thinking along the right lines.
It's maybe little appreciated that jQuery allows ad hoc promises to be formed from jQuery collections, with $(selector).promise(type, target), typically at the end of a longer method chain. type defaults to "fx" (the standard animation queue), and target is optional (and not relevant here).
Thus, self.animateInfoWindow can be blissfully unaware of anything that will happen after the animation it kicks off has completed. All it needs to do is return a promise of the type described above, thus allowing chaining where self.animateInfoWindow is called.
self.animateInfoWindow = function() {
return self.$modalInfoWindow.animate({'bottom':'0px'}, 200).promise();
};
And self.showAuthorInfo can perform the post-animation action without passing any params to self.animateInfoWindow.
self.showAuthorInfo = function() {
var authorID = $authorLink.data('authorId') || null; //PL-INT - determine what info needs be captured here
self.animateInfoWindow().done(function() {
self.$modalInfoWindow.addClass('active');
self.loadAuthorInfo(authorID);
});
};
Note, || null in the first line to ensure that authorID is not undefined. (Slightly more complicated if an authorId of 0 (zero) is valid).
The only other thing is to ensure that self.loadAuthorInfo is tollerant of being passed null.
You can just pass the callback to animate and avoid unnecessary function wrapping:
self.showAuthorInfo = function(){
var authorID = $authorLink.attr('data-author-id'); //PL-INT - determine what info needs be captured here
var callback = self.displayAuthorContent();
self.animateInfoWindow(authorID,function(){
//do something here
});
}
self.someOtherFunction = function(){
var authorID2 = $authorLink2.attr('data-author-id2'); //PL-INT - determine what info needs be captured here
var callback2 = self.displayAuthorContent2();
self.animateInfoWindow(authorID2,function(){
//do something different
});
}
self.animateInfoWindow = function(authorID,callback){
self.$modalInfoWindow.animate({ 'bottom': '0px' },200,callback)
}
Here's a fiddle: http://jsfiddle.net/95kwD/
I don't really know what you want to accomplish with:
var callback = self.displayAuthorContent();
You are calling the callback before calling the function which is the whole purpose of a callback function. Maybe it's just the name of the function variable
If you want to keep animateWindow as generic as possible, then just have a callback and no params. The callback can be more context-aware to allow flexibility.
self.showAuthorInfo = function(){
var authorID = $authorLink.attr('data-author-id');
var customCallback = function(){
self.loadAuthorInfo(authorID);
};
self.animateInfoWindow(customCallback);
}
self.animateInfoWindow = function(callback){
self.$modalInfoWindow.animate({ 'bottom': '0px' },200,callback);
}

Java script function to hold until save evenet execution is completed

I have a javascript function. In thi function i am calling a button event like below.
$("#btnSave").trigger("click");
My query is , Is there any way to keep the control here on this line until the saving is done?
I have some code written underneath this line and it is being overridden.
Any suggestions?
It would have helped if you've posted some code.
You can do it in 2 ways:
1.) Use polling. After the trigger call use a loop to check for a flag that you must set when the save is complete. A timeout is needed for saving CPU from intensive js processing.
2.) Put the code to be executed after the trigger call inside a function. Pass this function as a callback to the onClick function.
function onSaveClick(e) {
//do my save stuff
e.data.callback();
}
No. 2 is recommended.
//attach onclick event
$("#btnSave").click(onSaveClick);
//you onclick function
function onSaveClick(event, callback) {
//save data
callback();
}
//trigger
$("#btnSave").trigger("click", afterSave);
//after save stuff
function afterSave(){
//do more stuff
}
Use a callback.
Get the lines under the trigger line and pass to your save function as callback when the event has success.

Hook into the end of an asynchronous javascript call

I'm calling a javascript function provided by a third-party. This function fires off a few ajax/asynchronous requests before returning, and (impolitely) neither allows me to pass a callback, nor returns any references to the asynchronous calls it is making.
Is there any way I can trigger something when all of the calls it's making complete?
Is there a way I can track 'calls' launched from a javascript function? Forgive my terminology; I'm a javascript beginner.
Is this a library that's loaded from an external source, or do you have your own local copy? In the latter case, you could patch the code to do what you want. Otherwise, I don't really see a way to directly intercept the calls.
If you know exactly what state changes occur for each completed async call, you could set a function to execute on an interval (setInterval(fn, millis)) and check whether all those states have been met. Then, you could fire off some sort of final function to indicate completion.
ie:
var completionHandler = function() { /* do something awesome */ }
var checkCompletion = function() {
if (state1 && state2 && state3) {
clearInterval(interval); // make sure you clear the interval.
completionHandler();
}
}
var interval = setInterval(checkCompletion, 200);
If your third party script is based on jQuery you could try to modify the ajax behaviour with $.ajaxSetup(), set a context object and bind a ajaxComplete handler to this object. But that might mess up the third party library.

Categories

Resources