ColdFusion.Window.create callbackhandler issue - javascript

I'm trying to use the callbackhandler entry for the configuration parameter for ColdFusion.Window.create(). I have the following js functions below. Within populateWindow2() I have calls to other functions that I intend to only run after the window is rendered as these functions need to make references to elements within the created window.
Triggering populateCFwindow with:
<input id="selectProcessorButton" onclick="javascript:populateCFwindow();">
populateCFwindow = function(){
ColdFusion.Window.create(...{callbackhandler:populateWindow2()}).
}
populateWindow2 = function(){
initSearchgetProcessorList();
initTable_selectProcessor();
}
The issue I am having is that the init functions above still fire before the window is completely rendered.
I appreciate any feedback. Thank you.

You need to remove the parentheses which are invoking the function and passing it's result to callbackHandler (undefined) instead of passing a reference to the populateWindow2 function .
<input id="selectProcessorButton" onclick="javascript:populateCFwindow();">
populateCFwindow = function(){
ColdFusion.Window.create(...{callbackhandler:populateWindow2}).
}
populateWindow2 = function(){
initSearchgetProcessorList();
initTable_selectProcessor();
}

I had the same problem and checked their JavaScript code. The configuration property name is callbackHandler, not callbackhandler. Adobe needs to update their docs, this problem drove me nuts!!!

Related

In this context, what exactly does $('id').on('click', this.method.bind(this)) do?

Here is the app I'm referring to:
I am trying to fundamentally understand the bind method in Javascript.
My understanding when I play around with it in the console is that bind returns a copy of the function, with "this" bound to whatever you pass into bind.
function logThis(){
console.log(this)
}
logThis.bind({today: 'Tuesday'})
//Will return a copy of the logThis function, with 'this' set to the
{today:'Tuesday'} object. The code does not run right away though.
var explicitlyLogThis = logThis.bind({today: 'Tuesday'});
explicitlyLogThis(); //This will run the code and display the {today: 'Tuesday'} object to the console.
This is my understanding so far. I understand that to actually run this new function that has 'this' explicitly bound using the bind method, you need to set it to a variable and then run it.
I see a contradiction when I look at the app in the above link. If you look at the bindEvents method on line 56, we have .on('keyup', this.create.bind(this)). I understand that we have to set 'this' to App when we run the create method because jQuery defaults to setting 'this' to the jQuery object itself. So this line is actually the same as: $('#new-todo').on('keyup', App.create.bind(App)).
That isn't where my confusion is. My question is:
How exactly are these copies of the functions with 'this' set to App actually being called? The app does not set them to a variable and then call that variable the way I had to when I was working in the console.
It just invokes the bound functions directly as soon as an event occurs on one of the jQuery elements. But I thought writing it this way would just return a copy of the function, and not run the function itself, if I am basing my assumptions on what I have figured out in the code I wrote above. I thought in order to invoke the function immediately, you would need to use call or apply.
I also realize that the app runs the bindEvents method when it starts (see line 46). So I understand that when you start the app, copies of the various functions are created with the correct 'this' bound to the functions. But...when/how do they actually get invoked without assigning them to variables? How are these copies accessed?
I think I have a flawed understanding of the bind method, so I would love some help. Thanks!
It sounds like you understand bind well enough. Perhaps there is some confusion with passing anonymous functions. As you know calling bind returns a new function and this can optionally be stored as a variable or passed as a function argument.
In the example below btn1 accepts a bound function as you've seen. This could also be written in a more long hand fashion with btn2. They're identical. btn3 doesn't receive a bound function, when its clicked its context is the button element, this looses all visibility of MagicalApp fucntions.
<button id="example1">button one bound</button>
<button id="example2">button one bound</button>
<button id="example3">button two unbound</button>
<script>
class MagicalApp {
add() {
console.log('this could do addition');
}
}
const app = new MagicalApp();
function contextOfEvent(event) {
console.log('contextSensitive', this.add)
}
const btn1 = document.querySelector("#example1");
btn1.addEventListener('click', contextOfEvent.bind(app));
const btn2 = document.querySelector("#example2");
const btn2ClickHandler = contextOfEvent.bind(app)
btn2.addEventListener('click', btn2ClickHandler);
const btn3 = document.querySelector("#example3");
btn3.addEventListener('click', contextOfEvent);
</script>

How can you pass anonymous functions as parameters to existing functions to use later in javascript?

