Phonegap.js on second html page - angularjs

I basically have two pages in my phonegap application that I am building with PGB (index.html and main.html), that both use angular.js. Index.html is a login for the app, which redirects to main.html afterwards. All my plugins and phonegap.js are being injected fine into main, but none of the inline JS (alerts on doc ready, device ready, window load) are firing, let alone phonegap.js being loaded as well.
Any advice would be appreciated.
Script Includes:
<script src="phonegap.js"></script>
<script src="cdv-plugin-fb-connect.js"></script>
<script src="facebook-js-sdk.js"></script> <script>alert("inside pg");</script>
<script src="childbrowser.js"></script>
<script src="js/jquery.js"></script>
<script src="js/angular.min.js"></script>
<script>alert("here");</script>
<script src="js/controllers.js"></script>
<script src="js/klass.min.js"></script>
<script src="js/code.photoswipe.jquery-3.0.5.min.js"></script>
<script src="js/maskedInput.js" type="text/javascript"></script>
<script src="js/jquery.joyride.js"></script>
<script src="js/jquery.fancybox.pack.js"></script>
<script src="http://connect.facebook.net/en_US/all.js" type="text/javascript"></script>
Scripts:
alert("p2 adding")
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is loaded and it is now safe to make calls PhoneGap methods
//
function onDeviceReady() {
alert("main.html: device is ready");
}
$(window).load(function(){
alert("window.load happening");
})
</script>
<script>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-42023187-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-42023187-1', 'openvino.com');
ga('send', 'pageview');
</script>
<script type="text/javascript">
var objectToLike = window.location;
var FBactivated = false;
FB.init({
appId : '659381964079214', // App ID
channelURL : '', // Channel File, not required so leave empty
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
oauth : true,
xfbml : true // parse XFBML
});
FB.Event.subscribe('auth.authResponseChange', function(response) {
// Here we specify what we do with the response anytime this event occurs.
if (response.status === 'connected') {
getFriends();
testAPI();
FBactivated = true;
}
});
function getFriends() {
var fbUserIDs = []
FB.api('/me/friends', function(response) {
if(response.data) {
$.each(response.data,function(index,friend) {
var id = friend.id;
fbUserIDs.push(id);
});
var dataString = "fbUserIDs="+fbUserIDs.join();
$.ajax({
type: "POST",
data: dataString,
async: false,
url: "http://m.openvino.com/Scripts/faveMatch.php"
}).done(function(data){
console.log(data);
window.localStorage.setItem("fbFriends", data);
console.log("Saved");
});
} else {
alert("Error!");
}
});
}
function testAPI() {
FB.api('/me', function(response) {
//console.log(response, response.email);
var dataString2 = "id=" + response.id;
dataString2 += "&first_name=" + response.first_name;
dataString2 += "&last_name=" + response.last_name;
dataString2 += "&email=" + response.email;
console.log(dataString2);
$.ajax({
type: "POST",
url: "http://m.openvino.com/Scripts/fbconnect.php",
data: dataString2
}).done(function(data){
var dataJSON = $.parseJSON(data);
if (dataJSON[0].STATUS == "FAILURE") {
//console.log(dataJSON[0].MESSAGE);
return false;
} else if (dataJSON[0].STATUS == "SUCCESS") {
window.localStorage.setItem('email',dataJSON[0].COOKIE.email);
window.localStorage.setItem('password',dataJSON[0].COOKIE.password);
window.localStorage.setItem('name_first',dataJSON[0].COOKIE.name_first);
window.localStorage.setItem('name_last',dataJSON[0].COOKIE.name_last);
window.localStorage.setItem('uID',dataJSON[0].COOKIE.uID);
window.localStorage.setItem('phone',dataJSON[0].COOKIE.phone);
window.localStorage.setItem('firstTime',dataJSON[0].COOKIE.firstTime);
}
});
});
}
function fbLogout() {
if (FBactivated) {
try {
FB.logout(function(response) {
window.location.href = "index.html";
});
} catch (err) {
window.location.href = "index.html";
}
} else {
window.location.href = "index.html";
}
}
$(document).ready(function() {
alert("document.ready loaded");
$("#logmeout").click(function(e){
e.preventDefault();
window.localStorage.clear();
fbLogout();
return false;
});
$('.back_btn').click(function(e) {
$('.profile_menu').hide();
history.back();
});
$(document).click(function(e) {
$('.profile_menu').hide();
})
$('.profile_btn').click(function(e) {
$('.profile_menu').slideToggle();
e.stopPropagation();
e.preventDefault();
return false;
});
$('.profile_menu a').each(function() {
$(this).click(function(e) {
$('.profile_menu').hide();
});
});
});
HTML:
<body ng-app="OpenVino">
<div id="fb-root"></div>
<div class="header-wrap">
<header>
<div ng-show="(page != 'list')" class="back_btn"></div>
<img src="imgs/logo_only.png" alt="OpenVino" />
<div class="profile_btn"></div>
</header>
</div>
<div class="profile_menu">
My Favorites
Contact OpenVino
Images
Logout
</div>
<div class="content {{page}}" ng-view></div>

