can't tap on item in google autocomplete list on mobile - autocomplete

I'm making a mobile-app using Phonegap and HTML. Now I'm using the google maps/places autocomplete feature. The problem is: if I run it in my browser on my computer everything works fine and I choose a suggestion to use out of the autocomplete list - if I deploy it on my mobile I still get suggestions but I'm not able to tap one. It seems the "suggestion-overlay" is just ignored and I can tap on the page. Is there a possibility to put focus on the list of suggestions or something that way ?
Hope someone can help me. Thanks in advance.

There is indeed a conflict with FastClick and PAC. I found that I needed to add the needsclick class to both the pac-item and all its children.
$(document).on({
'DOMNodeInserted': function() {
$('.pac-item, .pac-item span', this).addClass('needsclick');
}
}, '.pac-container');

There is currently a pull request on github, but this hasn't been merged yet.
However, you can simply use this patched version of fastclick.
The patch adds the excludeNode option which let's you exclude DOM nodes handled by fastclick via regex. This is how I used it to make google autocomplete work with fastclick:
FastClick.attach(document.body, {
excludeNode: '^pac-'
});

This reply may be too late. But might be helpful for others.
I had the same issue and after debugging for hours, I found out this issue was because of adding "FastClick" library. After removing this, it worked as usual.
So for having fastClick and google suggestions, I have added this code in geo autocomplete
jQuery.fn.addGeoComplete = function(e){
var input = this;
$(input).attr("autocomplete" , "off");
var id = input.attr("id");
$(input).on("keypress", function(e){
var input = this;
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(37.2555, -121.9245),
new google.maps.LatLng(37.2555, -121.9245));
var options = {
bounds: defaultBounds,
mapkey: "xxx"
};
//Fix for fastclick issue
var g_autocomplete = $("body > .pac-container").filter(":visible");
g_autocomplete.bind('DOMNodeInserted DOMNodeRemoved', function(event) {
$(".pac-item", this).addClass("needsclick");
});
//End of fix
autocomplete = new google.maps.places.Autocomplete(document.getElementById(id), options);
google.maps.event.addListener(autocomplete, 'place_changed', function() {
//Handle place selection
});
});
}

if you are using Framework 7, it has a custom implementation of FastClicks. Instead of the needsclick class, F7 has no-fastclick. The function below is how it is implemented in F7:
function targetNeedsFastClick(el) {
var $el = $(el);
if (el.nodeName.toLowerCase() === 'input' && el.type === 'file') return false;
if ($el.hasClass('no-fastclick') || $el.parents('.no-fastclick').length > 0) return false;
return true;
}
So as suggested in other comments, you will only have to add the .no-fastclick class to .pac-item and in all its children

I was having the same problem,
I realized what the problem was that probably the focusout event of pac-container happens before the tap event of the pac-item (only in phonegap built-in browser).
The only way I could solve this, is to add padding-bottom to the input when it is focused and change the top attribute of the pac-container, so that the pac-container resides within the borders of the input.
Therefore when user clicks on item in list the focusout event is not fired.
It's dirty, but it works

worked perfectly for me :
$(document).on({
'DOMNodeInserted': function() {
$('.pac-item, .pac-item span', this).addClass('needsclick');
}
}, '.pac-container');
Configuration: Cordova / iOS iphone 5

Related

Transition from Launchpad to application sets focus on SearchField

we have the problem that a transition from the SAP Fiori Launchpad into our application sets the focus on the SearchField of the Master view.
It's a problem, because on mobile devices it triggers the activation of the keyboard which blocks the list view entries.
Any idea how to prevent that behaviour?
Directly entering the application is not creating this problem.
It's also happening in another Master/Detail application we created.
Across Android and iOS devices, replicated on Safari, Chrome, and Firefox.
Kind regards,
Michael
A bit late to the party but we had the same problem. Using onAfterRendering does work only once because that lifecycle hook gets only called once. To solve the issue do the following:
onInit: function () {
// onAfterShow hook gets called every time the view is shown
this.getView().addEventDelegate({onAfterShow: this._afterShow}, this);
},
_afterShow: function () {
jQuery.sap.delayedCall(0, this, function () {
jQuery('input').blur();
});
}
Hope that helps.
This is a workaround (the easiest solution I could Find as of now)
since I couldn't reproduce your issue :(
onDataLoaded() or in onAfterRedering() methods
//basically set the focus on something like this.. OR just create any SAPUI5 element and setVisible(false) and set the focus()
this.getList().focus();
UPDATE: Catch hold of search in getHeaderFooterOptions()
getHeaderFooterOptions: function () {
var _this = this;
var objHdrFtr = {
//sI18NMasterTitle: "YOUR_TITLE",
onRefresh: function (searchField, fnRefreshCompleted) {
_this._searchField = searchField;
}
};
return objHdrFtr;
}
then
onAfterRendering(){
if(this._searchField){
this._searchField.onAfterRendering = function() {
jQuery(this.getDomRef()).focusout()
};
}
}
Let me know if this works or not!
I will delete the answer.

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.

