I am trying to understand the execution flow of angularjs/phonegap. I have 2 views: one is list view another is detail view. When the app is started the first time, the list view is shown first, user then selects which list item and show detail view which is recorded in localStorage. When the app is started next time, it should show the detail view directly without showing list view first. I use the following code and is working except when the app is started next time, the list view is shown first then quickly detail view is shown.
index.html:
<!-- Libs -->
<script type="text/javascript" src="phonegap.js"></script>
<script src="lib/angular/angular.js"></script>
<script src="lib/underscore-min.js"></script>
<script src="lib/angular/angular-resource.js"></script>
<!-- App -->
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript" src="js/routers.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/services.js"></script>
<script type="text/javascript">
app.initialize();
</script>
index.js:
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
//handle backbutton to exit app when on homepage
document.addEventListener('backbutton', function(e){
if(window.location.hash == '#/users' || window.location.hash == '#' || window.location.hash == ''){
e.preventDefault();
navigator.app.exitApp();
}
else {
navigator.app.backHistory()
}
}, false);
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
onDeviceReady: function() {
//app.startPage(); //listview then detailview
angular.element(document).ready(function() {
//app.startPage(); //listview only
angular.module('userdemo', []);
//app.startPage(); //listview only
angular.bootstrap(document, ['userdemo']);
//app.startPage(); //listview only
});
app.startPage(); //listview then detailview. if remove "route otherwise clause", show blank listview then detail template view, backbutton working
},
// decide which page to start with
startPage: function() {
var userId = window.localStorage.getItem("userId");
if(!userId) window.location.hash = '/users';
else window.location.hash = '/users/' + userId;
}
};
routers.js:
angular.module('userdemo', ['userdemoFilters', 'userdemoServices']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/users',{
templateUrl: 'partials/user-grid.html',
controller: UserGridCtrl
}).
when('/users/:userId', {
templateUrl: 'partials/user-detail.html',
controller: UserDetailCtrl
}).
otherwise({redirectTo: //if removed, it shows black screen. backbutton working
'/users' //normal
//'/users/3' //show detail template only. backbutton not working
/*
function(routeParams, path, search) { //show detail template only. backbutton not working
var userId = window.localStorage.getItem("userId");
if(!userId) return '/users';
else return '/users/' + userId;
}*/
});
}])
.run(function($location) { //listview then detailview. if remove "otherwise" clause, blank screen, backbutton not working
//var userId = window.localStorage.getItem("userId");
//if(!userId) $location.hash('/users');
//else $location.hash('/users/' + userId);
});
UserDetailControl():
function UserDetailCtrl($rootScope, $scope, $routeParams, User) {
//handle the case when the app is started from the last saved userId
if(!$rootScope.users)
$scope.users = User.query(function() {
for (var i=0; i<$scope.users.length; i++) {
var user = $scope.users[i];
if(!user.id) user.id = i;
}
$rootScope.users = $scope.users;
});
else
$scope.users = $rootScope.users;
$scope.user = $rootScope.users[$routeParams.userId];
}
user-detail.html:
<div class="container-fluid">
<div class="row-fluid">
<div>
<b>Hello {{user.name}}</b><br>
</div>
</div>
</div>
I tried other possible alternatives:
remove "route otherwise clause". It shows blank listview then detail template view without scope applied(that is, literally, Hello {{user.name}}).
put app.startPage() in different places. around, inside, before, after document.ready or angular.bootstrap call. If around document.ready, it shows listview then detailview. If inside document.ready, it shows listview only.
write a custom "route otherwise redirectTo" function as shown in commented code. The result shows detail template only without scope applied. Also backbutton not working.
put initialization code inside module.run() as shown in commented code. It shows listview then detailview. If remove "otherwise" clause, blank screen, backbutton not working.
Not change others, just replace "route otherwise redirectTo" from "/users" to "/users/3", it shows detail template view only. backbutton not working.
None of them shows what I want. Can someone expert on Angular/Phonegap explain why these happen to better understand mechanism behind? What is the right solution for showing the detail view only for app's next start?
You may set the angular routs dynamically after loading phonegap and checking the local-storage, and before manually bootstraping angular..
otherwise({redirectTo:SOME_DYNAMIC_VALUE})
Related
On long press gesture the context action menu appears along the selected text.
But not getting hide unless I select an option from the menu.
First to enable context action menu, I used this:
overflow-scroll = "true" in the ion-content.
In the CSS class, I wrote:
-webkit-user-select: auto;
But now I can't hide it. It is locked on my view. Even after touching anywhere in my web view, it is still enabled. To hide context menu I used this:
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout:none;
But still not getting success. This particular issue is in android only. For iOS, it is working fine. Any help would be appreciated.
Ionic version - 2.1.0
Update
Finally I found the answer.
I used the following two methods. First method to select text on long press and second method to remove selection.
/*----------- To get selection--------*/
$scope.getSelectionText = function() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
$scope.selectMode = true;
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
$scope.selectMode = true;
}
return text;
};
/*---------------To remove selection----------*/
$scope.remove = function(){
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
} else if (document.selection) { // IE?
document.selection.empty();
}
};
And add ng-click to your div
<div class="selectable" ng-click="remove()">
<ng-include src="activeTab.url"></ng-include>
</div>
Finally I found the answer.
I used the following two methods. First method to select text on long press and second method to remove selection.
/*----------- To get selection--------*/
$scope.getSelectionText = function() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
$scope.selectMode = true;
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
$scope.selectMode = true;
}
return text;
};
/*---------------To remove selection----------*/
$scope.remove = function(){
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
} else if (document.selection) { // IE?
document.selection.empty();
}
};
And add ng-click to your div
<div class="selectable" ng-click="remove()">
<ng-include src="activeTab.url"></ng-include>
</div>
This is a simple Cordova & jQuery mobile (1.4.5) app...
When I click on an item in a listview I want to dinamically build a listview on another page and navigate there.
The code I have works as desired as long as I don't click items/buttons too quickly. If I navigate between pages back and forth quickly then sooner or later I end up with an empty page, with the wrong text in header.
This happens both in Ripple and in actual Android device. Why? how can I avoid this? I think it is related to clicking items during page transition but I don't know.
HTML:
<div data-role="page" id="home">
Exercises
</div>
<div data-role="page" id="categories">
<div data-role="header" data-position="fixed" data-add-back-btn="true" data-back-btn-text="Go back">
<h1>Categories</h1>
</div>
<ul data-role="listview" id="categoryList"></ul>
</div>
<div data-role="page" id="exercises">
<div data-role="header" data-position="fixed" data-add-back-btn="true" data-back-btn-text="Go back">
<h1 id="category"></h1>
</div>
<ul data-role="listview" id="exerciseList"></ul>
</div>
Javascript:
var lastCategoryID;
$(document).on("pagecontainerbeforechange", function (e, data) {
switch (data.toPage[0].id) {
case "categories":
createCategories();
break;
case "exercises":
createExercises(event.target.id, $(event.target).text());
break;
}
});
function createExercises(categoryID, categoryName) {
//Don't rebuild if is same category of last time.
if (lastCategoryID == categoryID) return; else { lastCategoryID = categoryID; }
//Set header text.
$("#category").text(categoryName);
$("#exerciseList").empty();
switch (categoryID){
case "c0":
$("#exerciseList").append('<li>Warming up</li>');
$("#exerciseList").append('<li>Weight lifting</li>');
break;
case "c1":
$("#exerciseList").append('<li>Warming up</li>');
$("#exerciseList").append('<li>Running</li>');
break;
}
$("#exerciseList").listview("refresh");
}
function createCategories() {
$("#categoryList").empty();
$("#categoryList").append('<li>Arms</li>');
$("#categoryList").append('<li>Legs</li>');
$("#categoryList").listview("refresh");
}
Steps to reproduce (it doesn't always happen):
1- Click on "Arms"
2- Quickly click on back button
3- Quickly click on "Arms" again
Instead of getting this:
you get this:
I was able to solve the problem mainly by changing
$(document).on("pagecontainerbeforechange", function (e, data) {
to
$(document).on('vclick', 'a', function () {
What happens when selected index is updated($('#idSelectControl').prop('selectedIndex', self.lastSelected);). Immediately the radio button is not getting refreshed, I need to close the select drop down when I reopen the control, it's showing the updated radio button checked with the current selected index.
Please find the code below.
HTML
<div id="idSelectCustomControl" data-bind="visible : searchVisibleFlag">
<select id="idSelectControl" class="float-left big-select" data-native-menu="true" data-corners="false" data-icon="search" data-iconpos="left" data-mini="true" data-bind="dataOptions: arrayList, optionsText : 'text', optionsValue : 'id'">
</select>
</div>
JS
// fired when user selects on drop down list
$(#idSelectControl).live("change", function (event) {
var selectedItem = $("#idSelectControl option:selected").val();
console.log("merchant subscription" + self.merchant());
self.lastSelected = $('#idSelectControl').prop('selectedIndex');
$('#idSelectControl').prop('selectedIndex', self.lastSelected);
//$("select").selectmenu("refresh");
var myselect = $("#idSelectControl");
myselect[0].selectedIndex =0;
myselect.selectmenu("refresh",true);
$('select').selectmenu('refresh', true);
$("select").selectmenu("close");
//$("#idSelectControl").val(selectedItem ).selectmenu("refresh");
if (selectedItem ) {
self.item((selectedItem);
}
else {
self.item("");
}
});
I have tried below also:
$("input[type='radio']").prop("checked",true).checkboxradio("refresh");
$('input[value='+$(this).find("HomeStatus").text()+']')
.attr('checked',true).checkboxradio('refresh');
I have designed an app using Phonegap and jQuery Mobile. The fixed footer works properly until I click on a dropdown or text field, which causes the footer to either disappear from view (Android 4.0) or move to the middle of the view (Android 2.2 Galaxy Tab). Any suggestions?
Phonegap Version: Cordova 2.1.0
jQuery Mobile Version: 1.2.0
Here is my code:
<div data-role="footer" class="nav-mobilyzer" data-tap-toggle="false" data-position="fixed">
<div data-role="navbar" class="nav-mobilyzer" data-grid="d">
<h1>footer</h1>
</div>
</div>
I had the problem in some devices the footer displayed and in others it didn't. I found this worked for me:
var initialScreenSize = window.innerHeight;
window.addEventListener("resize", function() {
if(window.innerHeight < initialScreenSize){
$("[data-role=footer]").hide();
}
else{
$("[data-role=footer]").show();
}
});
EDIT:
But what about orientation changes?
var portraitScreenHeight;
var landscapeScreenHeight;
if(window.orientation === 0 || window.orientation === 180){
portraitScreenHeight = $(window).height();
landscapeScreenHeight = $(window).width();
}
else{
portraitScreenHeight = $(window).width();
landscapeScreenHeight = $(window).height();
}
var tolerance = 25;
$(window).bind('resize', function(){
if((window.orientation === 0 || window.orientation === 180) &&
((window.innerHeight + tolerance) < portraitScreenHeight)){
// keyboard visible in portrait
}
else if((window.innerHeight + tolerance) < landscapeScreenHeight){
// keyboard visible in landscape
}
else{
// keyboard NOT visible
}
});
The tolerance accounts for the inexact calculation of landscape height with portrait width and vis-versa.
Okay, this thread is as old as the internet at this point, but the answer above didn't seem to do the job for me.
The best way I found was to bind a method to the jquery .blur() event, and then call fixedtoolbar() methods in a very specific order, i.e.
var that = this;
$(':input').blur(function(){
that.onFocusLoss();
});
......
onFocusLoss : function() {
try {
$("[data-position='fixed']").fixedtoolbar();
$("[data-position='fixed']").fixedtoolbar('destroy');
$("[data-position='fixed']").fixedtoolbar();
console.log('bam');
} catch(e) {
console.log(e);
}
},
The keyboard is opened when we have the focus on an input so:
// hide the footer when input is active
$("input").blur(function() {
$("[data-role=footer]").show();
});
$("input").focus(function() {
$("[data-role=footer]").hide();
});
You can also detect when the keyboard shows and when it hides and show or hide your footer accordingly:
document.addEventListener("showkeyboard", function(){ $("[data-role=footer]").hide();}, false);
document.addEventListener("hidekeyboard", function(){ $("[data-role=footer]").show();}, false);
Try data-hide-during-focus="" and set it to an empty string.
My solution uses another JQUERY attribute on the div footer. Adding data-fullscreen="true" to that div was all I needed. I know that this fix might not have been available until recently, but I am using jqm 1.3.2 and jq 1.9. I thought I would post this solution just in case it helps someone. Good luck. :)
I have a problem in android phonegap mobile website application, I applied scroll bar in my application, it is working good in PC but when i test in android device(mobile phone) scroll bar not enable.
personally I don't like iscroll.. had many problems using it so I discovered another solution... you can try this:
1.) set your DIV overflow to auto (or scroll) and set its height.. e.g.
<div id="wrapper" style="overflow:auto; height: 200px">...content...</div>
(I usually calculate height with javascript based on user's screen size.. I never set just a fixed height for all devices, this is just for the purpose of this "demo")
2.) add this javascript:
<script>
function isTouchDevice(){
try{
document.createEvent("TouchEvent");
return true;
}catch(e){
return false;
}
}
function touchScroll(id){
if(isTouchDevice()){ //if touch events exist...
var el=document.getElementById(id);
var scrollStartPos=0;
document.getElementById(id).addEventListener("touchstart", function(event) {
scrollStartPos=this.scrollTop+event.touches[0].pageY;
event.preventDefault();
},false);
document.getElementById(id).addEventListener("touchmove", function(event) {
this.scrollTop=scrollStartPos-event.touches[0].pageY;
event.preventDefault();
},false);
}
}
</script>
3.) call it on page load.. if you use jQuery:
$(document).ready(function() {
touchScroll("wrapper");
});
4.) if you want your scrollbars to be visible, just define following CSS rules:
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: #000;
}
Use this PhoneGap link
http://phonegap.pbworks.com/w/page/22863184/Hide%20the%20scrollbar%20in%20Android
this works in Android ,PhoneGap Applications for vertical and Horizontal Scroll
Code look Like this
public class MyActivity extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
// Display vertical scrollbar and hide horizontal scrollBar
super.appView.setVerticalScrollBarEnabled(true);
super.appView.setHorizontalScrollBarEnabled(false);
// set scrollbar style
super.appView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
}
}