NGX-Bootstrap Datepicker when i open it on my ipad its not selecting the date on first click - datepicker

I am using NGX-Bootstrap DatePicker
When i open it in tab or mobile (all the devices other than desktop and laptop).I need to tap on the Date two times to select. How to resolve this problem
For Demo please open (https://valor-software.com/ngx-bootstrap/#/datepicker) in TAB or MOBILE

I was facing the same problem yesterday. This is a Apple devices issue and happens because it device detect the user's first touch like a hover, instead of a click.
To solve this, im using a event inside the input that im calling the ngx-bootstrap datepicker to execute a method when calendar is shown , like:
<input type="text" bsDaterangepicker (onShown)="onShowPicker($event)">
and inside the method onShownPicker, my algorithm is detecting if the user is inside an apple device and then, it use a ngxbootstrap-datepicker method to instance dayHandler (that is called when click is normally detected, instead of hover):
onShowPicker(event) {
const dayHoverHandler = event.dayHoverHandler;
const hoverWrapper = (hoverEvent) => {
const { cell, isHovered } = hoverEvent;
if ((isHovered &&
!!navigator.platform &&
/iPad|iPhone|iPod|Apple/.test(navigator.platform)) &&
'ontouchstart' in window
) {
(this.datapickerDirective as any)._datepickerRef.instance.daySelectHandler(cell);
}
return dayHoverHandler(hoverEvent);
};
event.dayHoverHandler = hoverWrapper;
}
To work properly, you need to have the datepicker directive as viewChild because its used on this method above. in my case, im using like:
#ViewChild(BsDaterangepickerDirective, {static: false}) datapickerDirective;

Related

TinyMCE - open code view inside editor - range error

like I mentions in the topic I want to open code view inside my editor, not on separate modal window. I found similar topic and use some of the code from it:
TinyMCE Code Plugin - don't want to open code view in a modal dialog
I managed to do something like this:
const tinyDomUtils = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
const editorBody = editor.getBody();
const toggleCodeView = (isCodeView: string) => {
editorContent = editor.getContent({ source_view: !0 });
editorBody.setAttribute(codeViewAttribute, isCodeView);
if (editorBody.getAttribute(codeViewAttribute) === 'true') {
editor.setContent(tinyDomUtils.DOM.encode(editorContent));
editorBody.blur();
} else {
editor.setContent(tinyDomUtils.DOM.decode(editorContent));
}
};
And it works pretty good, I am able to switch between modes. The problem I have is that currently when I am on the code view, the user can hit "save" and then the content is display with all the html markup. I am trying to fix it just by some event listener to "Save" button and when user click it I am running my function again
toggleCodeView("false");
but then I get console error:
react-dom.development.js:22738 Uncaught TypeError: Cannot read properties of undefined (reading 'createRange')
at c.getRng (tinymce.min.js?5.0.0:6:15446)
at c.getNode (tinymce.min.js?5.0.0:6:16732)
at a.getBookmark (tinymce.min.js?5.0.0:6:8198)
at c.getBookmark (tinymce.min.js?5.0.0:6:13908)
at Object.add (tinymce.min.js?5.0.0:7:12595)
at A.i (tinymce.min.js?5.0.0:7:10860)
at t.i [as fire] (tinymce.min.js?5.0.0:8:4752)
at A.fire (tinymce.min.js?5.0.0:8:6637)
at A.save (tinymce.min.js?5.0.0:11:11915)
at A.remove (tinymce.min.js?5.0.0:11:15152)
I can't find any solution for this. Can anyone help?

React-Bootstrap-Typeahead: Capture moment before setting selection into box (to allow conditional rejection)

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

How to keep focus within modal dialog?

I'm developing an app with Angular and Semantic-UI. The app should be accessible, this means it should be compliant with WCAG 2.0.
To reach this purpose the modals should keep focus within the dialog and prevents users from going outside or move with "tabs" between elements of the page that lays under the modal.
I have found some working examples, like the following:
JQuery dialog: https://jqueryui.com/dialog/#modal-confirmation
dialog HTML 5.1 element: https://demo.agektmr.com/dialog
ARIA modal dialog example:
http://w3c.github.io/aria-practices/examples/dialog-modal/dialog.html
(that I have reproduced on Plunker)
Here is my try to create an accessible modal with Semantic-UI: https://plnkr.co/edit/HjhkZg
As you can see I used the following attributes:
role="dialog"
aria-labelledby="modal-title"
aria-modal="true"
But they don't solve my issue. Do you know any way to make my modal keeping focus and lose it only when user click on cancel/confirm buttons?
There is currently no easy way to achieve this. The inert attribute was proposed to try to solve this problem by making any element with the attribute and all of it's children inaccessible. However, adoption has been slow and only recently did it land in Chrome Canary behind a flag.
Another proposed solution is making a native API that would keep track of the modal stack, essentially making everything not currently the top of the stack inert. I'm not sure the status of the proposal, but it doesn't look like it will be implemented any time soon.
So where does that leave us?
Unfortunately without a good solution. One solution that is popular is to create a query selector of all known focusable elements and then trap focus to the modal by adding a keydown event to the last and first elements in the modal. However, with the rise of web components and shadow DOM, this solution can no longer find all focusable elements.
If you always control all the elements within the dialog (and you're not creating a generic dialog library), then probably the easiest way to go is to add an event listener for keydown on the first and last focusable elements, check if tab or shift tab was used, and then focus the first or last element to trap focus.
If you're creating a generic dialog library, the only thing I have found that works reasonably well is to either use the inert polyfill or make everything outside of the modal have a tabindex=-1.
var nonModalNodes;
function openDialog() {
var modalNodes = Array.from( document.querySelectorAll('dialog *') );
// by only finding elements that do not have tabindex="-1" we ensure we don't
// corrupt the previous state of the element if a modal was already open
nonModalNodes = document.querySelectorAll('body *:not(dialog):not([tabindex="-1"])');
for (var i = 0; i < nonModalNodes.length; i++) {
var node = nonModalNodes[i];
if (!modalNodes.includes(node)) {
// save the previous tabindex state so we can restore it on close
node._prevTabindex = node.getAttribute('tabindex');
node.setAttribute('tabindex', -1);
// tabindex=-1 does not prevent the mouse from focusing the node (which
// would show a focus outline around the element). prevent this by disabling
// outline styles while the modal is open
// #see https://www.sitepoint.com/when-do-elements-take-the-focus/
node.style.outline = 'none';
}
}
}
function closeDialog() {
// close the modal and restore tabindex
if (this.type === 'modal') {
document.body.style.overflow = null;
// restore or remove tabindex from nodes
for (var i = 0; i < nonModalNodes.length; i++) {
var node = nonModalNodes[i];
if (node._prevTabindex) {
node.setAttribute('tabindex', node._prevTabindex);
node._prevTabindex = null;
}
else {
node.removeAttribute('tabindex');
}
node.style.outline = null;
}
}
}
The different "working examples" do not work as expected with a screenreader.
They do not trap the screenreader visual focus inside the modal.
For this to work, you have to :
Set the aria-hidden attribute on any other nodes
disable keyboard focusable elements inside those trees (links using tabindex=-1, controls using disabled, ...)
The jQuery :focusable pseudo selector can be useful to find focusable elements.
add a transparent layer over the page to disable mouse selection.
or you can use the css pointer-events: none property when the browser handles it with non SVG elements, not in IE
This focus-trap plugin is excellent at making sure that focus stays trapped inside of dialogue elements.
It sounds like your problem can be broken down into 2 categories:
focus on dialog box
Add a tabindex of -1 to the main container which is the DOM element that has role="dialog". Set the focus to the container.
wrapping the tab key
I found no other way of doing this except by getting the tabbable elements within the dialog box and listening it on keydown. When I know the element in focus (document.activeElement) is the last one on the list, I make it wrap
"focus" events can be intercepted in the capture phase, so you can listen for them at the document.body level, squelch them before they reach the target element, and redirect focus back to a control in your modal dialog. This example assumes a modal dialog with an input element gets displayed and assigned to the variable currDialog:
document.body.addEventListener("focus", (event) => {
if (currDialog && !currDialog.contains(event.target)) {
event.preventDefault();
event.stopPropagation();
currDialog.querySelector("input").focus();
}
}, {capture: true});
You may also want to contain such a dialog in a fixed-position, clear (or low-opacity) backdrop element that takes up the full screen in order to capture and suppress mouse/pointer events, so that no browser feedback (hover, etc.) occurs that could give the user the impression that the background is active.
Don't use any solution requiring you to look up "tabbable" elements. Instead, use keydown and either click events or a backdrop in an effective manor.
(Angular1)
See Asheesh Kumar's answer at https://stackoverflow.com/a/31292097/1754995 for something similar to what I am going for below.
(Angular2-x, I haven't done Angular1 in a while)
Say you have 3 components: BackdropComponent, ModalComponent (has an input), and AppComponent (has an input, the BackdropComponent, and the ModalComponent). You display BackdropComponent and ModalComponent with the correct z-index, both are currently displayed/visible.
What you need to do is have a general window.keydown event with preventDefault() to stop all tabbing when the backdrop/modal component is displayed. I recommend you put that on a BackdropComponent. Then you need a keydown.tab event with stopPropagation() to handle tabbing for the ModalComponent. Both the window.keydown and keydown.tab could probably be in the ModalComponent but there is purpose in a BackdropComponent further than just modals.
This should prevent clicking and tabbing to the AppComponent input and only click or tab to the ModalComponent input [and browser stuffs] when the modal is shown.
If you don't want to use a backdrop to prevent clicking, you can use use click events similarly to the keydown events described above.
Backdrop Component:
#Component({
selector: 'my-backdrop',
host: {
'tabindex': '-1',
'(window:keydown)': 'preventTabbing($event)'
},
...
})
export class BackdropComponent {
...
private preventTabbing(event: KeyboardEvent) {
if (event.keyCode === 9) { // && backdrop shown?
event.preventDefault();
}
}
...
}
Modal Component:
#Component({
selector: 'my-modal',
host: {
'tabindex': '-1',
'(keydown.tab)': 'onTab($event)'
},
...
})
export class ModalComponent {
...
private onTab(event: KeyboardEvent) {
event.stopPropagation();
}
...
}
Here's my solution. It traps Tab or Shift+Tab as necessary on first/last element of modal dialog (in my case found with role="dialog"). Eligible elements being checked are all visible input controls whose HTML may be input,select,textarea,button.
$(document).on('keydown', function(e) {
var target = e.target;
var shiftPressed = e.shiftKey;
// If TAB key pressed
if (e.keyCode == 9) {
// If inside a Modal dialog (determined by attribute role="dialog")
if ($(target).parents('[role=dialog]').length) {
// Find first or last input element in the dialog parent (depending on whether Shift was pressed).
// Input elements must be visible, and can be Input/Select/Button/Textarea.
var borderElem = shiftPressed ?
$(target).closest('[role=dialog]').find('input:visible,select:visible,button:visible,textarea:visible').first()
:
$(target).closest('[role=dialog]').find('input:visible,select:visible,button:visible,textarea:visible').last();
if ($(borderElem).length) {
if ($(target).is($(borderElem))) {
return false;
} else {
return true;
}
}
}
}
return true;
});
we can use the focus trap npm package.
npm i focus-trap
This might help someone who is looking for solution in Angular.
Step 1: Add keydown event on dialog component
#HostListener('document:keydown', ['$event'])
handleTabKeyWInModel(event: any) {
this.sharedService.handleTabKeyWInModel(event, '#modal_id', this.elementRef.nativeElement, 'input,button,select,textarea,a,[tabindex]:not([tabindex="-1"])');
}
This will filters the elements which are preseneted in the Modal dialog.
Step 2: Add common method to handle focus in shared service (or you can add it in your component as well)
handleTabKeyWInModel(e, modelId: string, nativeElement, tagsList: string) {
if (e.keyCode === 9) {
const focusable = nativeElement.querySelector(modelId).querySelectorAll(tagsList);
if (focusable.length) {
const first = focusable[0];
const last = focusable[focusable.length - 1];
const shift = e.shiftKey;
if (shift) {
if (e.target === first) { // shift-tab pressed on first input in dialog
last.focus();
e.preventDefault();
}
} else {
if (e.target === last) { // tab pressed on last input in dialog
first.focus();
e.preventDefault();
}
}
}
}
}
Now this method will take the modal dialog native element and start evaluate on every tab key. Finally we will filter the event on first and last so that we can focus on appropriate elements (on first after last element tab click and on last shift+tab event on first element).
Happy Coding.. :)
I used one of the methods suggested by Steven Lambert, namely, listening to keydown events and intercepting "tab" and "shift+tab" keys. Here's my sample code (Angular 5):
import { Directive, ElementRef, Attribute, HostListener, OnInit } from '#angular/core';
/**
* This directive allows to override default tab order for page controls.
* Particularly useful for working around the modal dialog TAB issue
* (when tab key allows to move focus outside of dialog).
*
* Usage: add "custom-taborder" and "tab-next='next_control'"/"tab-prev='prev_control'" attributes
* to the first and last controls of the dialog.
*
* For example, the first control is <input type="text" name="ctlName">
* and the last one is <button type="submit" name="btnOk">
*
* You should modify the above declarations as follows:
* <input type="text" name="ctlName" custom-taborder tab-prev="btnOk">
* <button type="submit" name="btnOk" custom-taborder tab-next="ctlName">
*/
#Directive({
selector: '[custom-taborder]'
})
export class CustomTabOrderDirective {
private elem: HTMLInputElement;
private nextElemName: string;
private prevElemName: string;
private nextElem: HTMLElement;
private prevElem: HTMLElement;
constructor(
private elemRef: ElementRef
, #Attribute('tab-next') public tabNext: string
, #Attribute('tab-prev') public tabPrev: string
) {
this.elem = this.elemRef.nativeElement;
this.nextElemName = tabNext;
this.prevElemName = tabPrev;
}
ngOnInit() {
if (this.nextElemName) {
var elems = document.getElementsByName(this.nextElemName);
if (elems && elems.length && elems.length > 0)
this.nextElem = elems[0];
}
if (this.prevElemName) {
var elems = document.getElementsByName(this.prevElemName);
if (elems && elems.length && elems.length > 0)
this.prevElem = elems[0];
}
}
#HostListener('keydown', ['$event'])
onKeyDown(event: KeyboardEvent) {
if (event.key !== "Tab")
return;
if (!event.shiftKey && this.nextElem) {
this.nextElem.focus();
event.preventDefault();
}
if (event.shiftKey && this.prevElem) {
this.prevElem.focus();
event.preventDefault();
}
}
}
To use this directive, just import it to your module and add to Declarations section.
I've been successful using Angular Material's A11yModule.
Using your favorite package manager install these to packages into your Angular app.
**"#angular/material": "^10.1.2"**
**"#angular/cdk": "^10.1.2"**
In your Angular module where you import the Angular Material modules add this:
**import {A11yModule} from '#angular/cdk/a11y';**
In your component HTML apply the cdkTrapFocus directive to any parent element, example: div, form, etc.
Run the app, tabbing will now be contained within the decorated parent element.
For jquery users:
Assign role="dialog" to your modal
Find first and last interactive element inside the dialog modal.
Check if current target is one of them(depending on shift key is
pressed or not).
If target element is one of first or last interactive element of the
dialog, return false
Working code sample:
//on keydown inside dialog
$('.modal[role=dialog]').on('keydown', e => {
let target = e.target;
let shiftPressed = e.shiftKey;
// If TAB is pressed
if (e.keyCode === 9) {
// Find first and last element in the ,modal-dialog parent.
// Elements must be interactive i.e. visible, and can be Input/Select/Button/Textarea.
let first = $(target).closest('[role=dialog]').find('input:visible,select:visible,button:visible,textarea:visible').first();
let last = $(target).closest('[role=dialog]').find('input:visible,select:visible,button:visible,textarea:visible').last();
let borderElem = shiftPressed ? first : last //border element on the basis of shift key pressed
if ($(borderElem).length) {
return !$(target).is($(borderElem)); //if target is border element , return false
}
}
return true;
});
I read through most of the answers, while the package focus-trap seems like a good option. #BenVida shared a very simple VanillaJS solution here in another Stack Overflow post.
Here is the code:
const container=document.querySelector("_selector_for_the_container_")
//optional: needed only if the container element is not focusable already
container.setAttribute("tabindex","0")
container.addEventListener("focusout", (ev)=>{
if (!container.contains(ev.relatedTarget)) container.focus()
})

How to enable auto focus on SAPUI5 input suggestion field

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.

jQuery Mobile checkbox takes time to get checked/unchecked on iPhone

I am facing an issue with jQuery Mobile on iPhone.
I have a list of checboxes and a checkbox to select "All".
After an initial few taps on the checkbox, the check box takes few seconds to get marked as checked/unchecked.
The checkbox doesnt get marked unless the user waits for a few seconds or scroll the screen.
This seems to be an issue only with this particular phone as it works fine on desktop browsers and Android devices.
Here is the script:
/* Check-Uncheck */
self.elements.listview.on('change', ':checkbox', function (event) {
var unchecked = $(':checkbox:not(:checked)', self.elements.listview);
self.elements.selectAll
.prop('checked', unchecked.length === 0)
.checkboxradio("refresh");
});
/* Check-Uncheck 'Select All' */
self.elements.selectAll.change(function () {
var checkboxes = $(':checkbox', self.elements.listview);
var checked = self.elements.selectAll.is(':checked');
checkboxes
.prop('checked', checked)
.checkboxradio("refresh");
});
Please let me know if anyone has faced this particular issue, or have any suggestions.
Thanks