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.
Related
This is my js file content:
window.onload = function() {
obj = document.getElementById("_accountwebsite_id");
Event.observe(obj, 'change', function () {
alert('hi');
});
}
I want to fire the on change event for my dropdown: _accountwebsite_id . The prototype library it is loaded before this file. I got no errors in the console. Where am i wrong ? thx
You're doing a lot of extra work here that Prototype does for you. First off, setting the document's onload method not only is really old-school, it also will clobber any previously set observer on that event.
$(document).observe('dom:loaded', function( ... ){...});
...is the modern way to register one (or more) event listeners to the document load event.
Next, you're using getElementById here, which will work, but does not return a Prototype-extended object in some browsers.
$('element-id');
...will both get the element reference and extend it if your browser failed to respect every aspect of prototypal inheritance.
Finally, this whole thing can be made both simpler and more bulletproof by using a deferred observer. Imagine if your interface DOM was updated by Ajax -- that would make your observer miss the events fired by this select element, because it was not referring to the same (===) element, even if the ID matched.
$(document).on('change', '#_accountwebsite_id', function(evt, elm){
alert(elm.inspect());
});
This observer will respond to any change event on an element with the correct ID, even if it was added after the observer was registered with the document.
I'm new to backbone. I have been looking it has been used in Saiku. I came across the below line.
Saiku.session.trigger('workspace:new', { workspace: this });
Is 'workspace:new' an event? How does backbone trigger recognize it as an event?
Short answer: yes, workspace:new is an event.
Backbone has several built-in events that you can listen for. But you can also trigger custom events, as this code does. The event is identified by only a string (in this case, "workspace:new"). When you call trigger on an object that inherits from Backbone's Event Module, that event "happens." As a second parameter to trigger, you can pass some data about the event, anything you want accessible from the event handler function.
Then, usually somewhere else, there will be code waiting for that event to happen. That is set up by calling the .on or .listenTo methods.
Here's a basic example: (See it in action on JSBin)
var model = new Backbone.Model();
model.on('my-event', function (data) {
console.log("my-event happened!");
console.log(data);
});
model.trigger('my-event');
model.trigger('my-event', 'some-data');
model.trigger('my-event', { anything: 'works' });
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.
Good day to all.
I'm writing an application using Marionette.js and recently I started noticing that moving from view to view and starting/stopping different modules memory consumption grows and not getting released. I started wondering whether I unbind my events correctly and whether I bind to them correctly as well.
So, I have the following cases
Modules
My application consists of sub-applications (modules). When I define a module I do some binding to global event aggregator. Something like this:
MyApplication.module(...) {
var api = { ... some functions here ... }
// Binding to events
MyApplication.vent.on('some:event', function() {...});
MyApplication.vent.on('some:other:event', function() {...});
}
I have checked the documentation and understand that "on" is not a very good choice, I should probably use "listenTo":
MyApplication.module(...) {
var api = { ... some functions here ... }
// Binding to events
this.listenTo(MyApplication.vent, 'some:event', function() {...});
this.listenTo(MyApplication.vent, 'some:other:event', function() {...});
}
But, here is the question, when module gets stopped, does it call "stopListening" or some other internal method that unbinds all the events I have bound in it? I checked the source code of the marionette's module and documentation but, if I understood correctly, when stop is called I need to take care of unbinding everything myself. Am I right?
Controllers
Can be initialized and closed. From the documentation I see that:
Each Controller instance has a built in close method that handles unbinding all of the events that are directly attached to the controller instance, as well as those that are bound using the EventBinder from the controller.
Does it mean that if do the following I correctly unbind all of the events I bound in the controller? I guess the answer is yes.
MyApplication.module(...) {
var controller = Marionette.Controller.extend({
...
// This will be unbinded as I understand?
this.listenTo(someObject, 'some:event', _.bind(function() {
// This will also be unbinded
this.listenTo(someOtherObject, 'some:event', function() {
// This won't be, because in this case this is not in a "controller"
// context but in a function's context which wasn't bound to "controler"
// context.
this.listenTo(some3rdObject, 'some:event', function() { ... });
});
}, this));
});
// Create controller when this sub-application gets initialized.
Contents.addInitializer(function () {
MyModule.Controller = new controller();
});
// Destroy controller and unbind all its event handlers.
Contents.addFinalizer(function () {
MyModule.Controller.close();
delete Contents.Controller;
});
}
So, with controllers I don't need to do anything as long as I use "listenTo", correct?
Views
In views, according to documentation, all gets unbinded when the view gets closed. And again, as long as I use
this.listenTo(..., 'some:event', function() {...});
I should be ok, correct?
To summarize... I only need to take care of unbinding in module's stop event, in all other cases it is taken care of by marionette's core as long as I don't use direct "on" and use "this.listenTo" instead.
Thank you all very much in advance for your answers.
Controllers and Views do their cleaning work correctly but Modules doesn't do it.
Here is more detailed info:
Controller
If you close controller it will unbind all events that are bonded using listenTo in context of controller. You can look in in controller source code.
View
According to Backbone.View source code remove method does stopListening. Also Marionette.View's close calls backbone's remove under the hood. Here is source code.
Module
I've checked Marionette.Module source code but there is no stopListening in stop method. So, Marionette.Module#stop does not do unbinding of events and you should do it manually in finalizer or in onStop, onBeforeStop handlers.
UPDATED: After Marionette.js v1.7.0 Marionette.Module calls stopListening on stop to unbind all events.
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.