I'm building a Google Maps app, and have an image of a compass outside of the map. Each of the compass points is on an image map, and has its own id. I want the 45° orientation to change, depending on the compass point clicked.
Within the google maps initialize function, I have this line:
google.maps.event.addDomListener(document.getElementById('compassSouth'), 'click', map.setHeading(180));
However, that handler is fired on page load, and doesn't respond after that. It's not due to the image map - the same behavior happens if the element is a button.
I have another handler in the same format that responds to a button press, which works fine.
The code is doing exactly what you are telling it to do: It is calling the map.setHeading(180) function immediately when you execute your code.
Let's write it out line by line for clarity:
var element = document.getElementById('compassSouth');
var listener = map.setHeading( 180 );
google.maps.event.addDomListener( element, 'click', listener );
As you can see, this code calls map.setHeading(180) immediately where you write that code, and then it passes the return value from that function (which I'm now calling listener) into addDomListener().
But map.setHeading(180) doesn't return any value at all - or put another way, it returns undefined, so listener is undefined.
addDomListener() sees that undefined value and ignores it: it doesn't set any listener at all!
What you need to do instead is pass a reference to a function into addDomListener(). You could do this easily like this:
function compassClick() {
map.setHeading( 180 );
}
var element = document.getElementById('compassSouth');
google.maps.event.addDomListener( element, 'click', compassClick );
Or as you'll often see, you can make that compassClick function an anonymous function instead (now going back to code more like your original):
google.maps.event.addDomListener(
document.getElementById('compassSouth'), 'click',
function() {
map.setHeading( 180 );
}
);
Related
First of all: this site has been a great help already to me, thnx a lot!
In a Google doc I am adding a vertical panel to assist the user in composing and sending a letter. I used the example in this thread and it works fine showing the panel:
function onOpen() {
var app = UiApp.createApplication().setWidth(455).setTitle('User input')
var panel = app.createVerticalPanel().setStyleAttribute('padding','25px')
var label1 = app.createLabel('Your name please');
var box1 = app.createTextBox().setId('Field1').setName('Field1');
panel.add(label1)
panel.add(box1)
var pasteHandler = app.createServerChangeHandler('readTextbox');
pasteHandler.addCallbackElement(panel);
var clickButton=app.createButton('OK').setId('PasteTest').addClickHandler(pasteHandler)
panel.add(clickButton);
app.add(panel);
DocumentApp.getUi().showSidebar(app);
//I want to arrive here only after a value is entered in the panel
// ... follows more code ...
}
function readTextbox(e){
var app = UiApp.getActiveApplication();
var boxValue=e.parameter.Field1;
//how to get this e.parameter values (more than one..) to the main function
return app;
}
My question is: how to make the main function wait after 'showSidebar' until a value is entered?
Second question: how to use this input outside the handler, e.g. for writing in the document? I found a workaround by writing the fields to a spreadsheet within the handler, but that's not very elegant ;-)
Many thanks in advance...
You can't make the onOpen() function wait, but you don't need to. You have a click handler and the readTextbox() function. And you don't need to get the readTextbox() function to branch back to the onOpen() function. If there are conditions that require branching to different functions depending on what the user does, then you can create a new function.
You can call a function from a function just by using it's name, and parenthesis after the name and a semicolon.
function readTextbox(e){
var app = UiApp.getActiveApplication();
var boxValue=e.parameter.Field1;
anotherCoolFunction(boxValue);
//how to get this e.parameter values (more than one..) to the main function
return app;
}
function anotherCoolFunction(someArg){
Logger.log('Some Arg: ' + someArg);
}
In the above code, after the name is entered and the user clicks the button, the readTextBox function runs, then the readTextBox() function calls the anotherCoolFunction(boxValue); function and passes the variable boxValue to the anotherCoolFunction().
You can verify that it works, by looking at the log. Choose the View Menu, and the Logs menu item to display the Log output.
Let's say we have a simple Backbone View, like this:
class MyView extends Backbone.View
events:
'click .save': 'onSave'
onSave: (event) ->
event.preventDefault()
# do something interesting
I want to test that event.preventDefault() gets called when I click on my element with the .save class.
I could test the implementation of my callback function, pretty much like this (Mocha + Sinon.js):
it 'prevents default submission', ->
myView.onSave()
myView.args[0][0].preventDefault.called.should.be.true
I don't think it's working but this is only to get the idea; writing the proper code, this works. My problem here is that this way I'm testing the implementation and not the functionality.
So, my question really is: how can I verify , supposing to trigger a click event on my .save element?
it 'prevents default submission', ->
myView.$('.save').click()
# assertion here ??
Thanks as always :)
Try adding a listener on the view's $el, then triggering click on .save, then verify the event hasn't bubbled up to the view's element.
var view = new MyView();
var called = false;
function callback() { called = true; }
view.render();
// Attach a listener on the view's element
view.$el.on('click', callback);
// Test
view.$('.save').trigger('click');
// Verify
expect(called).toBeFalsy();
So you want to test that preventDefault is called when a click event is generated, correct?
Couldn't you do something like (in JavaScript. I'll leave the CoffeeScript as an exercise ;)):
var preventDefaultSpy;
before(function() {
preventDefaultSpy = sinon.spy(Event.prototype, 'preventDefault');
});
after(function() {
preventDefaultSpy.restore();
});
it('should call "preventDefault"', function() {
myView.$('.save').click();
expect(preventDefaultSpy.callCount).to.equal(1);
});
You might want to call preventDefaultSpy.reset() just before creating the click event so the call count is not affected by other things going on.
I haven't tested it, but I believe it would work.
edit: in other words, since my answer is not that different from a part of your question: I think your first approach is ok. By spying on Event.prototype you don't call myView so it's acting more as a black box, which might alleviate some of your concerns.
This jQuery selector matches a Rails 3 HTML form for a new model: $('form[id^="new_"]')
I'd like to have a simple focus function run each time a matching form loads. Sometimes the forms are loaded via a simple GET but also via Ajax. In the latter case, the content returned can be either HTML or escaped JS.
I was hoping jQuery would be able to match all cases via the selector, .on(), and the "load" event, but I can't seem to make that work for ANY case. Code:
$(document).ready(function() {
$('form[id^="new_"]').on("load", function(){
console.log("Matched!")
});
})
Any ideas?
Thanks Justice. I'm afraid I wasn't able to get your code to work. I'm using the following callback with the new custom event defined outside it as shown and I don't think the $('form') is triggering the event.
$('.shows-children').bind('ajax:success', function(evnt, data, status, xhr){
var boxSelector = '#' + $(this).data("shows");
$(boxSelector).html(xhr.responseText);
$('form').trigger('customevent');
});
$(document).on('customevent','form[id^="new_"]', function(){
console.log('Matched!')
});
(I'm surprised it seems more involved than expected to have jQuery act on HTML returned in an Ajax response.)
$(document).on("change","form[id^=\"new_\"]" function(){
console.log("Matched!")
});
For delegation, you want to delegate the original selector to a parent, as the event will bubble up.
However, load does NOT bubble up. In this case, change may suffice, but it'll trigger and attempt to see if the delegate is valid every time the document changes.
I would then suggest that you create a custom event after AJAX loads for the form.
Example:
$(document).on("customevent","form[id^="new_"]" function(){
console.log("Matched!")
$.ajax(url, function(response){
//success
$(document).append(response);
$('form').trigger('customevent');
});
});
HTH
How can I receive all events attached to an element with dojo?
dojo.query('#mydiv') // which events does #mydiv has?
To get all events on a DOM element:
// Get my div
myDiv = dojo.byId("myDiv");
// Obtain all event-related attributes
var events = dojo.filter(
myDiv.attributes,
function(item) {
return item.name.substr(0, 2) == 'on';
}
);
// Execute first found event, just for fun
eval(events[0].value);
If you get myDiv using dojo.query, remember that dojo.query returns an array, so your element would be in myDiv[0].
This solution does not work with events attached with dojo.connect. There probably is a way to extract this info from Dojo inner workings, but you would have to delve into the source code to understand how.
Another option is that you explicitly manage all dojo.connect events with a global registry. You could use dojox.collections to make this easier. For example, creating a global registry whose keys will be the dom nodes, and values will be the handles returned by dojo.connect (these handles contain the dom node, the type of event and the function to execute):
// On startup
dojo.require(dojox.collections.Dictionary);
eventRegistry = new dojox.collections.Dictionary();
...
// Registering an event for dom node with id=myDiv
var handle1 = dojo.connect(dojo.byId("myDiv"), "onclick", null, "clickHandler");
// Check if event container (e.g. an array) for this dom node is already created
var domNode = handle1[0];
if (!eventRegistry.containsKey(domNode))
eventRegistry.add(domNode, new Array());
eventRegistry.item(domNode).push(handle1);
...
// Add another event later to myDiv, assume container (array) is already created
var handle2 = dojo.connect(dojo.byId("myDiv"), "onmouseover", null, "mouseHandler");
eventRegistry.item(domNode).push(handle2);
...
// Later get all events attached to myDiv, and print event names
allEvents = eventRegistry.item(domNode);
dojo.forEach(
allEvents,
function(item) {
console.log(item[1]);
// Item is the handler returned by dojo.connect, item[1] is the name of the event!
}
);
You can hide the annoying check to see if event container is already created by creating a subclass of dojox.collections.Dictionary with this check already incorporated. Create a js file with this path fakenmc/EventRegistry.js, and put it beside dojo, dojox, etc:
dojo.provide('fakenmc.EventRegistry');
dojo.require('dojox.collections.Dictionary');
dojo.declare('fakenmc.EventRegistry', dojox.collections.Dictionary, {
addEventToNode : function(djConnHandle) {
domNode = djConnHandle[0];
if (!this.containsKey(domNode))
this.add(domNode, new Array());
this.item(domNode).push(djConnHandle);
}
});
Using the above class you would have to dojo.require('fakenmc.EventRegistry') instead of 'dojox.collections.Dictionary', and would simply directly add the dojo connect handle without other checks:
dojo.provide('fakenmc.EventRegistry');
eventRegistry = new fakenmc.EventRegistry();
var handle = dojo.connect(dojo.byId("myDiv"), "onclick", null, "clickHandler");
eventRegistry.addEventToNode(handle);
...
// Get all events attached to node
var allEvents = eventRegistry.item(dojo.byId("myDiv"));
...
This code is not tested, but I think you get the idea.
If its only for debugging purpose. You can try dijit.byId("myId").onClick.toString(); in your firebug console and you can see the entire onclick code this works even if the function is anonymous you can view the content of anonymous content.
I want to add an on blur event to a dojo timetextbox but the event never been runned
so the declaration of the timetextbox is like this:
<label>End</label><input id="endp" name="endp" onBlur="calculateTimeSpent2(startp,endp,output);" />
the javascript function is like this:
function calculateTimeSpent2(startp,endp,outputp)
{
var tmp0=document.getElementById('startp').value.split(':');
var tmp1=document.getElementById('endp').value.split(':');
if (tmp0[0]!='' && tmp1[0]!='')
{
var val1= findtime(tmp0[0],tmp0[1],tmp1[0],tmp1[1]);
var tmp=val1.split(':');
if (tmp[0].indexOf('-')==-1)
document.getElementById('outputp').value=val1;
else
{
alert ("Start Time must be lower than End Time ");
document.getElementById('endp').focus();
}
}
}
I don't understand why dojo didn't execute the event correctly while loosing the focus.
I tried to put the type=text but it does'nt work.
Thanks for help.
startp, endp and output are probably undefined at the time the method handler is invoked. It doesn't look like your function actually uses the arguments it names. Perhaps you don't need to pass in any values at all?