Wait for response of javascript on SWT browser - javascript

I have no idea how to do this. I am using swt browser to run openlayers , I had some basic function. So I want to capture the coordinates where I click on a map.
I try ta add a listener to the browser widget, so it calls a function on javascript that returns the coordinates of the mouse, but for what I can tell the click listener on the browser gets executed first, then on javascript the clik event gets executed, so on the first try it returns undefined and then it returns the previews clicks, not the current one.
So part of the problem is that in order to get the coordinates i am using ol3 function to get the position
I am using ol3 functions to set the mouse click
map.on('singleclick', function (evt) {
position = evt.coordinate;
....
})
and I have a function to return position but it takes a while to position to change.
Is there a way to create something like a callback that when a function in javascript is done it will call a function on java so it can update my window?

You can define a function in your code that can be called from JavaScript by using a class derived from BrowserFunction:
class MyFunction extends BrowserFunction {
MyFunction(Browser browser, String name) {
super (browser, name);
}
#Override
public Object function(Object[] arguments) {
// Your code
}
}
name is the JavaScript name for the function.
More details here

Related

It's possible mix Javascript and C# code in a DOM event in Blazor?

I'm trying to achieve the next in Blazor WebAssembly; I need to be able to listen for an event in a component, and use both Javscript and C# code like the next way:
<button onclick="console.log('Showing event from Js: ' + event); #Test()">Test</button>
#code {
public void Test()
{
JSRuntime.InvokeVoidAsync("console.log", "Showing log from C#");
}
}
The first problem is that I get the error "cannot implicitly convert type void to object", so if I change the Test method signature just to return an object
public object Test()
{
JSRuntime.InvokeVoidAsync("console.log", "Showing log from C#");
return null;
}
The App compiles but once the page is loaded, the "Test()" function is executed automatically, and if I click the button, it just executes the Javascript code, and not both pieces of code.
I know I should handle events in Blazor prefixing the event name with "#" symbol in order to call a C# method, and execute Javascript code there using the interop, but in that way, I can't use the default Javascript "event" which I need to use, instead of the Blazor "event" version.
Thanks in advance!
You can only have 1 onclick attribute, so either call the C## method from JS or call the JS code from C#. In both cases you will need Interop, there is no support for combining this in the way you are trying to.
the "Test()" function is executed automatically
Yes, in onclick="... #Test()" it is executed when the page renders, not when the button is clicked.

How to pass an argument to the external function in addEventListener

OK this question already has a lot of answers in web, I have read all of them and I don't think any of them fit my situation. After tried like 2 hours I decide to give up and ask the people here:
This is the simplified example: I have a function, which will be triggered by a button click, I will call it click and it has an parameter with it. Inside the click function, I need to add an event listener to the window object use addEventListener().
I need the event to be passed to the handleKeydown(), because I need to know if the shift key (keycode == 16) is pressed down and I need to pass the parameter map to the handleKeydown() because I need to do something on it. after that, there will be more things done, let's say it has a function to draw pictures on the map
So I write the codes below:
function click (map) { // can be called multiple times, so multiple listener are attached, not needed
this.addEventListener("keydown", function(e) {handleKeydown(e, map)}, false)
drawPictureOnMap(map);
}
function deletePictureOnMap() {
// user always call this function to delete the picture before they
// call the click() to draw a new one
// delete the picture on map
}
function handleKeydown(e, map) {
if (e.keyCode == 16) {
// do something to map, e. g.:
// map.getLayers()
}
}
It works all fine until today, I find a big problem with it.
Because the function click can be called multiple times, so I found that multiple event listener are attached to the window object. That has a negative effect on the performance.
The idea is to attach a removeEventlistener() to another function, which is mean to delete the picture on map. Because, the user always delete the picture before they draw a new one.
The Problem is, I can't remove a event listener with anonymous function. But if I want to use external function, I can't find a way to pass the map parameter to it.
Another Idea is, make the map parameter global, so I don't need to pass it to the handleKeydown. But I am not willing to do it.
There are a few ways to solve this. Without more information, the one that comes to mind is this: Maintain a WeakMap of the handlers for a given element (a WeakMap so that if the element is removed and all references to it are dropped, the map entry automatically gets removed). Even IE11 supports WeakMap (enough of it, anyway).
const elementClickHandlers = new WeakMap();
Within that element-to-handlers map, store a Map of the handlers keyed by map.
Then in click, use those maps:
function click (map) { // can be called multiple times, so multiple listener are attached, not needed
let handlers = elementClickHandlers.get(this);
if (!handlers) {
handlers = new Map();
elementClickHandlers.set(this, handlers);
}
let handler = handlers.get(map);
if (!handler) {
handler = function(e) {handleKeydown(e, map)};
handlers.set(map, handler);
}
this.addEventListener("keydown", handler, false)
drawPictureOnMap(map);
}
When removing, find the handler for the element and map and remove that:
const handlers = elementClickHandlers.get(theElement);
if (handlers) {
const handler = handlers.get(map);
if (handler) {
handlers.delete(map);
someElement.removeEventListener("click", handler, false);
}
}
But there may be simpler ways to solve the problem we could suggest, if you showed a proper MCVE.

JavaScript callback firing out of sequence

