How do I properly invoke an onChange event fired off by filepicker? - javascript

I'm using filepicker-rails, and setting this up:
<%= p.filepicker_field :bathroom_images, cache: true, multiple: true, onchange: "$.onFileUpload(event);" %>
This sets the onChange event to whatever function I throw in (more details here)
Now here's where I have two questions: how do I need to set up my coffeescript to be invoked by this?
ready = ->
console.log("ready")
onFileUpload = (event) ->
console.log "results of upload stored"
window.results = event
$(document).ready ready
When I upload file and the event fires off, this code throws an error:
Uncaught TypeError: $.onFileUpload is not a function
That's the concrete question. Here's what I'm really curious about: ok, so you tell me how to call it, what aspects of JS am I not understanding that I need to learn better in order for me to understand what's going wrong here?
I thought I was creating a variable (onFileUpload) that references the function I want to pass the event fired off by the form to. What am I missing here?

The first issue is that you're asking rails to call $.onFileUpload(event); but you're implementing a function named onFileUpload(event) that lacks the '$.' part. I suggest just changing that in the rails code to onFileUpload(event).
The second issue is that rails is trying to call this method on the global namespace but you're hiding it in a sub-scope that rails can't access. This happens because you wrapped all your code in a jQuery ready event and due to the way javascript works, any code inside that function it not accessible by the code outside it unless specified otherwise.
Now to fix this simply make onFileUpload a property of the global window object. I'm not a pro in coffeescript so i don't know if this is the exact way to do it, but you can fix this by changing your code to:
ready = ->
console.log("ready")
window.onFileUpload = (event) ->
console.log "results of upload stored"
window.results = event
$(document).ready ready
This should make the function onFileUpload global allowing rails to call it.

Related

Appending function to Custom Event in Prototype JS

I'm working with a 3rd party product where I am extending the UI with my own custom functionality. Within part of that I need to call an event after the UI has been updated with an AJAX call. Luckily the app fires a call to a Custom Event using the Prototype JS library after the call is complete, like this:
$(document.body).fire("ns:customevent");
If I add my own custom event with the same name then this works as expected
$(document).observe("ns:customevent", function(event) {
//do custom stuff here
});
[I could not get $(document.body).observe() to work here but I don't think that really matters.]
My concern here is that there may be other parts of the app that have registered functions against that event, and I am (blindly) overwriting them with my own, which will lead to issues further down the line.
Does Prototype append custom functions even though they have the same name or does it in fact overwrite them? If it does overwrite them then how can I append my function to anything that is already existing? Is there anyway of viewing what
I would imagine something like this, but I hardly know Protoype and my JS is very rusty these days.
var ExistingCustomEvent = $(document.body).Events["ns:customevent"];
$(document).observe("ns:customevent", function(event) {
ExistingCustomEvent();
//do custom stuff here
});
I can't add my event handler or add in code to call my own function, I want to try avoiding the 3rd party library (if that would even be possible).
Thanks.
As an FYI for anyone else that stumbles upon this question, following the comment from Pointy it turns out that Prototype does append the functions to the custom event.
I verified this by trying the following and both alerts fired.
$(document).observe("ns:customevent", function(event) {
alert("ALERT 1");
});
$(document).observe("ns:customevent", function(event) {
alert("ALERT 2");
});
Great :)

calling a function using a mouse event without attaching it to an HTML element?

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>

Passing console.log as listener for events

See the following fiddle: http://jsfiddle.net/calvintennant/jBh3A/
I would like to use console.log as a listener for an event :
badButton.addEventListener('click', console.log);
As demonstrated in the fiddle, this will result in an error.
I understand how to circumvent the error (by wrapping console.log in another function). What I would like to know is why the error happens. Is there some security feature preventing the use of native functions being used in this way?
That's because inside the log function, this must be the console (it's implementation dependant). If you pass it directly as event handler, this would be the widget as you can see by trying
goodButton.addEventListener('click', function(e) { console.log(this);});
Another solution than wrapping it in a function you create is to pass console.log.bind(console) (but not if you want to be compatible with IE8) :
goodButton.addEventListener('click', console.log.bind(console));

javascript function is calling more than once

In my javascript code ( which is too long , so i can`t put it here ), functions are calling more than once , like suppose :
$("#button").bind({ click : Call }); // bind the Call with button click event
function Call()
{
alert("This message shows me more than once when i clicked the button");
}
if this alert message shows me more than once it means function Call() is calling more than once. Can anybody guess or tell me what's going on in my code? (Please don't ask me for code)
Works for me: http://jsfiddle.net/aC8Bm/
I'm guessing that you are binding more than once somewhere.
Also, I'd recommend either returning false from the Call function, or stopping event propagation.
One more thing: avoid naming functions with an uppercase -- that's reserved for constructor functions by convention.
You're hooking the event handler to the button the number of times 'Call' is being called. Do you have this code in something like a template or partial file?
Instead of doing this inside any function:
$("#button").bind({ click : Call });
Place the following somewhere outside:
$("#button").live("click", Call);
It will bind once for all existing and ever added #button

Can an Orbeon event in an XBL be dispatched from Javascript?

Orbeon version: Orbeon Forms 3.8.0.201005270113
I have the following code in a Javascript file. This code is executed, but it seems like the model in the XBL is not found.
ORBEON.xforms.Document.dispatchEvent("model-name", "event-name");
Here is the model in the XBL. There are several models in the XBL. I don't see any message, so it seems as though the model isn't found. I don't see any errors in the logs.
<xforms:model id="model-name" xxforms:external-events="event-name">
<xforms:action ev:event="event-name">
<xforms:message>Test</xforms:message>
</xforms:action>
</xforms:model>
Does anyone know if there is some trick to getting a dispatch to work from Javascript to XBL?
Thanks very much!
UPDATED:
Another thing that could be the problem (maybe?) is that calling the javascript from the XBL using instance(this) isn't working. I wonder if the instance of the class isn't tied to a component instance, therefore it can't find the model?
Here's the call to the javascript from the xbl that doesn't invoke the init method:
<xxforms:script>YAHOO.xbl.fr.myTest.instance(this).init();</xxforms:script>
Here's the call that does invoke the init() method:
<xxforms:script>YAHOO.xbl.fr.myTest.prototype.init();</xxforms:script>
Here's the javascript:
YAHOO.namespace("xbl.fr");
YAHOO.xbl.fr.myTest = function() {};
ORBEON.xforms.XBL.declareClass(YAHOO.xbl.fr.myTest, "xbl-fr-myTest");
YAHOO.xbl.fr.myTest.prototype = {
},
init: function() {
alert('test');
},
valueChanged: function() {
},
};
AFAIK you can't address the XBL-internal model directly from outside, because of its strong encapsulation.
Instead, you'll have to dispatch the event to the xbl component node. For example, if you want an instance of the fr:currency XBL to handle a certain event, you'll have to dispatch the event to that fr:currency element that's part of your XForm.
Inside the XBL, you can define xbl:handlers to act upon that event, triggering some JavaScript action or something else.

Categories

Resources