I am trying to create a basic javascript framework that you can pass different things into, including functions for it to execute later. Right now, I'm in a more simple testing phase, but I can't quite get the function calling to work. A piece of my code is here:
[My JS Fiddle][1]http://jsfiddle.net/mp243wm6/
My code has an object that holds different data, and I want to call the method later, but with data that is available at the time of creation. Here is a code snippet of the function that uses the function that is passed to the object:
clickMe : function() {
this.obj.click(function() {
this.func();
});
}
Any suggestions or things I should read are welcome.
The problem is that there're two different contexts:
clickMe : function() {
// here is one
this.obj.click(function() {
// here is another
this.func();
});
}
You can simple pass the function as parameter, like the following:
clickMe : function() {
this.obj.click($.proxy(this.func, this));
}
http://jsfiddle.net/mp243wm6/2/
The problem:
Considering your code in the JSFiddle, you have:
onClick : function() {
this.obj.click(function() {
this.func();
});
},
As noted, you have different contexts going on here.
Consider the snippet this.obj.click(function() { this.func(); }). The first this here is a reference to the framework.events object. The second this here is a reference to whatever will be this when this function get called. In the case of your JSFiddle, when this.func gets called, this is actually the DOM object that represents the <div id="test">TEST</div> node. Since it doesn't have a func function, calling func() on it causes:
Uncaught TypeError: undefined is not a function
You have to understand the following: you have to pass the correct this in which you want the function func to be called.
The solution:
A couple of ways to make it work as you would like:
1. with bind
this.obj.click(this.func.bind(this));
This way, you are telling: "call my this.func function, but make sure that it will be called using the this that I am passing as a parameter". Vanilla JS, no $.proxy stuff.
JSFiddle
2. with a copy of the reference to the actual function
onClick : function() {
var theFunctionReference = this.func;
this.obj.click(function() {
theFunctionReference();
});
},
This way, you will not rely on the value of this outside of the context of the framework.events object.
JSFiddle
The issue is that this is not bound to the correct object. I would suggest you look into Function.bind() because that creates a function with this pointing to the right thing.

Changing the current closure?

I am trying to get some old code to work properly with minimal modification. The code was written on the assumption that it would run from a particular context. I have the context object.
Original code:
function oldExample(){
console.log(window); //New Error: window is undefined
console.log(gBrowser); //New Error: gBrowser is undefined
}
New, working code:
function fixedExample(){
console.log(this.window);
console.log(this.gBrowser);
}
//Elsewhere
function loadData(context) {
fixedExample.call(context);
}
Notes:
1. loadData and oldExample are defined in separate files.
2. context has other children besides window and gBrowser; This is an example
Is there a way to transition my oldExample code to work properly without needing to stuff this. everywhere? I.e., how can I run oldExample in a different context?
The only way I know how to do this is to define the properties as variables of the current context:
var object = {gBrowser: 'test'};
function oldExample(){
console.log(gBrowser);
}
var gBrowser = object.gBrowser;
oldExample();
This example outputs 'test'
But all this does is move the property access outside of the function definition, doesn't save you anything.
You can use bind method in javascript.
fixedExample.bind (context);
Now you need not use 'this' inside fixedExample and can use window directly.

Creating a JavaScript callback in an iframe

UPDATE: The back-end service was powered by an ASP.Net AJAX Web Service proxy.
1) The main page has two global objects, one for the back end connections (Svc) and another for handling the DOM (Main). It also dynamically loads documents into an iframe.
2) These iframes need to access services provided by Svc, and also supply a callback function.
3) The problem - passing a function created in the iframe to the parent frame, it's treated as an object not a function and cannot be invoked.
Can anyone provide a better solution than what I've got currently in the iframe:
var Main = parent.Main,
Svc = parent.Svc;
Svc.method(data, Main.createCallback(
function(response) {}
));
and in the parent frame:
Main.createCallback = function(func) {
return function() {
func.apply(func, arguments);
}
}
if you override the iFrame's function from the main, the main scope will then be used.
The inverse problem can be seen here, in your case, you just override the frame's function itself i.e:
document.getElementById('yourFrameID').contentWindow.targetFunctionInFrame = targetFunctionInMain;
Bonus: if you can modify the iFrame's code, I would suggest to:
In the frame:
make a placeholder function callbackParent() {}
add a call to this function into your iframe code, so that you just have to override the callbackParent from your main.
In the main:
make the function which should be invoked function doStuff() {}
override the function as described above document.getElementById('yourFrameID').contentWindow.callBackParent = doStuff;
I use iframes to modularize my app too.They are a kind of includes embedding all CSS, HTML and JS for a module.
My first attempts were by returning a function too, but then I found it quite hard for sharing scopes.
Now I make directly a reference to the main parent object in the iframe.
eg:
var Svc = parent.Svc, JSON = parent.JSON, $ = parent.$;
Svc.module1 = {
method1:function(arg){
...
},
...
}
The global var JSON and jQuery references are here to have them available inside the methods.
My guest is that Svc.method is making some checks to see if the callback has some criteria before calling it. This criteria might be that the callback function must created by the same framework (here it's ASP.Net). You have to find what that criteria is. if "Main.createCallback" works, it's because it's meeting that criteria.
Sorry but your all wrong... add this....
const event = new CustomEvent('MSGSent', { detail: "fff variable" });
Call it like this....use a global variable for detail... like an array []
window.dispatchEvent(event);
Now after the iframe loads add this code and you get an Object back in the main page....
iframe.onload = function() {
try {
iframe.contentWindow.addEventListener('MSGSent',function(e){
alert(e.detail);
});
} catch (error) {
}
};
The problem is ASP.Net AJAX Web Service proxies, which don't appear to support calling the web service from an iframe with an inline callback function.

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

Categories

Resources