I fixed it with a simple, but disheartening solution: You have to turn your multipage app into a one page app. Unfortunate how phonegap advertises that you can take your HTML, CSS, and JS and build it natively. All of the .js loaded on the second page wouldnt work until I changed my login to a partial and fooled around with the routing.

Related

Angular login auth what about using web worker?

What do you think about this approach
using web worker for angular login/auth
it looks good at me and in this way you can get rid of
$rootScope event as well :)
This is just an example in a more prodution way
you should use like https://stackoverflow.com/a/16730809
Html & js
<html ng-app="app">
<head>
<meta charset="utf-8">
<title>Form</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body ng-controller="LoginController as vm">
<p ng-if="vm.isLogged">Logged as {{vm.username}}</p>
<a href ng-click="vm.doFakeLogin()">Login</a>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.2/angular.min.js">
</script>
<script>
function LoginController($scope){
var vm = this;
vm.isLogged = false;
var workerCheckLogin = new Worker('worker-check-login.js');
var workerDoLogin = new Worker('worker-do-login.js');
var jwt = 'auth-token';
workerCheckLogin.postMessage(jwt);
workerCheckLogin.addEventListener('message', function(e) {
if(e.data > 0){
$scope.$evalAsync(function() {
vm.isLogged = true;
vm.username = 'Whisher';
});
}
}, false);
vm.doFakeLogin = function doFakeLogin(){
workerDoLogin.postMessage({username:'whisher','password':'12345'});
}
workerDoLogin.addEventListener('message', function(e) {
if(e.data > 0){
$scope.$evalAsync(function() {
vm.isLogged = true;
vm.username = 'Whisher';
});
}
}, false);
}
angular
.module('app', [])
.controller('LoginController',LoginController);
</script>
</body>
</html>
worker-check-login.js
self.addEventListener('message', function(e) {
console.log('Worker check login said: ', e.data);
/*
do xhr to the server
e.data = jwt
return
1 succees
0 fail
*/
self.postMessage(0); //
}, false);
worker-do-login.js
self.addEventListener('message', function(e) {
console.log('Worker do login said: ', e.data);
/*
do xhr to the server
e.data = credentials
return
1 succees
0 fail
*/
self.postMessage(1); //
}, false);

How to add twitter feed in AngularJS / Ionic apps for android