Ionic scrollTop "Cannot read property 'scrollTo' of null" (still exists in 1.0.0-rc.1)

This bug was referred to here: in ionic changing route causes "TypeError: Cannot read property 'scrollTo' of null"
The answer says that this bug was fixed in beta-13, but I'm using 1.0.0-rc.1 and the bug still appears.
In my case, it the error is showing when navigating back to a page that uses $ionicScrollDelegate.scrollTop()
Is anyone else getting this error after updating to rc.1?
EDIT:
I find that if I do not call $ionicScrollDelegate.scrollTop() automatically when my view loads, the error does not come up. Should I be calling scrollTop() within a specific Ionic event that waits for the right time?
Had the same problem, even with v1.0.0 "uranium-unicorn".
Wrapping the scroll call into a $timeout helped - this is what it looks like in my code:
$timeout(function() {
$ionicScrollDelegate.scrollTo(scrollPosition.left, scrollPosition.top);
}, 0);
You can just put it in
$ionicPlatform.ready(function () {
$ionicScrollDelegate.scrollTop();
})
Im late to this but was getting the same error but by calling the scroll top element with:
$ionicScrollDelegate.scrollTop();
but rather:
var scrollTop = e.detail.scrollTop;
and fixed my by using the following:
var scrollTop = $ionicScrollDelegate.getScrollPosition().top;
Im also using js scrolling as it seems to work better with the scrolla-sista plugin so I have the following in my config block at the start of my app
$ionicConfigProvider.scrolling.jsScrolling(true);
where their docs state:
Whether to use JS or Native scrolling. Defaults to native scrolling. Setting this to true has the same effect as setting each ion-content to have overflow-scroll='false'.
I hope this helps someone
For what it's worth, I saw this solution on this thread here and it worked for me with version 1.0.0-beta.14
If upgrading to version 1.0.0-beta.14 is not an option, you can change the ionic-bundle.js file with the following:
Approximately Line 39910:
this.scrollTop = function(shouldAnimate) {
this.resize().then(function() {
if(typeof scrollView !== 'undefined' && scrollView !== null){
scrollView.scrollTo(0, 0, !!shouldAnimate);
}
});
};
And Approximately line 39813:
if (!angular.isDefined(scrollViewOptions.bouncing)) {
ionic.Platform.ready(function() {
if(!scrollView){
return;
}
scrollView.options.bouncing = true;
if(ionic.Platform.isAndroid()) {
// No bouncing by default on Android
scrollView.options.bouncing = false;
// Faster scroll decel
scrollView.options.deceleration = 0.95;
}
});
}
Please change
e.detail.scrollTop
to
e.target.scrollTop
then this will Work

Twitter Bootstrap Modal Form: How to drag and drop?

