I want to perform some action in my SAPUI5 control when Page Up / Page Down is pressed.
How can we handle jQuery.sap.PseudoEvents such as sappageup and sappagedown in custom control?
In your control definition, try with
metadata: {
// ...
},
init: function() {
// ...
},
onsappageup: function() {
// Page up key pressed!
},
onsappagedown: function() {
// Page down key pressed!
},
From API reference:
SAPUI5 controls should simply implement an onpseudo-event (oEvent) method. It will be invoked only when that specific pseudo event has been recognized. This simplifies event dispatching even further.
Be aware that such pseudo events can be only fired if the control has received the focus first. To make the control focusable, provide the HTML attribute tabindex[video] to your control. E.g.:
render: (renderManager, myCustomControl) => renderManager
.write("<div")
.writeControlData(myCustomControl)
.writeAttribute("tabindex", "-1") // make it focusable
.write(">")
// ...
.write("</div>")
In case you're working on keyboard handling to navigate items, take a look at the delegate sap.ui.core.delegate.ItemNavigation.
API reference of ItemNavigation
Documentation topic "Supporting Keyboard Handling in List-like Controls"
Related
I'm trying set easyautocomplete on my input. Dataset i am geting from ajax json and there is some delay. If user is too fast and writes for example "Adam" and pushes tab, cursor skips to next input, but after easyautocomplete shows dialog on previous input and doesn´t hide it. Is there any way how to show easyautocomplete dialog only when i have cursor in input?
var options = {
minCharNumber: 3,
url: function(phrase) {
return "data?q=" + phrase;
},
getValue: function(element) {
return element.surname + " " + element.name;
},
template: {
type: "description",
fields: {
description: "phone"
}
},
ajaxSettings: {
dataType: "json",
method: "POST",
data: {
dataType: "json"
}
},
list: {
onClickEvent: function() {
/*Some action*/
},
hideAnimation: {
type: "slide", //normal|slide|fade
time: 400,
callback: function() {}
}
},
requestDelay: 400
};
$(".autoComplete").easyAutocomplete(options);
Minimum, Complete, Verifiable, Example
In order to easily see this result, you'll have to open up your dev tools and throttle your network traffic so the ajax connection takes a little while
Here's a Demo of the issue in jsFiddle
Handling Library Events (Doesn't Work)
My initial thought was you could handle this during some of the EAC lifecycle events that fired, like the onLoadEvent or onShowListEvent:
var options = {
url: "https://raw.githubusercontent.com/KyleMit/libraries/gh-pages/libraries/people.json",
getValue: "name",
list: {
match: {
enabled: true
},
onLoadEvent: function() {
console.log('LoadEvent', this)
},
onShowListEvent: function() {
console.log('ShowListEvent', this)
}
},
};
However, these methods don't seem to provide an option to alter the control flow and prevent future events
Updating Source Code (Works)
Peeking into the library's source code, Easy AutoComplete does the following ...
Handles keyup events
Which then calls loadData
Which fires an AJAX request with the provided URL
depending on the network and server speed, any amount of time can pass before step 4, and the input could lose focus
Once the ajax promise is returned, will call showContainer()
Which triggers the "show.eac" event on the container
Which then opens the list with the selected animation
During step 6, we could add one last check to confirm the selected input still has focus before actually opening, which would look like this:
$elements_container.on("show.eac", function() {
// if input has lost focus, don't show container
if (!$field.is(":focus")) {return}
// ... rest of method ...
Here's a working demo in Plunker which modifies the library's source code in a new file
Unfortunately, that's not a great practice as it leaves you fragile to future changes and transfers ownership of the lib maintenance to your codebase. But it does work.
I created Pull Request #388 with the proposed changes, so hopefully a long term fix within the library itself will be available at some point in the future.
Wrapper (Recommended for now)
If you don't want to muck with third party code, there are some weird workarounds to mess with the internal execution. We can't modify the showContainer method since it's inside a closure.
We can add another listener on the show.eac event so we can be a part of the event pipeline, however there are some challenges here too. Ideally, we'd like to fire before the library handler is executed and conditionally stop propagation. However, initializing EAC will both a) create the container we have to listen to and also b) attach an event listener.
Note: Event handlers in jQuery are fired in the order they are attached!
So, we have to wait until after the lib loads to attach our handler, but that means we'll only fire after the list is already displayed.
From the question How to order events bound with jQuery, we can poke into the jQuery internals and re-order attached events so we can fire our handler before the library's handler is called. That'll look like this:
$._data(element, 'events')["show"].reverse()
Note: Both e.stopPropagation() and e.preventDefault() won't work since they prevent future events; instead we need to take more immediate action with e.stopImmediatePropagation()
So the wrapper would look like this:
$("#countries").easyAutocomplete(options);
$(".easy-autocomplete-container").on("show.eac", function(e) {
var inputId = this.id.replace('eac-container-','')
var isFocused = $("#"+inputId).is(":focus")
if (!isFocused ) {
e.stopImmediatePropagation()
}
});
$(".easy-autocomplete-container").each(function() {
$._data(this, 'events')["show"].reverse()
})
Here's a working demo in CodePen
Originally I wrote standard functions triggered by an on input event handler that I placed in the HTML. However, it was recommended to me to rather 'listen' for events using jQuery (to make for more readable code).
Question:
What is the difference in terms of processing between the two? (as in how is the code of each style interacting with the DOM).
Originally I had something like this:
HTML:
<input type='range' oninput='doStuff()'../>
JS:
function doStuff() {
//Things happen
}
Below is the refactored code:
var makeMusic = {
var1: val,
var2: val,
var3: val,
init: function() {
makeMusic.watchExperience();
},
watchExperience: function() {
$(document).on('input change', '#input_experience', function() {
//do stuff
}
},
anotherFunction: function() {
},
etc
}
var otherScript = {
init: function() {
},
etc
}
var Main = {
run: function() {
makeMusic.init();
otherScript.init();
}
}
$(document).ready(Main.run);
I think you are talking about custom event dispatchers and redirecting it to a standard event
Based on your example the orginal event given by the browser DOM which is onchange if you want to do a proxy for it then you definitely catch that event and trigger your oninput
Refer https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
You can capture all the events at document level or a wilcard ***** selector level and re-trigger oninput with a custom code
if you use JQuery it will also help
The difference is: you can handle the native hardware events in a more sophisticated manner. This allows you create your own framework which give more proper event names.
I have the following listener in the view for when a model is changed:
this.listenTo(this.model, 'change', this.render);
When I change the model :
model.set('foo', bar);
Is it possible to make it not trigger the listener event for this specific function call? I still want the event to trigger at other calls.
From the fine manual:
Generally speaking, when calling a function that emits an event (model.set, collection.add, and so on...), if you'd like to prevent the event from being triggered, you may pass {silent: true} as an option. Note that this is rarely, perhaps even never, a good idea. Passing through a specific flag in the options for your event callback to look at, and choose to ignore, will usually work out better.
So if you don't want that specific set call to trigger a change event then:
model.set('foo', bar, { silent: true });
Or tunnel some information to render using a custom option:
model.set('foot', bar, { ignore_this: true });
and adjust render:
render: function(options) {
if(options && options.ignore_this)
return;
// ...
}
In Ember guides:
http://emberjs.com/guides/view_layer/
below the table of built-in events, an example was given of adding custom events:
App = Ember.Application.create({
customEvents: {
// add support for the loadedmetadata media
// player event
'loadedmetadata': "loadedMetadata"
}
});
However, I am still a bit confused as to how exactly to implement a custom event. For example, if I want to map a custom event 'leftArrow' to keycode 37, how would I name it ?
For your kind of event, I wouldn't class it as a 'custom event'. Custom events are types of events that are supported natively by the browser or by jQuery that have not been implemented yet in Ember.
What you want to achieve already exists as a 'key' event and you just need to capture the keycode and respond accordingly. For example:
App.SomeView = Em.View.extend({
keyDown: function (e) {
if (e.keycode === 37) {
// do your stuff or call a function
}
}
});
The application create constructor is not the place to do this, and you will want to handle the key events within your views or controllers depending on what you want to do. Take a look at the section on the EmberJs doc page just above custom events. Those are the events you can handle.
I want to validate a users input by keydown. For this I require a keydown event.
Unfortunatly I only have found custom model events:
initalize: function(){
this.model = new ModelClass();
this.model.bind("keydown", this.validate, this);
}
That approach surely is fine for model events but I don't believe this is the right way for view, ui-related stuff...
To give you a better explication, this is how I would like to use my event:
var SomeView;
SomeView = Backbone.View.extend({
events: {
"keydown input#some-field": "validate" // custom event
, "change input#some-field": "doSomethingElse" // predefined backbone event
},
validate: function(attr){
// validation
}
});
So what is the approach to create custom Backbone Events which are callable in the View?
what is the approach to create custom Backbone Events which are callable in the View?
I feel as if your problem is not a problem,because backbone.view default has been to support the events.
you can write code like what you want to:
//This is the right thing to do
SomeView = Backbone.View.extend({
events: {
"keydown input#some-field": "validate" // custom event
, "change input#some-field": "doSomethingElse" // predefined backbone event
},
validate: function(attr){
// validation
}
});
Reference here:
http://backbonejs.org/docs/todos.html#section-22
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDIT :
you can see here:
http://backbonejs.org/docs/backbone.html#section-156
The most critical sentence is:
this.$el.delegate(selector, eventName, method);
because backbone's events is jquery's delegate(http://api.jquery.com/delegate/),so jQuery's delegate to support the event, backbone are available.
I'm not sure I'm understanding what the problem is. Your second example is definitely how I would and have gone about setting up event handlers in Backbone Views. Backbone's validate method only exists in the model and is called automatically before the models set and save are called. It is left undefined as default. If you are validating in the view though your way should work. But i believe event handling functions are only passed the event. so it should probably be
validate: function (event) {
// do Something here
}
also you should keep in mind that backbone event delegation takes place in the el. so you will need to either set it manually or render into it in order for event delegation to to work