I have used sample code to add twitter feed in my apps from following link
https://github.com/bradleyprice/ionic_twitterfeed but I got token null, so nothing to show in my app just refreshing screen.After that i refer blog http://blog.ionic.io/displaying-the-twitter-feed-within-your-ionic-app/ it also give me same result.
Please suggest me changes or any another link where i get best solution.
Some code are shown as follows , in index.html
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="lib/sha.js"></script>
<script src="lib/angular-resource/angular-resource.js"></script>
<script src="lib/ngCordova/dist/ng-cordova.js"></script>
<script src="js/ng-cordova-oauth.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
</head>
<body ng-app="starter" ng-controller="AppCtrl">
app.js
angular.module('starter', ['ionic', 'ngResource', 'ngCordova'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
});
});
controllers.js
angular.module('starter').controller('AppCtrl', function($scope, $ionicPlatform, $ionicPopup, TwitterService) {
// Should we show the post tweet button
$scope.showUpdateStatus = true;
// 1
$scope.correctTimestring = function(string) {
return new Date(Date.parse(string));
};
// 2
$scope.showHomeTimeline = function() {
alert("1");
TwitterService.getHomeTimeline().then(function(res) {
alert("home_timeline");
$scope.home_timeline = res;
}, function(req) {
console.log(req);
});
};
// 3
$scope.doRefresh = function() {
$scope.showHomeTimeline();
$scope.$broadcast('scroll.refreshComplete');
};
$scope.updateStatus = function() {
TwitterService.updateStatus().then(function(res) {
$scope.showUpdateStatus = false;
$scope.doRefresh();
}, function(req) {
console.log(req);
});
}
// 4
$ionicPlatform.ready(function() {
if (TwitterService.isAuthenticated()) {
$scope.showHomeTimeline();
} else {
TwitterService.initialize().then(function(result) {
if(result === true) {
$scope.showHomeTimeline();
}
});
}
});
});
services.js
angular.module('starter',['ionic', 'ngCordovaOauth']).factory('TwitterService', function($cordovaOauth, $cordovaOauthUtility, $http, $resource, $q) {
// 1
var twitterKey = "";
var clientId = '';
var clientSecret = '';
// 2
function storeUserToken(data) {
window.localStorage.setItem(twitterKey, JSON.stringify(data));
}
function getStoredToken() {
return window.localStorage.getItem(twitterKey);
}
// 3
function createTwitterSignature(method, url) {
var token = angular.fromJson(getStoredToken());
var oauthObject = {
oauth_consumer_key: clientId,
oauth_nonce: $cordovaOauthUtility.createNonce(32),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Math.round((new Date()).getTime() / 1000.0),
oauth_token: token.oauth_token,
oauth_version: "1.0"
};
var signatureObj = $cordovaOauthUtility.createSignature(method, url, oauthObject, {}, clientSecret, token.oauth_token_secret);
$http.defaults.headers.common.Authorization = signatureObj.authorization_header;
}
function createTwitterPostSignature(method, url, message) {
var token = angular.fromJson(getStoredToken());
var oauthObject = {
oauth_consumer_key: clientId,
oauth_nonce: $cordovaOauthUtility.createNonce(32),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Math.round((new Date()).getTime() / 1000.0),
oauth_token: token.oauth_token,
oauth_version: "1.0",
status: message
};
var signatureObj = $cordovaOauthUtility.createSignature(method, url, oauthObject, oauthObject, clientSecret, token.oauth_token_secret);
$http.defaults.headers.common.Authorization = signatureObj.authorization_header;
}
return {
// 4
initialize: function() {
var deferred = $q.defer();
var token = getStoredToken();
alert(token);
if (token !== null) {
deferred.resolve(true);
} else {
$cordovaOauth.twitter(clientId, clientSecret).then(function(result) {
storeUserToken(result);
deferred.resolve(true);
}, function(error) {
deferred.reject(false);
});
}
return deferred.promise;
},
// 5
isAuthenticated: function() {
return getStoredToken() !== null;
},
// 6
getHomeTimeline: function() {
var home_tl_url = 'https://api.twitter.com/1.1/statuses/home_timeline.json';
createTwitterSignature('GET', home_tl_url);
return $resource(home_tl_url).query().$promise;
},
updateStatus: function() {
var message = "test from ionic";
var update_url = 'https://api.twitter.com/1.1/statuses/update.json';
var results = createTwitterPostSignature('POST', update_url, message);
return $resource(update_url, {'status': message}).save().$promise;
},
storeUserToken: storeUserToken,
getStoredToken: getStoredToken,
createTwitterSignature: createTwitterSignature,
createTwitterPostSignature: createTwitterPostSignature
};
})
Might be worth checking out this example on Github
https://github.com/bradleyprice/ionic_twitterfeed

