.controller('paymentsController', function ($scope, $localStorage, $log, $state, $window, $ionicModal, Payment, ItemList, SweetAlert) {
$scope.scanCard = function(){
var cardIOResponseFields = [
"card_type",
"redacted_card_number",
"card_number",
"expiry_month",
"expiry_year",
"cvv",
"zip"
];
var onCardIOComplete = function(response) {
for (var i = 0, len = cardIOResponseFields.length; i < len; i++) {
var field = cardIOResponseFields[i];
console.log(field + ": " + response[field]);
}
};
var onCardIOCancel = function() {
console.log("card.io scan cancelled");
};
var onCardIOCheck = function (canScan) {
console.log("card.io canScan? " + canScan);
var scanBtn = angular.element($("#scanBtn")).scope();
//var scanBtn = document.getElementById("scanBtn");
if (!canScan) {
scanBtn.innerHTML = "Manual entry";
}
};
CardIO.scan({
"collect_expiry": true,
"collect_cvv": false,
"collect_zip": false,
"shows_first_use_alert": true,
"disable_manual_entry_buttons": false
},
onCardIOComplete,
onCardIOCancel
);
CardIO.canScan(onCardIOCheck);
};
}
I installed a card reader plugin in my phonegap(i'm using ionic as a framework) the problem I'm having is that the plugin doesn't work. this is the plugin I'm using https://github.com/card-io/card.io-iOS-SDK-PhoneGap.
this is my view.
<button id="scanBtn" ng-click="scanCard()" class="button button-large button-block button-light">Scan Card</button>
when the user click on the #scanBtn it loads this script.
var cardIOResponseFields = [
"card_type",
"redacted_card_number",
"card_number",
"expiry_month",
"expiry_year",
"cvv",
"zip"
];
var onCardIOComplete = function(response) {
for (var i = 0, len = cardIOResponseFields.length; i < len; i++) {
var field = cardIOResponseFields[i];
console.log(field + ": " + response[field]);
}
};
var onCardIOCancel = function() {
console.log("card.io scan cancelled");
};
var onCardIOCheck = function (canScan) {
console.log("card.io canScan? " + canScan);
var scanBtn = angular.element($("#scanBtn")).scope();
//var scanBtn = document.getElementById("scanBtn");
if (!canScan) {
scanBtn.innerHTML = "Manual entry";
}
};
CardIO.scan({
"collect_expiry": true,
"collect_cvv": false,
"collect_zip": false,
"shows_first_use_alert": true,
"disable_manual_entry_buttons": false
},
onCardIOComplete,
onCardIOCancel
);
CardIO.canScan(onCardIOCheck);
};
my app doesn't work in my browser or using the phonegap app, but when i launch the ionic emulator only the entry to input the card form shows up and no camera loads to scan the card, which led me to believe the camera execution is failing.
When load the cardio on my browser i get the following console error:
ReferenceError: CardIO is not defined.
Try the same on device.
I got the same error on browser and it works well on the device. You could think of this as the camera / or contacts picker plugin - which will work only on device - and not on sim or browser.
All cordova plugins will throw an error when running on browsers or emulators. Always use them on devices and inside
$ionicPlatform.ready(function() { ... });
Related
Previously I could add the path of an image after converting it to Base64 even Input to then be shown in a DIV, but after a while in trying to perform the process does not allow me to do that action and I get the following message:
angular.module('perfilEstudiante', ['ionic', 'ngCordova'])
.controller('mostrarPerfilEstu', mostrarPerfilEstu)
.directive('pickFile', pickFile)
.factory('obtenerPerfilEstu', obtenerPerfilEstu);
mostrarPerfilEstu.$inject = ['$scope', 'obtenerPerfilEstu'];
function mostrarPerfilEstu($scope, obtenerPerfilEstu, $element) {
var Perfil, Mes, Periodo_Estu, input, button, evtHandler, dataImage;
dataImage = localStorage.getItem("imgData");
if (dataImage === null) {
$scope.dataImage = "img/profile_icon.png";
} else {
$scope.dataImage = "data:image/png;base64," + dataImage;
}
$scope.loadImage = function (file) {
if (file.type.indexOf('image') < 0) {
$scope.res = "Tipo inválido";
$scope.$apply();
return;
}
var fReader = new FileReader();
fReader.onload = function () {
var data = fReader.result;
$scope.dataImage = data;
$scope.res = "";
$scope.$apply();
localStorage.setItem("imgData", data.replace(/^data:image\/(png|jpe?g);base64,/, ""));
};
fReader.readAsDataURL(file);
};
};
function pickFile() {
return {
restrict: 'EA',
scope: {
onselected: "&"
},
template: '<button class="button button-icon icon ion-plus-round pull-right">' +
'<input type="file" style="display: none !important">' +
'</button>',
link: function ($scope, $element) {
var input = $element.find('input');
var button = $element.find('button');
var evtHandler = function () {
input[0].click();
};
button.on('click', evtHandler)
input.on('change', function () {
var file = input[0].files[0];
$scope.onselected({
file: file
});
});
}
};
};
Android version in my smartphone is 4.2.2
Edit
Came across this plugin. Looks like it will do the job.
https://github.com/dbaq/cordova-plugin-filepickerio/blob/master/README.md
Original
Input type=file is not supported in Cordova.
You will have to use something like the Cordova File Plugin:
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/
Along with the Cordova File Transfer Plugin:
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file-transfer/
If you just want to select images or pictures you can use the Cordova Camera Plugin
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/
Using this you can enable users to select an image from their photo library. This will be passed back to the app and you can use the file transfer plugin to send the image to a server.
Install camera plugin:
cordova plugin add cordova-plugin-camera
Sample camera plugin JS code:
var cameraOptions = {
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY
}
function cameraSuccess(data){
console.log(data);
var img = document.getElementById("yourImg");
img.src = data;
}
function cameraError(error){
console.log(error);
}
navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions);
Sample HTML:
<div><img id="yourImg" src=""/><div>
i have designed app using ionic and angularjs. Earlier the app was working fine but now i have changed the api ....the app working on browser but not on device...its functionalities not working on device..
before changed the api(app working on device):
var CONSTANTS = "http://ip_address/api/";
var api = CONSTANTS+'api.php?method=register' + '&user_registration=';
$http.post(api, {username : username,email : useremail,pwd : userpassword}).success(function(response) {
if( response[0].status == 1){
$cordovaToast.showShortBottom('Successfully Registered').then(function(success) {
// success
}, function (error) {
// error
});
document.getElementById('user_email').innerHTML = "";
document.getElementById('user_email').innerHTML = "";
document.getElementById('user_email').innerHTML = "";
$state.go('auth.login');
}else if( response[0].status == 0){
$cordovaToast.showLongBottom('Existing User or Invalid Data').then(function(success) {
// success
}, function (error) {
// error
});
}else {
//console.log('Error');
}
}, function(err) {
// console.log(err);
});
after changing the api in the code(app not working on device):
var CONSTANTS = "https://www.test.com/api/";
var api = CONSTANTS+'api.php?method=register' + '&user_registration=';
$http.post(...)... // Same as above
I am following this article on Social Logins with AngularJS and ASP.Net WebAPI (which is quite good):
ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app
Pretty much, the code works fine when you are running the social login through a desktop browser (i.e. Chrome, FF, IE, Edge). The social login opens in a new window (not tab) and you are able to use either your Google or Facebook account and once your are logged in through any of them, you are redirected to the callback page (authComplete.html), and the callback page has a JS file defined (authComplete.js) that would close the window and execute a command on the parent window.
the angularJS controller which calls the external login url and opens a popup window (not tab) on desktop browsers:
loginController.js
'use strict';
app.controller('loginController', ['$scope', '$location', 'authService', 'ngAuthSettings', function ($scope, $location, authService, ngAuthSettings) {
$scope.loginData = {
userName: "",
password: "",
useRefreshTokens: false
};
$scope.message = "";
$scope.login = function () {
authService.login($scope.loginData).then(function (response) {
$location.path('/orders');
},
function (err) {
$scope.message = err.error_description;
});
};
$scope.authExternalProvider = function (provider) {
var redirectUri = location.protocol + '//' + location.host + '/authcomplete.html';
var externalProviderUrl = ngAuthSettings.apiServiceBaseUri + "api/Account/ExternalLogin?provider=" + provider
+ "&response_type=token&client_id=" + ngAuthSettings.clientId
+ "&redirect_uri=" + redirectUri;
window.$windowScope = $scope;
var oauthWindow = window.open(externalProviderUrl, "Authenticate Account", "location=0,status=0,width=600,height=750");
};
$scope.authCompletedCB = function (fragment) {
$scope.$apply(function () {
if (fragment.haslocalaccount == 'False') {
authService.logOut();
authService.externalAuthData = {
provider: fragment.provider,
userName: fragment.external_user_name,
externalAccessToken: fragment.external_access_token
};
$location.path('/associate');
}
else {
//Obtain access token and redirect to orders
var externalData = { provider: fragment.provider, externalAccessToken: fragment.external_access_token };
authService.obtainAccessToken(externalData).then(function (response) {
$location.path('/orders');
},
function (err) {
$scope.message = err.error_description;
});
}
});
}
}]);
authComplete.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<script src="scripts/authComplete.js"></script>
</body>
</html>
authComplete.js
window.common = (function () {
var common = {};
common.getFragment = function getFragment() {
if (window.location.hash.indexOf("#") === 0) {
return parseQueryString(window.location.hash.substr(1));
} else {
return {};
}
};
function parseQueryString(queryString) {
var data = {},
pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;
if (queryString === null) {
return data;
}
pairs = queryString.split("&");
for (var i = 0; i < pairs.length; i++) {
pair = pairs[i];
separatorIndex = pair.indexOf("=");
if (separatorIndex === -1) {
escapedKey = pair;
escapedValue = null;
} else {
escapedKey = pair.substr(0, separatorIndex);
escapedValue = pair.substr(separatorIndex + 1);
}
key = decodeURIComponent(escapedKey);
value = decodeURIComponent(escapedValue);
data[key] = value;
}
return data;
}
return common;
})();
var fragment = common.getFragment();
window.location.hash = fragment.state || '';
window.opener.$windowScope.authCompletedCB(fragment);
window.close();
The issue I am having is that when I run the application on a mobile device (Safari, Chrome for Mobile), the social login window opens in a new tab and the JS function which was intended to pass back the fragment to the main application window does not execute nad the new tab does not close.
You can actually try this behavior on both a desktop and mobile browser through the application:
http://ngauthenticationapi.azurewebsites.net/
What I have tried so far in this context is in the login controller, I modified the function so that the external login url opens in the same window:
$scope.authExternalProvider = function (provider) {
var redirectUri = location.protocol + '//' + location.host + '/authcomplete.html';
var externalProviderUrl = ngAuthSettings.apiServiceBaseUri + "api/Account/ExternalLogin?provider=" + provider
+ "&response_type=token&client_id=" + ngAuthSettings.clientId
+ "&redirect_uri=" + redirectUri;
window.location = externalProviderUrl;
};
And modified the authComplete.js common.getFragment function to return to the login page, by appending the access token provided by the social login as query string:
common.getFragment = function getFragment() {
if (window.location.hash.indexOf("#") === 0) {
var hash = window.location.hash.substr(1);
var redirectUrl = location.protocol + '//' + location.host + '/#/login?ext=' + hash;
window.location = redirectUrl;
} else {
return {};
}
};
And in the login controller, I added a function to parse the querystring and try to call the $scope.authCompletedCB(fragment) function like:
var vm = this;
var fragment = null;
vm.testFn = function (fragment) {
$scope.$apply(function () {
if (fragment.haslocalaccount == 'False') {
authenticationService.logOut();
authenticationService.externalAuthData = {
provider: fragment.provider,
userName: fragment.external_user_name,
externalAccessToken: fragment.external_access_token
};
$location.path('/associate');
}
else {
//Obtain access token and redirect to orders
var externalData = { provider: fragment.provider, externalAccessToken: fragment.external_access_token };
authenticationService.obtainAccessToken(externalData).then(function (response) {
$location.path('/home');
},
function (err) {
$scope.message = err.error_description;
});
}
});
}
init();
function parseQueryString(queryString) {
var data = {},
pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;
if (queryString === null) {
return data;
}
pairs = queryString.split("&");
for (var i = 0; i < pairs.length; i++) {
pair = pairs[i];
separatorIndex = pair.indexOf("=");
if (separatorIndex === -1) {
escapedKey = pair;
escapedValue = null;
} else {
escapedKey = pair.substr(0, separatorIndex);
escapedValue = pair.substr(separatorIndex + 1);
}
key = decodeURIComponent(escapedKey);
value = decodeURIComponent(escapedValue);
data[key] = value;
}
return data;
}
function init() {
var idx = window.location.hash.indexOf("ext=");
if (window.location.hash.indexOf("#") === 0) {
fragment = parseQueryString(window.location.hash.substr(idx));
vm.testFn(fragment);
}
}
But obviously this is giving me an error related to angular (which I have no clue at the moment):
https://docs.angularjs.org/error/$rootScope/inprog?p0=$digest
So, pretty much it is a dead end for me at this stage.
Any ideas or input would be highly appreciated.
Gracias!
Update: I managed to resolve the Angular error about the rootscope being thrown, but sadly, resolving that does not fix the main issue. If I tried to open the social login on the same browser tab where my application is, Google can login and return to the application and pass the tokens required. It is a different story for Facebook, where in the Developer's tools console, there is a warning that seems to stop Facebook from displaying the login page.
Pretty much, the original method with which a new window (or tab) is opened is the way forward but fixing the same for mobile browser seems to be getting more challenging.
On desktop, when the auth window pops up (not tab) it has the opener property set to the window which opened this pop up window, on mobile, as you said, its not a pop up window but a new tab. when a new tab is opened in the browser, the opener property is null so actually you have an exception here:
window.opener.$windowScope.authCompletedCB
because you can't refer the $windowScope property of the null value (window.opener) so every line of code after this one wont be executed - thats why the window isn't closed on mobile.
A Solution
In your authComplete.js file, instead of trying to call
window.opener.$windowScope.authCompletedCB and pass the fragment of the user, save the fragment in the localStorage or in a cookie (after all the page at authComplete.html is in the same origin as your application) using JSON.stringify() and just close the window using window.close().
In the loginController.js, make an $interval for something like 100ms to check for a value in the localStorage or in a cookie (don't forget to clear the interval when the $scope is $destroy), if afragment exist you can parse its value using JSON.parse from the storage, remove it from the storage and call $scope.authCompletedCB with the parsed value.
UPDATE - Added code samples
authComplete.js
...
var fragment = common.getFragment();
// window.location.hash = fragment.state || '';
// window.opener.$windowScope.authCompletedCB(fragment);
localStorage.setItem("auth_fragment", JSON.stringify(fragment))
window.close();
loginController.js
app.controller('loginController', ['$scope', '$interval', '$location', 'authService', 'ngAuthSettings',
function ($scope, $interval, $location, authService, ngAuthSettings) {
...
// check for fragment every 100ms
var _interval = $interval(_checkForFragment, 100);
function _checkForFragment() {
var fragment = localStorage.getItem("auth_fragment");
if(fragment && (fragment = JSON.parse(fragment))) {
// clear the fragment from the storage
localStorage.removeItem("auth_fragment");
// continue as usual
$scope.authCompletedCB(fragment);
// stop looking for fragmet
_clearInterval();
}
}
function _clearInterval() {
$interval.cancel(_interval);
}
$scope.$on("$destroy", function() {
// clear the interval when $scope is destroyed
_clearInterval();
});
}]);
I'm trying to register a background task on my Windows Phone 8.1 to receive and handle push notifications.At the moment everything is working when the app is opened (foreground+background), but a background task that is defined in the app.js does not work when app is closed.
This is defined in the package.phone.appxmanifest:
<Extension Category="windows.backgroundTasks" StartPage="js/lib/backgroundTask.js">
<BackgroundTasks>
<Task Type="pushNotification" />
</BackgroundTasks>
</Extension>
backgroundTask.js
(function () {
//var backgroundTask = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current,
//taskName = backgroundTask.task.name;
Windows.Storage.ApplicationData.current.localSettings.values["hello"] = "world";
close();
})();
this is what my app.js does:
var taskName = "mySuperFancyBgTaskName";
var registerBackgroundTask = function() {
var btr = Windows.ApplicationModel.Background.BackgroundTaskRegistration;
var iter = btr.allTasks.first();
var taskRegistered = false;
while (iter.hasCurrent){
var ta = iter.current.value;
if (ta.name == taskName){
taskRegistered = true;
break;
}
iter.moveNext();
}
if (!taskRegistered){
var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
var trigger = new Windows.ApplicationModel.Background.PushNotificationTrigger();
builder.setTrigger( trigger );
builder.taskEntryPoint = "js\\lib\\backgroundTask.js";
builder.name = taskName;
try{
var task = builder.register();
//task.addEventListener("completed", onPushNotification);
}
catch (e){
console.error(e);
}
}
}
var channel;
var pushNotificationManager = Windows.Networking.PushNotifications.PushNotificationChannelManager;
var channelOperation = pushNotificationManager.createPushNotificationChannelForApplicationAsync();
channelOperation.then(function (newChannel) {
channel = newChannel;
saveChannelUriInSettings(channel.uri);
console.log("opened push notification channel with uri: " + channel.uri);
registerBackgroundTask();
},
function (error) {
console.log("Channel could not be retreived. " + error.number)
}
);
It seems that backgroundTask.js is never started,because there is nothing written in the localsettings. Tried to do some stuff there, but of course not able to debug there.
If I do
var onPushNotification = function (e) { ...}
channel.addEventListener("pushnotificationreceived", onPushNotification);
receiving raw push notifications works fine. So how do I get backgroundtask to work, so that it can save incoming push notifications? If it is working there is no need to define a event listener in the app to catch push notifications, right?
Any help is appreciated - thanks in advance!
I'm using Kendo UI Mobile via Icenium Extension for Visual Studio. I'm very new at this, but I'm stumbling along. I've written a method (called popDataSource) in a view that gets some data (reads the names of files in a folder) and returns those file names. The method works perfectly if I wire it up to a button click event, but what I really want is for the method to be called when the page first loads. I've tried setting data-show=popDataSource and even data-after-show=popDataSource, but when I do that I get the error Object [object Object] has no method 'set' when I try to return the data. I'm also not that well versed in javascript, which I'm sure isn't helping me any.
Here's my code:
Snippet from index.html:
<div id="tabstrip-listSonicImages" data-role="view" data-title="Sonic Images List" data-model="app.listSonicImagesService.viewModel"
data-after-show="app.listSonicImagesService.viewModel.popDataSource">
<div data-role="content" class="view-content">
<div data-role="scroller">
<div class="buttonArea">
<a id="btnShowList" data-role="button" data-bind="click: popDataSource"
class="login-button">Display List</a>
</div>
<ul class="forecast-list" data-role="listview" data-bind="source: sonicImagesDataSource" data-template="sonic-image-list-template">
</ul>
</div>
</div>
</div>
<script type="text/x-kendo-tmpl" id="sonic-image-list-template">
<a data-role="listview-link" href="\#tabstrip-playSonicImage?fileName=${fileName}">${fileName}</a>
</script>
listiconimages.js
(function(global) {
var SonicImageListViewModel,
app = global.app = global.app || {};
SonicImageListViewModel = kendo.data.ObservableObject.extend({
popDataSource: function () {
var that = this;
var listSI = new Array();
try{
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
function (fileSys) {
fileSys.root.getDirectory("SIData", { create: true, exclusive: false},
function (dataDirEntry) {
var directoryReader = dataDirEntry.createReader ();
directoryReader.readEntries(
function (entries) {
var rows = entries.length;
for (i = 0; i < rows; i++) {
var fName = entries[i].name;
listSI[i] = { "fileName": fName, "image": "xxx" };
}
},
function (error) {
alert("error: " + error.code);
}
);
},
null);
},
null
);
var dataSource = new kendo.data.DataSource(
{
data: listSI,
filter: { field: "fileName", operator: "endswith", value: ".simg" }
}
);
that.set("sonicImagesDataSource", dataSource);
} catch (ex) {
alert(ex.message);
}
}
});
app.listSonicImagesService = {
viewModel: new SonicImageListViewModel()
};
}
)(window);
app.js
(function (global) {
var mobileSkin = "",
app = global.app = global.app || {};
document.addEventListener("deviceready", function () {
app.application = new kendo.mobile.Application(document.body, { layout: "tabstrip-layout" });
}, false);
app.changeSkin = function (e) {
if (e.sender.element.text() === "Flat") {
e.sender.element.text("Native");
mobileSkin = "flat";
}
else {
e.sender.element.text("Flat");
mobileSkin = "";
}
app.application.skin(mobileSkin);
};
})(window)
As I said, I'm new to Icenium and Kendo, and my javascript knowledge is limited, so I'm not quite sure where the answer lies. Any help would be greatly appreciated.
Thanks