I've noticed that the call to the createJSAPI method in my plugin is only called after I somehow try to interact with the actual DOM element.
Is there a way to make it happen before any javascript interaction is happening?
In the documentation for getRootJSAPI it states:
It is not recommended to call this from the constructor or before
setHost is called, as many JSAPI objects need the BrowserHost and a
weak_ptr to the Plugin class to function correctly
So when is it appropriate to call this method? in onPluginReady or onWindowAttached?
Thanks.
Edit
This is my createJSAPI code:
FB::JSAPIPtr plugin::createJSAPI()
{
this->jsApi = JSApiPtr(new pluginAPI(FB::ptr_cast<plugin>(shared_from_this()), m_host));
return this->jsApi;
}
And this is the onPluginReady code:
void plugin::onPluginReady()
{
this->getRootJSAPI();
this->jsApi->fireMyEvent(this->myId);
}
and the event isn't fired, though this does:
bool plugin::onMouseDown(FB::MouseDownEvent *evt, FB::PluginWindow *)
{
this->jsApi->fireMyEvent(this->myId);
return false;
}
Why is that?
As for the build in onload mechanism, I need my own, since I need to pass some parameters to that fired event.
Thanks.
You can call this method during or after onPluginReady -- that's one of the main purposes of the function.
EDIT:
To answer your further question, onPluginReady is likely to be called before your onLoad callback from the param tag gets called; that means your event handlers aren't attached yet. That's the reason that FireBreath provides the onload param callback -- it gives you a place to attach event handlers and find out that things are loaded.
Related
Comming from a c# background, I just want to create an event in a certain point of my code, soas to be dispatched elsewere, meaning that if in some part of the code there has been a subscription, this delegate function is called.
So I tried to do:
function myFunction() {
console.log("delegated call achieved!");
}
const myEvent = new Event('onMyConditionIsMet', myFunction, false);
//at this point the program the subscription takes place
function whatever1() {
//...not meaningfull code
myEvent.addEventListener('onMyConditionIsMet');
//myEvent += myFunction; c# way subscription in case it makes sense
}
//at this point in the program, event subscription is checked and
//delegate func run in case there has been a subscription
function whatever2() {
//...not meaningfull code
myEvent?.invoke(); // ?.invoke(); would be the c# way to do it.
}
All the examples I found are related to DOM events, but my case would be for events I create myself, think these are called synthetic events.
Another assumption I make in this question is that there would be no arguments in the delegate call function, so, just to be clear with the naming, it would be a delegate with no arguments. Just pointing this because in c# events are just delegate funcs with no arguments, so a specific type of delegate. Not sure if this works the same way in Javscript.
What would be the approach to do this? (Meaning creating a simple event instance, subscribing, and executing the delegated code if there is any subscription)?
I think the functionality you are looking for can be best obtained by using OOP/Classes.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#prototype_methods
Edit: see this also - "event" is deprecated, what should be used instead?
What does the jQuery method $.on return?
Example:
$(document).on("CustomEvent", CustomFunction);
What does the jQuery method $.on return?
$(document).on(...) returns the jQuery object created by $(document). This makes it chainable as in:
$(document).on("click", clickHandler).on("hover", hoverHandler);
In fact all jQuery methods that don't have a specific value to return will return the jQuery object so they can be chainable in this fashion.
Another commonly used example:
$("#target").fadeIn(2000).delay(5000).fadeOut(2000);
But, a method that has a specific value to return such as .prop() or .attr() will return that specific value:
var isChecked = $("#myCheckbox").prop("checked");
var imgSrc = $("#myImg").attr("src");
The return value for any jQuery API is listed in the documentation (here's a screen shot from the doc page for .on():
If you want to prevent an event handler from getting called again, you can either use .one() which will only trigger the event once or you can use .off(...) to remove the event handler as desired or you can use some sort of flag in your own code to tell the event handler whether it should do its work or not.
The cleanest architectural solution to preventing repeat calls to something triggered by .load() is to move the event handler setup code to a different area of your Javascript so it is not loaded again by .load() and is only loaded once by the parent page. That way it only gets called once. Exactly how to do that depends upon the specific circumstances of your design which you have not disclosed so we can't advise more specifically than that.
using jquery .load causing some repeating actions in page. if i am not wrong, you have to call your callback function inside "promise"
example
$(document).on("click", ".someClass", function () {
//do something
}).promise().done(function() {
//your callback function
});
});
I am taking a web development class. Today the teacher gave us a piece of code that raised some questions that I haven't been able to satisfactorily solve through my own searching. The code in question was essentially this:
<script>
function selectmouse(e){
...
...
}
document.onmousedown = selectmouse;
</script>
My first question, is this a legitimate way of calling functions? Is this something that is done? I am of course familiar with the typical way of calling functions from HTML elements, for example
<body onmousedown="selectmouse(event)">
The code was supposed to be calling the function and passing it the event object for the onmousedown. After playing with the code for a while I found a few unusual things.
First, if I put parenthesis after the function call, like I am used to doing (i.e. selectmouse();), then the function resolved immediately upon loading the page, with a value of 'undefined' for the variable. This makes intuitive sense to me, because I assume the browser is treating it like a variable assignment and therefore calling the function as it parses the code, as it normally would to assign a variable.
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to. It would call the function when the mouse was pressed in any part of the body, and it sent the event object as the variable for the function. But I can't figure out why. I can't find reference to anything similar to it online, and I've never seen anything like it before. Is this a legitimate way to do something like this? Or is this bad code that happens to be working for some reason and would probably cause problems in the future? Why is it working?
document.onmousedown = selectmouse; //note: never do this except in old browsers
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to.
That's not weird. You are passing the reference of the function to the browser, not executing it.
For example, you have this function:
function callback(){
alert("clicked!");
}
document.body.onclick = callback;
You pass the reference to onclick and the browser will know what function to call when the event is triggered. But if you do it like this:
document.body.onclick = callback();
This will be evaluated into:
document.body.onclick = alert("clicked!");
//Note that this is simplified explanation to visualize what is happening.
//The returned value of alert() is not assigned to onclick.
//To be exact the returned value of callback() is the one that is being assigned.
//Similar to:
// ...onclick = (function(){ alert("clicked!"); })();
Then you will see an alert, and the browser will continue executing the rest of the code:
document.body.onclick = undefined;
<body onmousedown="selectmouse(event)"> <!-- Don't do this too -->
The parentheses are necessary because this code is not executed instantly. It is only executed when the event is triggered.
Anyway, you shouldn't attach events both using .onmousedown or onmousdown="...". There is a better way of doing it:
element.addEventListener("mousedown", callback, false);
Reason: If you use the onmousedown property, you can only attach one mousedown event. In most cases you would want to attach more than one.
Also attaching events inline might cause security problems (cross-site scripting), and that is exactly why Google decided to prohibit all developers from using them in developing Chrome apps/extensions.
This is legitimate code and is working as it should.
The way you are comfortable with is just a method we tried while the web was evolving, but at present we should better use the second way you showed, although its changed bit more to make you understand it in a better way using event bindings.
When you do
function selectmouse(e){
...
...
}
javascript will create a variable named selectmouse and save the function in that variable. So selectmouse is a variable of type function with the function body as its value.
document on the other hand can be related to class or specifically an object which is an instance. Each document and each HTML element or DOM node can have in it variables to store the functions to be called on user events like onmousedown.
so when doing
document.onmousedown = selectmouse;
we are inturn saying
when mousedown happens in document, the function named selectmouse
should be called
If you do
document.onmousedown = selectmouse();
it means
run the function selectmouse immediately and get the result, assign
the result to onmousedown event of the DOM Node document.
And if you ask why this is taken apart from the form
<body onmousedown="selectmouse(event)">
To answer in a simple way, HTML is Hyper Text Markup Language, its sole purpose is to represent formatted data, the quick evolution of web inturn made it deranged with behaviours like this and presentation code like inline css. So to make behaviour and presentation out of HTML and thus a better design we do this.
Please take time to take a look at how you can bind a function to an event which is the current tradeoff in doing this same thing.
For a detailed explanation please check the events sectio of ppk blog here
I think that is correct, because the function is being called within the script as if it were an object, to me is not the best way to do it, I would have like this (with jquery):
$(document).mousedown(function (event) {
// here the content of the function
});
<body onmousedown="selectmouse(event)">
In this example the browser evaluates the result of the expression selectmouse(event) and assigns it to the onmousedown property of the body, event is undefined and the selectmouse doesn't return anything so it's result is undefined.
It is equivalent of the following if it was inside a script tag
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse(event);
</script>
<body onmousedown="selectmouse">
When you remove the () you are assigning a function to the onmousedown property. Now the browser fires your callback method whenever the mousedown event is raised and it bubbles up to the body, passing the current event as the parameter you're declaring as "e". If another element also had an onmousedown event handler declared but it cancelled the event ( by calling event.cancelBubble = true ) the body's onmousedown handler will not be invoked.
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse;
</script>
In my plugin I need to be able to fire event(s) once the plugin was loaded.
I don't want to use the built in mechanism (adding it in the object params) since I need to be able to control the parameters which are sent along with the event firing.
The problem is that when I try to fire the event in onPluginReady it just doesn't fire.. While debugging I noticed that the m_proxies is empty (in JSAPIImpl::FireEvent), but if I try the same code for firing the event in the onMouseDown method then it works well.
This is my createJSAPI code:
FB::JSAPIPtr plugin::createJSAPI()
{
this->jsApi = JSApiPtr(new pluginAPI(FB::ptr_cast<plugin>(shared_from_this()), m_host));
return this->jsApi;
}
And this is the onPluginReady code:
void plugin::onPluginReady()
{
this->getRootJSAPI();
this->jsApi->fireMyEvent(this->myId);
}
and the event isn't fired, though this does:
bool plugin::onMouseDown(FB::MouseDownEvent *evt, FB::PluginWindow *)
{
this->jsApi->fireMyEvent(this->myId);
return false;
}
Why is that?
Thanks.
onPluginReady is likely to be called before your onLoad callback from the param tag gets called; that means your event handlers aren't attached yet. That's the reason that FireBreath provides the onload param callback -- it gives you a place to attach event handlers and find out that things are loaded.
Edit to clarify from comments:
The callback will be provided with a single parameter which contains a reference to your root JSAPI object. Note that in this case it is not the object or embed tag, just the JSAPI object, so you can use any methods or properties from there.
I'm looking for a way to check within pageLoad() if this method is raised during load event because of a postback/async postback or because of being loaded and access the first time.
This is similar to Page.IsPostback property within code behind page.
TIA,
Ricky
One way you could do that is to wire up an Application.Load handler in Application.Init, then have that handler unbind itself after running:
Sys.Application.add_init(AppInit);
function AppInit() {
Sys.Application.add_load(RunOnce);
}
function RunOnce() {
// This will only happen once per GET request to the page.
Sys.Application.remove_load(RunOnce);
}
That will execute after Application.Init. It should be the last thing before pageLoad is called.
#Darren: Thanks for the answer. I had tried to create pageLoad with event argument ApplicationLoadEventArgs as parameter (see below). However according to this:
The load event is raised for all postbacks to the server, which includes asynchronous postbacks.
As you have indicated, the isPartialLoad property does not cover all postback scenarios. It'll be nice if the event argument also contain isPostback property.
function pageLoad(sender, arg) {
if (!arg.get_isPartialLoad()) {
//code to be executed only on the first load
}
}
#mmattax: I'm looking for property that can be called from client-side (javascript).
What you can do is wire up to the load event of the Sys.Application class. you can then use the isPartialLoad property of the Sys.ApplicationLoadEventArgs class. I believe that would let you know if you are in a async postback or not.
To know if you are in a post back, you'll have to handle that in server side code and emit that to the client.
You could have a hidden input that you set to a known value on the server side if it's a postback/callback - and your javascript could check that value.
That said, I really hope that there's a client-only solution for this.
Edit: #mmattax - I believe he's looking for a client-side solution - the JavaScript equivalent of that.
You can still use Page.IsPostback during an async call.
Application.Init is probably a more appropriate event to use, if you only want the code to execute on the first load.
#Dave Ward: This normally would work. However, the code is to attach event on behavior object. Because the creation of behavior object happens during Application.Init, attaching to that event will lead to unpredictable behavior.
It will be nice if there is PostInit event.
#Dave Ward:
The use of RunOnce method works perfectly. This solve my problem without having the workaround to check first if handler already exist before attaching to an event.
I'll mark your answer as an accepted answer. Thanks again.
Here's our Ajax equivalent to isPostback which we've been using for a while.
public static bool isAjaxRequest(System.Web.HttpRequest request)
{//Checks to see if the request is an Ajax request
if (request.ServerVariables["HTTP_X_MICROSOFTAJAX"] != null ||
request.Form["__CALLBACKID"] != null)
return true;
else
return false;
}