I struggle to understand the automatic focus handling in SAPUI5 and how to change its default behavior:
Let's say I have a ResponsivePopover with a SearchField in it. When I open the popover, the SearchField gets focused automatically.
However when there is an <endButton> aggregation with a Button in it, it gets the focus instead.
Try it out here: JSbin: Focus in ResponsivePopover
function showPopover(oEvent) {
var oRespPopover = new ResponsivePopover({
showHeader: true,
title: "title",
content: [
new SearchField(),
// ...
],
/*
endButton: new sap.m.Button({
text: 'close',
press: function(oEvent) {
oRespPopover.close();
}
}),
*/
afterClose: function(oEvent) {
oEvent.getSource().destroy();
}
});
oRespPopover.openBy(oBtn);
};
General question
Where is defined which Control gets the focus and how can I change this behavior?
I checked the Implementing Focus Handling documentation on this topic, but did not manage to achieve anything.
My specific case
How can I prevent that the SearchField gets the focus (because that triggers the keyboard on mobile devices), without having an EndButton aggregation?
If the target focus control has a stable ID, you can assign that ID to the initialFocus association of the sap.m.ResponsivePopover, sap.m.Dialog, or sap.m.Popover so that the target control gets focused even if there are buttons in the end/beginButton aggregation.
Focus on the popover is set in the sequence of beginButton and endButton, when available. But if a control other than these two buttons needs to get the focus, set the initialFocus with the control which should be focused on. src
In XML:
<ResponsivePopover initialFocus="myFocusableControl"><!--Same for Dialog, Popover, ...-->
<content>
<SomeFocusableControl id="myFocusableControl" />
</content>
</ResponsivePopover>
Or in JS (Controller):
new ResponsivePopover({ // Same for Dialog, Popover, ...
initialFocus: this.getView().createId("myFocusableControl"),
content: [
new SomeFocusableControl({
id: this.getView().createId("myFocusableControl"),
}),
],
// ...
});
Note: For mobile devices, initial focus does not trigger opening the on-screen keyboard.
Setting initialFocus to input controls doesn't open the On-Screen keyboard on mobile device as, due to browser limitation, the On-Screen keyboard can't be opened with JavaScript code. The opening of On-Screen keyboard must be triggered by real user action. src
Related
In React-Boostrap-Typeahead, I need to capture the moment after the mouse has been clicked, but before the menu selection gets loaded into the Typeahead's box.
This is because I need to check items being selected, and for some of them, I need to display an alert with a Yes/No warning. Only if Yes is clicked can I proceed with setting that value into the box. Otherwise I need to reject the selection and keep it whatever it was prior to the mouse click.
I can't use onChange because by that point the selection is already in the box.
I can't use onInputChange because that is for typing rather than for menu selection. I need the post-menu-select, pre-box change.
If there are any workarounds please let me know.
You should be able to achieve what you're after using onChange:
const ref = useRef();
const [selected, setSelected] = useState([]);
return (
<Typeahead
id="example"
onChange={(selections) => {
if (!selections.length || window.confirm('Are you sure?')) {
return setSelected(selections);
}
ref.current.clear();
}}
options={options}
ref={ref}
selected={selected}
/>
);
Working example: https://codesandbox.io/s/objective-colden-w7ko9
I'm currently developing a sapui5 mobile application and am using an sap.m.Input with suggestions bound by a model like this:
new Page('page', {
showNavButton: true,
content: [
new sap.m.Input({
id: "input",
type: 'Text',
showSuggestion: true,
suggestionItemSelected: function(event) {
event.getParameters().selectedItem.mProperties.text;
},
liveChange: function() {
// some stuff
}
})
]
});
The Model is created and bound like the following:
var model = new sap.ui.model.json.JSONModel();
// model is filled
sap.ui.getCore().byId('input').setModel(model);
sap.ui.getCore().byId('input').bindAggregation('suggestionItems', '/', new sap.ui.core.Item({
text: "{someField}"
}));
When I now click into the input field on a mobile device, kind of a new screen opens with a new input field, which the user has to manually focus again, what seems like a usability flaw to me.
Is there a nice possibility to enable auto focusing the input field on this new screen, so that the user doesn't has to do it again? Or can this screen be disabled at all on mobile devices?
sap.m.input doesn't seem to have a own method for focusing, or at least I'm not finding one - I already tried using jquery's .focus() on the new input field, but without success.
edit: for clarification, the suggestion works troublefree - only the absence of the auto focus on the appearing new screen is what bothers me.
Here is a workaround to "fix" this behavior: https://jsbin.com/lukozaq
Note 1: The above snippet relies on internal implementation of how the popup works. Use it with caution as there are currently no public APIs to access the corresponding internal controls.
Note 2: I put the word fix in quotes because it seems to be the intended behavior that the user has to click on the second input field explicitly, according to the comment in the source code:
Setting focus to DOM Element, which can open the on screen keyboard on mobile device, doesn't work consistently across devices. Therefore, setting focus to those elements are disabled on mobile devices and the keyboard should be opened by the user explicitly.
That comment is from the module sap.m.Dialog. On a mobile device, when the user clicks on the source input field, a stretched Dialog opens up as a "popup" which has the second input field in its sub header.
Please check the API documentation of sap.m.Input, it has a method focus. You can call:
this.byId("input").focus()
to set the focus into the input field.
Try this:
jQuery.sap.delayedCall(0, this, function() {
this.byId("input").focus()
});
About how to detect when the user presses the input field: maybe something like this? Only problem is that I think you probably don't know the id of the new input field which is shown.
var domId = this.byId("input").getId();
$( "#"+domId ).click(function() {
jQuery.sap.delayedCall(0, this, function() {
this.byId("input").focus()
});
});
I am pretty sure that the first piece of code is how to put focus on an input. I'm not sure about the second part, but it's something to try.
in onAfterRendering() do the below..
onAfterRendering : function() {
$('document').ready(function(){
sap.ui.getCore().byId('input').focus();
});
}
I didnĀ“t have the exactly same problem, but It was similiar.
My problem was that I needed focus into suggestion input when the view had been rendered. My solution was to put following code into "hanldeRouteMatched" function:
var myInput = this.byId("inputName");
var viewName = this.getView().getId();
var selector1 = viewName + "--inputName-inner";
var selector2 = viewName + "--inputName-popup-input-inner";
jQuery.sap.delayedCall(1000, this, function() {
myInput.focus();
if($("#" + selector1)){
$("#" + selector1).click();
jQuery.sap.delayedCall(500, this, function() {
if($("#" + selector2)){
$("#" + selector2).focus();
}
});
}
});
If you see that suggestion input catch focus, but It lose it after, or It never catched it, try increasing the time in delayedCalls. The needed time depends on your connection speed.
I want to introduce a new Control to TinyMce that I can use in the toolbar. In my case I want to add an icon control that can be placed at the start of the toolbar to differentiate between editors.
However there is almost no information about how to properly do this.
Finally I managed to come up with a way to properly do this.
First I introduce a new plugin icon (in icon/plugin.js) that registers a new control Icon. It uses a setting iconClass.
tinymce.PluginManager.add('icon', function() {
tinymce.ui.Icon = tinymce.ui.Widget.extend({
renderHtml: function () {
return '<span class="icon icon-' + this.settings.iconClass + '"> </span>';
}
});
});
Next I add a button facebook to the toolbar in the following way:
editor.addButton('facebook', {
type: 'icon',
iconClass: 'facebook-share'
});
Now I can add it to the toolbar specification:
tinymce.init({
toolbar: "facebook"
})
That's it! The new custom control should not render. The plugin code is only ran once; even if used multiple times.
I am migrating the AUI popup dialog window from liferay 6.1 to liferay 6.2. I see that there are some specific changes to be made. I had some problems with display of buttons but it is resolved now. But the problem is with the close icon (x) which should be on the top right corner. It disappeared suddenly as soon as I added a save button.
Here is my code:
myPopup = AUI().use('aui-base','liferay-util-window','aui-io-deprecated', 'event', 'event-custom', function(A) {
var buttons =[{
cssClass: 'button_close',
label: 'Save',
render:true,
id: 'myPopupButton',
on: {
click: function() {
myPopupSubmit();
}}
}];
myPopup = Liferay.Util.Window.getWindow(
{
dialog: {
title : a + ' mytitle',
centered : true,
height : 600,
width : 500,
draggable : true,
resizable : true,
modal : true,
toolbars: {
footer:buttons
},
}}).plug(A.Plugin.IO, {
uri : url
}).render();
myPopup.show();
});
}
Please let me know if you have any idea on it..
on myPopupSubmit I have also written code to close the popup as:
top.document.getElementById('closethick').click();
Since there is no closethick button it returns null.
Using the modal dialog example as a comparison, the X close button is removed when using the toolbars property.
Reviewing the source code for the toolbars property (line 309 at time of writing this) indicates that if you use this property directly, you'll need to include your own X close in the header.
An alternative would be to use the addToolbar function (as seen in the example) to include your buttons while preserving the default toolbars.
modal.addToolbar([{
cssClass: 'button_close',
label: 'Save',
render:true,
id: 'myPopupButton',
on: {
click: function() {
myPopupSubmit();
}
}
}]);
I would also consider making the instance of the dialog available to your myPopupSubmit function so that you would have direct access to perform dialog.hide() or calling dialog.hide() after myPopupSubmit versus using the X close approach.
If sticking with the current approach, the id being used will not work, you'll need to use a CSS selector as the YUI based id will change.
In my current usecase, I am trying to use angular-ui modal window to show the progress of calculations that we do in a background process which we disable on completion.
All works well. I just want to disable user from clicking any of element in background.
Any idea how can we do this?
You can pass the following options, when opening a modal window, to prevent users from closing the window:
backdrop: 'static' - top prevent users from closing a modal on backdrop click
keyboard: false - so users can't close a window by pressing ESC
Full documentation here: http://angular-ui.github.io/bootstrap/#/modal
I just want to add an example with code and extend pkozlowski.opensource answer,
Check this example:
var modalInstance = $modal.open({
templateUrl: '/views/registration/loginModal.html',
controller: LoginModalInstanceCtrl,
windowClass: 'login-modal-window',
resolve : {
credentials : function(){ return {email :'', password:''}; }
},
backdrop: 'static', /* this prevent user interaction with the background */
keyboard: false
});
modalInstance.result.then(function (res) {
}, function () {
/* cancel */
$state.go('home');
});