Integrate facebook with cordova and angular (Ionic)

I'm trying to add facebook integration to my ionic mobile app that I'm building using cordova. I'm able to get it working either without cordovaa or angular but in no way with both. With the code below, everything goes fine till FB.init gets called after loading all.js . After that, no further code is executed inside _init function, and because of that I cannot subscribe to events or do anything else.
angular facebook directive (uses code from this gist : https://gist.github.com/ruiwen/4722499)
angular.module('facebook', [])
.directive('fb', ['$FB', function($FB) {
return {
restrict: "E",
replace: true,
template: "<div id='fb-root'></div>",
compile: function(tElem, tAttrs) {
return {
post: function(scope, iElem, iAttrs, controller) {
var fbAppId = iAttrs.appId || '';
var fb_params = {
appId: iAttrs.appId || "",
cookie: iAttrs.cookie || true,
status: iAttrs.status || true,
nativeInterface: CDV.FB,
useCachedDialogs: false,
xfbml: iAttrs.xfbml || true
};
// Setup the post-load callback
window.fbAsyncInit = function() {
$FB._init(fb_params);
if('fbInit' in iAttrs) {
iAttrs.fbInit();
}
};
(function(d, s, id, fbAppId) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk', fbAppId));
}
}
}
};
}])
.factory('$FB', ['$rootScope', function($rootScope) {
var fbLoaded = false;
// Our own customisations
var _fb = {
loaded: fbLoaded,
isLoaded : function(){
return this.loaded;
},
authenticated : false,
isAuthenticated : function(){
return this.authenticated;
},
statusUpdated: function(response){
if (response.status == 'connected') {
self.authenticated = true;
alert('logged in');
} else {
alert('not logged in');
}
},
_init: function(params) {
self = this;
if(window.FB) {
// FIXME: Ugly hack to maintain both window.FB
// and our AngularJS-wrapped $FB with our customisations
angular.extend(window.FB, this);
angular.extend(this, window.FB);
// Set the flag
this.loaded = true;
// Initialise FB SDK
FB.init(params);
//THIS CODE IS NOT CALLED
FB.Event.subscribe('auth.statusChange', function(response) {
alert('auth.statusChange event');
});
FB.Event.subscribe('auth.authStatusChange', self.statusUpdated)
if(!$rootScope.$$phase) {
$rootScope.$apply();
}
}
}
}
return _fb;
}]);
My controller :
angular.module('starter.controllers', [])
.controller('StartCtrl', [
'$scope',
'$FB',
'$location',
function($scope, $FB, $location) {
$scope.$watch(function() {
return $FB.isLoaded()
},function(value){
console.log("VALUE",value);
// It needs authentication, this won't work.
if(value){
$scope.facebook_friends = $FB.api('/me/friends', function(response) {
$scope.facebook_friends = response.data;
});
}
},true);
$scope.$watch(function() {
return $FB.isAuthenticated()
},function(value){
alert("VALUE isAuthenticated "+value);
// YEP, this will work.
if(value){
$scope.facebook_friends = $FB.api('/me', function(response) {
$scope.facebook_friends = response.data;
console.log("FRIENDS",response);
});
}
},true);
$scope.FBlogin = function() {
FB.login(null, {scope: 'email'});
};
}
])
index.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, user-scalable=no, width=device-width">
<title>Starter</title>
<link href="lib/css/ionic.css" rel="stylesheet">
<link href="css/app.css" rel="stylesheet">
<script src="lib/js/ionic.bundle.js"></script>
<script src="cordova.js"></script>
<script src="js/angular-fb.js"></script>
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<!-- cordova facebook plugin -->
<script src="cdv-plugin-fb-connect.js"></script>
<!-- facebook js sdk -->
<script src="facebook-js-sdk.js"></script>
</head>
<body ng-app="starter" animation="slide-left-right-ios7">
<ion-nav-view></ion-nav-view>
<fb app-id='appid'></fb>
</body>
</html>
and app.js
angular.module('starter', ['ionic', 'starter.services', 'starter.controllers', 'facebook'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('start', {
url: "/start",
templateUrl: "templates/start.html",
controller: 'StartCtrl'
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/start');
});
You should not doing this <script src="facebook-js-sdk.js"></script> actually since it against TOS. Even-though you want to make sure the sdk is loading.
Instead you can try this code below (to make sure you can install cordova-inappbrowser first)
<script>
function statusChangeCallback(response) {
console.log('statusChangeCallback');
console.log(response);
if (response.status === 'connected') {
// Logged into your app and Facebook.
testAPI();
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
document.getElementById('status').innerHTML = 'Please log ' +
'into this app.';
} else {
document.getElementById('status').innerHTML = 'Please log ' +
'into Facebook.';
}
}
function checkLoginState() {
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
}
window.fbAsyncInit = function() {
FB.init({
appId : '{your-app-id}',
cookie : true, // enable cookies to allow the server to access
// the session
xfbml : true, // parse social plugins on this page
version : 'v2.5' // use graph api version 2.5
});
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
function testAPI() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Successful login for: ' + response.name);
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + '!';
});
}
</script>
<!--
Below we include the Login Button social plugin. This button uses
the JavaScript SDK to present a graphical Login button that triggers
the FB.login() function when clicked.
-->
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
<div id="status">
</div>
To deeper insight
1 first add this plugin
cordova plugin add cordova-plugin-inappbrowser
2 After that create app id follow these steps
https://developers.facebook.com/docs/apps/register
3 After that add this code where you need facebook integration`
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
$cordovaOauth.facebook("447073565475718", ["email", "public_profile"]).then(function(result) {
displayData($http, result.access_token);
var name = result.data.name;
var gender = result.data.gender;
var location = result.data.location;
var picture = result.data.picture;
}, function(error) {
console.log(error);
});
};
function displayData($http, access_token)
{
$http.get("https://graph.facebook.com/v2.2/me", {params: {access_token: access_token, fields: "name,gender,location,picture,email", format: "json" }}).then(function(result)
{
console.log(JSON.stringify(result));
var name = result.data.name;
var gender = result.data.gender;
var location = result.data.location;
var picture = result.data.picture;
var id =result.data.id;
var userid=id;
}, function(error) {
alert("There was a problem getting your profile. Check the logs for details.");
console.log(error);
});
`
une ngcordova, it gives you simple AngularJS wrappers for a massive amount of Cordova plugins, it include a wrapper for facebookConnectPlugin
The phonegap-facebook-plugin version 0.8.1 has more to do than a simple installation via cordova plugin add. phonegap-native-fb-ionic mentions the required one for ionic step by step.
You should integrate with Facebook through the facebookConnectPlugin of cordova.
You will find a deep explanation of how to use it in this link: https://github.com/Wizcorp/phonegap-facebook-plugin.
The plugin gives you everything you need and short examples. But you have to make sure the following things will be done:
Read carefully the instructions of installing the plugin. I choosed the manual way to install the plugin for Android through the cordova CLI.
Remember that you can use all phonegap plugins only after the deviceReady event, so you have to make sure you are calling the api of the facebookConnectPlugin after the device is ready of course.
Good luck!

AngularJS/PouchDB app stops syncing to CouchDB when cache.manifest added

I have a single page web app written using AngularJS. It uses PouchDB to replicate to a CouchDB server and works fine.
The problem comes when I try to convert the webpage to be available offline by adding cache.manifest. Suddenly ALL the replication tasks throw errors and stop working, whether working offline or online.
In Chrome it just says "GET ...myCouchIP/myDB/?_nonce=CxVFIwnEJeGFcyoJ net::ERR_FAILED"
In Firefox it also throws an error but mentions that the request is blocked - try enabling CORS.
CORS is enabled on the remote CouchDB as per the instructions from PouchDB setup page. Plus it works fine while not using the cache.manifest (i.e. it is quite happy with all the different ip addresses between my desk, the server and a VM - it is a prototype so there are no domain names at this time).
Incidentally, at this time I am not using any kind of authentication. Admin party is in effect.
So what changes when adding the cache.manifest? Clues gratefully welcomed.
Thanks in advance.
app.js
var app = angular.module('Assets', ['assets.controllers', 'ngRoute']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', {
controller: 'OverviewCtrl',
templateUrl: 'views/overview.html'
}).
when('/new', {
controller: 'NewMachineCtrl',
templateUrl: 'views/machineForm.html'
}).
otherwise({redirectTo: '/'});
}]);
controller.js
var _control = angular.module('assets.controllers', ['assets.services']);
_control.controller('OverviewCtrl', ['$scope', 'Machine', function($scope, Machine) {
var promise = Machine.getAll();
promise.then(function(machineList) {
$scope.machines = machineList;
}, function(reason) {
alert('Machine list is empty: ' + reason);
});
}]);
_control.controller('UpdateMachineCtrl', ['$scope', '$routeParams', 'Machine',
function($scope, $routeParams, Machine) {
$scope.title = "Update Installation Details";
var promise = Machine.getSingle($routeParams.docId);
promise.then(function(machine) {
$scope.machine = machine;
}, function(reason) {
alert('Record could not be retrieved');
});
$scope.save = function() {
Machine.update($scope.machine);
};
}]);
_control.controller('SyncCtrl', ['$scope', 'Machine', function($scope, Machine) {
$scope.syncDb = function() {
Machine.sync();
Machine.checkConflicts();
};
$scope.checkCors = function() {
// Check CORS is supported
var corsCheck = function(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
console.log('CORS not supported by browser');
}
xhr.onload = function() {
console.log('Response from CORS ' + method + ' request to ' + url + ': ' + xhr.responseText);
};
xhr.onerror = function() {
console.log('Error response from CORS ' + method + ' request to ' + url + ': ' + xhr.responseText);
};
xhr.send();
};
var server = 'http://10.100.3.21:5984/ass_support';
corsCheck('GET', server);
corsCheck('PUT', server);
corsCheck('POST', server);
corsCheck('HEAD', server);
// corsCheck('DELETE', server);
};
}]);
service.js
var _service = angular.module('assets.services', []);
_service.constant('dbConfig',{
dbName: 'assets',
dbServer: 'http://myCouchServerIp:5984/'
});
/**
* Make PouchDB available in AngularJS.
*/
_service.factory('$db', ['dbConfig', function(dbConfig) {
PouchDB.enableAllDbs = true;
var localDb = new PouchDB(dbConfig.dbName);
var remoteDb = dbConfig.dbServer + dbConfig.dbName;
var options = {live: true};
var syncError = function() {
console.log('Problem encountered during database synchronisation');
};
console.log('Replicating from local to server');
localDb.replicate.to(remoteDb, options, syncError);
console.log('Replicating from server back to local');
localDb.replicate.from(remoteDb, options, syncError);
return localDb;
}]);
_service.factory('Machine', ['$q', '$db', '$rootScope', 'dbConfig',
function($q, $db, $rootScope, dbConfig) {
return {
update: function(machine) {
var delay = $q.defer();
var doc = {
_id: machine._id,
_rev: machine._rev,
type: machine.type,
customer: machine.customer,
factory: machine.factory,
lineId: machine.lineId,
plcVersion: machine.plcVersion,
dateCreated: machine.dateCreated,
lastUpdated: new Date().toUTCString()
};
$db.put(doc, function(error, response) {
$rootScope.$apply(function() {
if (error) {
console.log('Update failed: ');
console.log(error);
delay.reject(error);
} else {
console.log('Update succeeded: ');
console.log(response);
delay.resolve(response);
}
});
});
return delay.promise;
},
getAll: function() {
var delay = $q.defer();
var map = function(doc) {
if (doc.type === 'machine') {
emit([doc.customer, doc.factory],
{
_id: doc._id,
customer: doc.customer,
factory: doc.factory,
lineId: doc.lineId,
plcVersion: doc.plcVersion,
}
);
}
};
$db.query({map: map}, function(error, response) {
$rootScope.$apply(function() {
if (error) {
delay.reject(error);
} else {
console.log('Query retrieved ' + response.rows.length + ' rows');
var queryResults = [];
// Create an array from the response
response.rows.forEach(function(row) {
queryResults.push(row.value);
});
delay.resolve(queryResults);
}
});
});
return delay.promise;
},
sync: function() {
var remoteDb = dbConfig.dbServer + dbConfig.dbName;
var options = {live: true};
var syncError = function(error, changes) {
console.log('Problem encountered during database synchronisation');
console.log(error);
console.log(changes);
};
var syncSuccess = function(error, changes) {
console.log('Sync success');
console.log(error);
console.log(changes);
};
console.log('Replicating from local to server');
$db.replicate.to(remoteDb, options, syncError).
on('error', syncError).
on('complete', syncSuccess);
console.log('Replicating from server back to local');
$db.replicate.from(remoteDb, options, syncError);
}
};
}]);
_service.factory('dbListener', ['$rootScope', '$db', function($rootScope, $db) {
console.log('Registering a onChange listener');
$db.info(function(error, response) {
$db.changes({
since: response.update_seq,
live: true,
}).on('change', function() {
console.log('Change detected by the dbListener');
// TODO work out why this never happens
});
});
}]);
cache.manifest
CACHE MANIFEST
# views
views/machineForm.html
views/overview.html
# scripts
scripts/vendor/pouchdb-2.2.0.min.js
scripts/vendor/angular-1.2.16.min.js
scripts/vendor/angular-route-1.2.16.min.js
scripts/app.js
scripts/controllers/controller.js
scripts/services/service.js
index.html
<!DOCTYPE html>
<html lang="en" manifest="cache.manifest" data-ng-app="Assets">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Asset Management</title>
<script src="scripts/vendor/angular-1.2.16.min.js" type="text/javascript"></script>
<script src="scripts/vendor/angular-route-1.2.16.min.js" type="text/javascript></script>
<script src="scripts/vendor/pouchdb-2.2.0.min.js" type="text/javascript"></script>
<script src="scripts/app.js" type="text/javascript"></script>
<script src="scripts/services/service.js" type="text/javascript"></script>
<script src="scripts/controllers/controller.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<nav class="sidebar">
<h3>Options</h3>
<div>
<a class="active" data-ng-href="#/">Overview</a>
<a data-ng-href="#" data-ng-controller="SyncCtrl" data-ng-click="syncDb()">Synchronise</a>
<a data-ng-href="" data-ng-controller="SyncCtrl" data-ng-click="checkCors()">Check CORS</a>
</div>
</nav>
<section class="main">
<div data-ng-view></div>
</section>
</div>
</body>
</html>
overview.html
<h3>Installation Overview</h3>
<table>
<tr>
<th>Customer</th>
<th>Factory</th>
<th>Line Id</th>
<th>PLC Version</th>
</tr>
<tr data-ng-repeat="machine in machines">
<td>{{machine.customer}}</td>
<td>{{machine.factory}}</td>
<td><a data-ng-href="#/view/{{machine._id}}">{{machine.lineId}}</a></td>
<td>{{machine.plcVersion}}</td>
</tr>
</table>
machineForm.html
<h3>{{title}}</h3>
<form name="machineForm" data-ng-submit="save()">
<div>
<label for="customer">Customer:</label>
<div><input data-ng-model="machine.customer" id="customer" required></div>
</div>
<div>
<label for="factory">Factory:</label>
<div><input data-ng-model="machine.factory" id="factory" required></div>
</div>
<div>
<label for="lineId">Line ID:</label>
<div><input data-ng-model="machine.lineId" id="lineId" required></div>
</div>
<div>
<label for="plcVersion">PLC Version:</label>
<div><input data-ng-model="machine.plcVersion" id="plcVersion"></div>
</div>
<div><button data-ng-disabled="machineForm.$invalid">Save</button></div>
</form>
Try changing your cache.manifest file to this:
CACHE MANIFEST
CACHE:
# views
views/machineForm.html
views/overview.html
# scripts
scripts/vendor/pouchdb-2.2.0.min.js
scripts/vendor/angular-1.2.16.min.js
scripts/vendor/angular-route-1.2.16.min.js
scripts/app.js
scripts/controllers/controller.js
scripts/services/service.js
NETWORK:
*
When using a manifest file, all non-cached resources will fail on a cached page, even when you're online. The NETWORK section tells the browser to allow requests to non-cached resources (they'll still fail while offline, of course).