I would like to be able to move around (on the greyed-out background, by dragging and dropping) the modal form that is provided by Bootstrap 2. Can anyone tell me what the best practice for achieving this is?
The bootstrap doesn't come with any dragging and dropping functionality by default, but you can add a little jQuery UI spice into the mix to get the effect you're looking for. For example, using the draggable interaction from the framework you can target your modal ID to allow it to be dragged around within the modal backdrop.
Try this:
JS
$("#myModal").draggable({
handle: ".modal-header"
});
Demo, edit here.
Update: bootstrap3 demo
Whatever draggable option you go for, you might want to turn off the *-transition properties for .modal.fade in bootstrap’s CSS file, or at least write some JS that temporarily disables them during dragging. Otherwise, the modal doesn’t drag exactly as you would expect.
You can use a little script likes this.
simplified from Draggable without jQuery UI
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
var $selected = this;
var $elements = (opt.handle === "") ? this : this.find(opt.handle);
$elements.css('cursor', opt.cursor).on("mousedown", function (e) {
var pos_y = $selected.offset().top - e.pageY,
pos_x = $selected.offset().left - e.pageX;
$(document).on("mousemove", function (e) {
$selected.offset({
top: e.pageY + pos_y,
left: e.pageX + pos_x
});
}).on("mouseup", function () {
$(this).off("mousemove"); // Unbind events from document
});
e.preventDefault(); // disable selection
});
return this;
};
})(jQuery);
example : $("#someDlg").modal().drags({handle:".modal-header"});
Building on previous answers utilizing jQuery UI, this, included once, will apply to all your modals and keep the modal on screen, so users don't accidentally move the header off screen so they can no longer access the handle. Also sets the cursor to 'move' for better discoverability.
$(document).on('shown.bs.modal', function(evt) {
let $modal = $(evt.target);
$modal.find('.modal-content').draggable({
handle: ".modal-header",
containment: $modal
});
$modal.find('.modal-header').css('cursor', 'move')
});
evt.target is the .modal which is the translucent overlay behind the actual .modal-content.
jquery UI is large and can conflict with bootstrap.
An alternative is DragDrop.js: http://kbjr.github.io/DragDrop/index.html
DragDrop.bind($('#myModal')[0], {
anchor: $('#myModal .modal-header')
});
You still have to deal with transitions, as #user535673 suggests. I just remove the fade class from my dialog.

Mobile Safari: Disable scrolling pages "out of screen"

I want to block scrolling page "out of the iPhone screen" (when gray Safari's background behind the page border is visible). To do this, I'm cancelling touchmove event:
// Disables scrolling the page out of the screen.
function DisableTouchScrolling()
{
document.addEventListener("touchmove", function TouchHandler(e) { e.preventDefault(); }, true);
}
Unfortunately, this also disables mousemove event: when I tap on a button then move my finger out of it, then release the screen, the button's onclick event is triggered anyway.
I've tried mapping touch events on mouse events, as desribed here: http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/, but to no avail (the same behavior).
Any ideas?
From what I understand of your question, you've attempted to combine the code you've presented above with the code snippet provided by Ross Boucher on Posterous. Attempting to combine these two snippets back-to-back won't work, because in disabling touchmove, you've also disabled the shim that allows mousemove to work via his sample.
This question and its answers sketch out a workable solution to your problem. You should try these two snippets to see if they resolve your issue:
This snippet, which disables the old scrolling behavior:
elementYouWantToScroll.ontouchmove = function(e) {
e.stopPropagation();
};
Or this one, from the same:
document.ontouchmove = function(e) {
var target = e.currentTarget;
while(target) {
if(checkIfElementShouldScroll(target))
return;
target = target.parentNode;
}
e.preventDefault();
};
Then, drop in the code on Posterous:
function touchHandler(event)
{
var touches = event.changedTouches,
first = touches[0],
type = "";
switch(event.type)
{
case "touchstart": type = "mousedown"; break;
case "touchmove": type="mousemove"; break;
case "touchend": type="mouseup"; break;
default: return;
}
//initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}
And that should do it for you. If it doesn't, something else isn't working with Mobile Safari.
Unfortunately I haven't had the time to check out to above yet but was working on an identical problem and found that the nesting of elements in the DOM and which relation you apply it to affects the handler a lot (guess the above solves that, too - 'var target = e.currentTarget').
I used a slightly different approach (I'd love feedback on) by basically using a class "locked" that I assign to every element which (including all its children) i don't want the site to scroll when someone touchmoves on it.
E.g. in HTML:
<header class="locked">...</header>
<div id="content">...</div>
<footer class="locked"></div>
Then I have an event-listener running on that class (excuse my lazy jquery-selector):
$('.ubq_locked').on('touchmove', function(e) {
e.preventDefault();
});
This works pretty well for me on iOs and Android and at least gives me the control to not attach the listener to an element which I know causes problems. You do need to watch your z-index values by the way.
Plus I only attach the listener if it is a touch-device, e.g. like this:
function has_touch() {
var isTouchPad = (/hp-tablet/gi).test(navigator.appVersion);
return 'ontouchstart' in window && !isTouchPad;
}
This way non-touch devices will not be affected.
If you don't want to spam your HTML you could of course just write the selectors into an array and run through those ontouchmove, but I would expect that to be more costly in terms of performance (my knowledge there is limited though). Hope this can help.