I thought I'd finally figured out JavaScript callbacks as I found a use for one, but it is firing out of sequence.
In a Google Maps application I have a function which checks if the map is zoomed to the maximum level before allowing the user to store the (new) location of a marker.
The check function is:
function checkForMaxAccuracy(nextOperation) {
// Check at full zoom and alert if not
maxZoomService.getMaxZoomAtLatLng( newLocationMarker.getPosition(), function(response) {
var levelToZoomTo;
if (response.status != google.maps.MaxZoomStatus.OK) {
alert("Please ensure you are at maximum zoom to ensure most accurate placement possible.");
// continue after this alert as Mao could be fully zoomed but zoom service not reporting correctly
} else {
//alert("The maximum zoom at this location is: " + response.zoom);
if (response.zoom > map.getZoom()) {
alert("You must be zoomed in to the maximum to ensure most accurate placement possible before saving.\n\n Click [ Zoom here ] in theInfo Window to zoom to the maximum.");
// return after this error as Mao is definitely not fully zoomed
return;
}
// Call the update function to do the saving to the database
nextOperation();
}
});
}
Where nextOperation is the callback function.
This is called by two different functions, the first, and simplest (because it's not fully written yet) works perfectly:
function saveNewLocation() {
checkForMaxAccuracy(function () {
alert("save new");
});
}
If not fully zoomed I get the warning message displayed by the check function. If the map IS fully zoomed I get the alert 'save new' message displayed which is a place holder for the code to do the database update.
However, the same check function is also called from a more complete function. This other function is called when the user is updating the location of an existing marker.
This second function actually sets the onclick property of an HTML span object - effectively enabling and disabling the save control depending on what is going on.
In this function I am setting the onclick as follows:
document.getElementById('savePosition'+locationId).onclick = (state)?function(){checkForMaxAccuracy(doUpdate(locationId,"position"));}:null;
In this case, when I click the corresponding span element the doUpdate() function gets fired before the checkForMaxAccuracy() function.
(Apologies for the use of ternary operator.. I know if makes things a little difficult to read, but I'm leaving as is in my code in case I've got the bracketing or syntax slightly wrong here and that's what's causing my problems.)
My guess is I'm getting something fundamentally wrong in my 'understanding' of callback functions.
Can anyone explain what I'm doing wrong?
-FM
checkForMaxAccuracy(
doUpdate(locationId,"position")
);
will pass the returned value of doUpdate as an argument of checkForMaxAccuracy. In other words, you're not passing the callback function itself but its return value.
What you could do is:
checkForMaxAccuracy(
function() {
doUpdate(locationId,"position")
}
);

Call an object as a function in JavaScript

I'm trying to execute JavaScript functions that are called when a event (for example onClick event) is performed on a web page with JavaScript code. I'm getting the function from the event like this :
var attributval = document.getElementsByTagName("a").getAttribute('onClick');
and I'm trying to execute this object (which a JavaScript function in fact) as a function (suppose we have <a onClick = alert('whatever');> on this example, I tried:
var attributval = document.getElementsByTagName("a").getAttribute('onClick');
attributval() = function(){attributval};
attributval();
but it didn't work.
A DOM attribute is not the same as a JavaScript property (even though they can have the same name onclick). You should use
var attributval = document.getElementsByTagName("a")[0].onclick;
to retrieve a function (or null) from the JS object (as opposed to getAttribute(), which will most likely return a toString() for the property).
Now, attributval() = is illegal syntax, as attributval() is not an l-value (you cannot assign to it).
attributval(); will work but without the second line (which is illegal JavaScript) it will invoke the original A element onclick handler (if one is defined) or throw an exception (if the onclick handler is null).
Skip trying to create a function around the function. Just call it:
var attributval = document.getElementsByTagName("a")[0].onclick;
attributval();
try
var attributval = document.getElementsByTagName("a")[0].getAttribute('onClick');
By using get attribute you are returning a string so your only way is to use eval(onclickString) or var fn = new Function(onClickString); fn();
attributval is simply a string, correct? If you trust this code, execute it with eval(attributval) -- however any reference to this won't work.
What you probably want is to manually trigger an event. jQuery makes that easy.
If you want to do more than a click, then Chris McDonald's answer at Is it possible to trigger a link's (or any element's) click event through JavaScript? seems to fit the bill, although you might need to heed the third comment.
I thought I'd add a short answer on how to work with events using jQuery, since it seems relevant.
// Select the link using it's ID field (assuming it has one)
var myLink = $('a#myLink')
// Add a click event to the link
myLink.on('click', function(e) {
console.log("I've been clicked!");
});
// Trigger the click event manually. This would result in the above
// function being run. Interestingly, this will not cause the browser
// to follow the link like a real click would
myLink.trigger('click');
// Remove the click event (this removes ALL click events)
myLink.off('click');
// Add a click event to the link that only runs once, then removes itself
myLink.one('click', function() {
alert("I'll only bother you once!");
});
// Add a click event that you can identify from other click events.
// This means that you can trigger it or remove it without bothering other
// click events
myLink.on('click.myClick', function() {
alert("This click event has been identified as 'myClick'");
});
// Now you can trigger it without triggering other click events
myLink.trigger('click.myClick');
// And remove it, also with no harm coming to other click events
myLink.off('click.myClick');
Hope this helps

Javascript event firing before action occurs

I am trying to write a script so that when I play an embedded sound object, a picture that I also have embedded will change.
function changePic() {
document.getElementById("sound").onclick = transform(document.getElementById("pic"));
}
function transform (pic) {
pic.src = "";
alert ("done");
}
The problem is that when I load the page, the Javascript code automatically runs even though I don't click play (autostart is set to false) on the sound object. Does anyone have an idea as to what is causing this?
When you write onclick = transform(...), you're calling transform and assigning the result to onclick.
You need to set the handler to an anonymous function that calls transform, like this:
document.getElementById("sound").onclick = function() {
transform(document.getElementById("pic"));
};
However, this is the wrong way to add events.
You should call element.addEventListener / element.attachEvent. (or just use jQuery)

Categories

Resources