"Error: $apply already in progress" when using FireBaseAuthClient with AngularJS

I'm trying to record the logged in user in an AngularJS scope, but getting an error when the page first loads up.
Clicking "Login" seems to work, but then logout bails with the same "$apply already in progress" error.
I'm expecting I've just misunderstood how $apply works, can anybody help?
Update:
It works seamlessly if I wrap just the if (user) part in $apply() as follows.
var auth = new FirebaseAuthClient(ref, function(error, user) {
if (user) {
$scope.$apply(function(){ $scope.user = user; });
console.log(user);
} else if (error) {
// I can't vouch for this, haven't tested it
$scope.$apply(function(){ $scope.user = null; });
console.log(error);
} else {
$scope.user = null;
console.log("logged out");
}
});
Original code:
app.js:
var app = angular.module('app', ['firebase']);
controller.js:
app.controller('Login', ['$scope', 'angularFire',
function($scope, angularFire) {
$scope.loginstatus = 'logged out';
var ref = new Firebase("https://app.firebaseio.com/");
var auth = new FirebaseAuthClient(ref, function(error, user) {
if (user) {
$scope.$apply(function(){ $scope.loginstatus = 'logged in'; });
} else if (error) {
$scope.$apply(function(){ $scope.loginstatus = 'error'; });
alert("Login error: " + error);
} else {
$scope.$apply(function(){ $scope.loginstatus = 'logged out'; });
}
});
$scope.login = function(provider, args) {
auth.login(provider, args);
}
$scope.logout = function() {
auth.logout();
}
}]);
index.html:
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<title>App</title>
<script type="text/javascript" src="https://cdn.firebase.com/v0/firebase.js">
<script type="text/javascript" src='https://cdn.firebase.com/v0/firebase-auth-client.js'></script></script>
<script type="text/javascript" src="lib/angular/angular.js"></script>
<script type="text/javascript" src="lib/angularFire.js"></script>
<script type="text/javascript" src="js/app.js"></script>
<script type="text/javascript" src="js/controllers.js"></script>
</head>
<body ng-controller="Login">
<p>Login status: {{loginstatus}}</p>
<div class="container">
<h1>Login</h1>
<p>
<button ng-hide="user" ng-click="login('twitter')" class="btn btn-primary btn-large">Login</button>
<button ng-show="user" ng-click="logout()" class="btn btn-primary btn-large">Logout</button>
</p>
</div>
</body>
</html>
$apply is only needed when you're outside of the context of Angular (like a setTimeout, setInterval, or non-Angular XHR callback).
Since FireBaseAuthClient is a tool written with Angular in mind and injected into your controller, it's likely that the callbacks are already wrapped in $scope.$apply. You can fix your code by removing $scope.$apply, so just:
var ref = new Firebase("https://app.firebaseio.com/");
var auth = new FirebaseAuthClient(ref, function(error, user) {
if (user) {
$scope.loginstatus = 'logged in';
} else if (error) {
$scope.loginstatus = 'error';
alert("Login error: " + error);
} else {
$scope.loginstatus = 'logged out';
}
});

Resources