Using ngCordova plugins without calling them in app.js? - angularjs

My app is looking good, thanks to Ionic. All the core info is there and I'm just adding the frills - email, sharing, media (one of the functions is a metronome) and so on.
I can't get any plugins to work.
I've had success with a previous Ionic app but the plugins were all called from within
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
}
}
and indeed the Statusbar plugin seems to working fine and it is called from within there.
I'm using the Side Menu starter with tabs built in btw.
My issue, I suppose, is that I've three controller files.
main_ctrls.js - for the main app
menu_ctrls.js - for the menu pages like feedback and email, analytics
extras_ctrls.js - for the "extra" section with the metronome and so on.
I've put 'ngCordova' as a dependency in each module and called the plugin from within the controller with the ready function. Here is the email controller.
angular.module('menu.controllers', ['ngCordova'])
.controller('FeedCtrl', function($ionicPlatform, $scope, $cordovaEmailComposer) {
$ionicPlatform.ready(function() {
$cordovaEmailComposer.isAvailable().then(function() {
// is available
alert('Email is available');
}, function () {
// not available
alert('Email is NOT available');
});
var email = {
to: 'max#mustermann.de',
cc: 'erika#mustermann.de',
bcc: ['john#doe.com', 'jane#doe.com'],
attachments: [
'file://img/logo.png',
'res://icon.png',
'base64:icon.png//iVBORw0KGgoAAAANSUhEUg...',
'file://README.pdf'
],
subject: 'Cordova Icons',
body: 'How are you? Nice greetings from Leipzig',
isHtml: true
};
$cordovaEmailComposer.open(email).then(null, function () {
alert('Email discarded.');
});
})
});
I'm testing it on Android (Nexus 4 with Android 5.1) with Chrome inspect and I just get an error saying "Cannot read property 'isAvailable' of undefined". Needless to say, the alerts don't pop up.
This happens with all plugins called from within controllers in this way.
What am I doing wrong?

It seems like you are invoking the plugins before the cordova device ready is fired. In my angularjs application I have done the following.
1. Removed ng-app from html and did manual bootstrap through script
2. Added cordova.js file to the dependency. ( As the last dependency. After ng-cordova js)
3. Placed the cordova.js in the same folder as that of the index.html. (No explanation for why. From any other location, simply it was not getting added. May be something specific pertaining to cordova.)
4. Added the following script to the index.html
<script type="text/javascript" language="text/javascript">
$(document).ready(function() {
document.addEventListener("deviceready", onDeviceReady, false);
});
onDeviceReady = function() {
alert("hello!");
angular.element(document).ready(function() {
angular.bootstrap(document, ["main"]);
});
};
</script>
Here "main" is my main angularjs module. This ensures that the app is loaded only after the device ready event is fired by cordova and all cordova related functions are available. Specific to ionic I donot have anycode. May be the portion where ionic bootstraps the app can be put instead of angular.bootstrap.
My assumptions: you have added the plugins to your cordova project through the command
cordova plugin add <plugin-location>

index.html ng-cordova include are okay if you can use ngCrdova plugins in app.js, I think ng-cordova is bad injected across angular dependencies. Try this:
app.js
controllers.js
adding ng-cordova to project involves adjusting the module definition files like:
app.js
angular.module('startapp', ['ionic','ngCordova','startapp.controllers'])
controllers.js
angular.module('startapp.controllers', [])
.controller('AppCtrl', function($scope,$cordovaEmailComposer) {
var email = {
to: 'max#mustermann.de',
cc: 'erika#mustermann.de',
bcc: ['john#doe.com', 'jane#doe.com'],
attachments: [
'file://img/logo.png',
'res://icon.png',
'base64:icon.png//iVBORw0KGgoAAAANSUhEUg...',
'file://README.pdf'
],
subject: 'Cordova Icons',
body: 'How are you? Nice greetings from Leipzig',
isHtml: true
};
$cordovaEmailComposer.open(email).then(null, function () {
// user cancelled email
});
})
Only include ngCordova in app.js app definition.

Related

How to call cordova plugin in ionic v1

I was installed cordova-plugin-media in ionic v1 . But media is not define by the app when I running it in the browser .
ionic.bundle.js:26794 ReferenceError: Media is not defined
at ChildScope.$scope.playPodcast (controllers.js:1405)
at fn (eval at compile (ionic.bundle.js:27638), <anonymous>:4:232)
at ionic.bundle.js:65427
at ChildScope.$eval (ionic.bundle.js:30395)
at ChildScope.$apply (ionic.bundle.js:30495)
at HTMLElement.<anonymous> (ionic.bundle.js:65426)
at defaultHandlerWrapper (ionic.bundle.js:16787)
at HTMLElement.eventHandler (ionic.bundle.js:16775)
at triggerMouseEvent (ionic.bundle.js:2953)
at tapClick (ionic.bundle.js:2942)
and this is my code
$scope.playPodcast = function($audioId) {
new Media("http://www.viaviweb.in/envato/cc/online_mp3_app_demo/uploads/40655_Overboard.mp3").play();
}
Just a quick search to that plugin's github page shows the way to use that method.
Specifically if you want to play a media file, this is the correct way to use it.
function playAudio(url) {
// Play the audio file at url
var my_media = new Media(url,
// success callback
function () { console.log("playAudio():Audio Success"); },
// error callback
function (err) { console.log("playAudio():Audio Error: " + err); }
);
// Play audio
my_media.play();
// Pause after 10 seconds
setTimeout(function () {
my_media.pause();
}, 10000);
}
Ok, depending on how you have the script file injected, you need to call it one of two ways:
If the media plugin is being loaded as a script file that is in your index.html by itself and it attaches itself to the global namespace, then add the following to your app.js:
angular.module('Media', [])
.factory('Media', function () {
return window.Media;
});
Later, in your app.js module definition, add the following:
angular.module('myApp',
[
'ionic',
'Media'
])
.run(
[
'ionicReady',
'Media',
function (
ionicReady,
Media,
) {
//Media initialization code here
}
This allows angular to use its Dependency Injection to ensure "Media" gets initialized in your main module. You'll have to import it to your other modules if you want to use it somewhere else in your application.
If you're using NgCordova, which provides angular wrappers for common Cordova plugins, then you'd import it the same way you'd import any other AngularJS library. There's sample code for the media plugin here.

Unable to show Toast message using Ionicframework

I am extremely new to the world of mobile development and I am working with ionic framework.
All I am trying to do is to display a toast message to the user by following this tutorial and so far I am just going crazy trying to implement it.
The error I get is as following
Cannot read property 'toast' of undefined
I have installed cordova
I have installed the Toast plugin
inside my index.html I have added the script of ng-cordova.min.js
<script src="lib/ngCordova/dist/ng-cordova.min.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
Do i need to add the Toast.js file in index.html too? If yes then that does not help either and leads to another error.
This is my controller
.controller('UsersController', ['$scope', '$http', '$cordovaToast', function ($scope, $http, $cordovaToast) {
$scope.showToast = function() {
$cordovaToast
.show("Here's a message", 'short', 'center')
.then(function(success) {
console.log('Success');
}, function (error) {
console.log('Error');
});
};
}
]);
What am i missing here?
I will really appreciate any help.
UPDATE
After making changes, suggested by #Del, the following error appears
ionic.bundle.js:25642 Error: [$injector:unpr] Unknown provider: $cordovaToastProvider <- $cordovaToast <- UsersController
http://errors.angularjs.org/1.4.3/$injector/unpr?p0=%24cordovaToastProvider%20%3C-%20%24cordovaToast%20%3C-%20UsersController
at ionic.bundle.js:13380
at ionic.bundle.js:17574
at Object.getService [as get] (ionic.bundle.js:17721)
at ionic.bundle.js:17579
at getService (ionic.bundle.js:17721)
at invoke (ionic.bundle.js:17753)
at Object.instantiate (ionic.bundle.js:17770)
at ionic.bundle.js:22326
at self.appendViewElement (ionic.bundle.js:56883)
at Object.switcher.render (ionic.bundle.js:54995)
If the plugin is correctly installed, I have used it without using $cordovaToast
.controller('UsersController', ['$scope', '$http', function ($scope, $http) {
$scope.showToast = function() {
window.plugins.toast
.show("Here's a message", 'short', 'center')
.then(function(success) {
console.log('Success');
}, function (error) {
console.log('Error');
});
};
}
]);
You dont have to add the ng-cordova or toast.js.
If you add the plugin (ionic plugin add ...), remove the platform, add again, and build, it should work
You are trying to run $cordovaToast on browser. It will not work because it is a native plugin. Please use it on a real device or emulator.
I am also new in ionic but I have little knowledge about android so then I found the way how to use android functions in ionic means I found the way to create own plugins from here.
so after following steps from the given link I have created an own plugin
you can see it ionic plug # github.
you need to follow simple 4 steps mentioned at git link.
hopefully, it will help you to sort out the same problem.
This error will not go away on the real device as well unless you inject the dependency for $cordovaToast. You may use or may remove $cordovaToast in the controller and it will not affect the working. It is good practice to keep dependencies. The crucial step which is missing in all the responses is to introduce DI for ngCordova in the module to which UsersControllers belongs.
The example highlighted by JSalaat has this controller
foodShop.controller('cartController', function($scope, cartFactory,
$cordovaToast)
and the foodshop module has injected ngCordova.
var foodShop = angular.module('foodShop',
['ionic','firebase','ngCordova'])
As the plug-in belong to ngCordova it does not need to be introduced separately in the controller. This explains why there is no error in that application.
in your case try the app instance creation could look like
var app = angular.module('app', ['ionic','ngCordova'])
if not you will continue to have the Unknown provider: $cordovaToastProvider error
For the record: For Ionic v2/v3
Install dependencies
Include it in ionic project
How to use it.
1. Install dependencies
Within CLI run below commands:
$ ionic cordova plugin add cordova-plugin-x-toast
$ npm install --save #ionic-native/toast
2. Include it in ionic project
1.Add below to app.module.ts
import { Toast } from '#ionic-native/toast';
....and to #NgModule section providers:[ HERE,]
2.Each page where you want to use Toast you need to add:
import { Toast } from '#ionic-native/toast';
....also add to constructor
constructor(private toast: Toast, ...){}
...now you can use it as below example:
this.toast.show('message', 'duration', 'position').subscribe();
...or sending message to console:
this.toast.show('message', 'duration', 'position').subscribe(
toast=>{
console.log(toast);
}
);

Using RequireJS with AngularJS. Problems loading AngularJS

I am creating a NodeJS app which uses AngularJS for it's front-end. I am Also using RequireJS to load in the JS dependencies and then instantiate the Angular app. Here is what I am trying to do:
Within my HTML file (written in Jade) I include the RequireJS files and then call the RequireJS config using the 'data-main' attribute:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
script(type="text/javascript" src="/bower_components/requirejs/require.js" data-main="/main.js")
My main.js file looks as follows:
"use strict";
function(require) {
require(['/assets/requiredPathsAndShim.js'], function(requiredPathsAndShim) {
require.config({
maps : {
// Maps
},
paths : requiredPathsAndShim.paths,
shim : {
// Modules and their dependent modules
}
});
angular.bootstrap(document, ['appNameInHere']);
});
})(require);
I have an external file which contains an object with my routes '/assets/requiredPathsAndShim.js' and it looks like follows:
"use strict";
(function(define) {
define([], function() {
return {
paths : {
'angular' : '/bower_components/angular/angular'
}
};
});
})(define);
I will add that my NodeJS/Express app has the 'bower_components' folder set to serve static files and this is working fine.
Whenever I try and instantiate the AngularJS app using the 'angular.bootstrap...' method it tells me Angular is not defined. I can't see why this is happening and haven't been able to figure it out yet. O can't see any problem with my routes to the Angular files. Can anyone see or suggest why this may be happening?
Thanks!
Just managed to crack it! I had to place the 'angular.bootstrap' call in a callback function of the require.config method as the app was trying to call AngularJS before it had been defined.
Hope this helps anyone in the future.

How to pick multiple images from device?

If i create a simple project:
ionic start MyApp
And add the ImagePicker plugin:
ionic plugin add https://github.com/wymsee/cordova-imagePicker.git -save
And simply copy this example www folder into the project and do:
ionic platform add android
ionic build android
ionic run android
Everything is working fine. I can pick multiple images as intended without getting any errors.
So far so good. Now i tried to include that into my project so i added the ImagePicker plugin. Now this is my plugin list:
ionic plugin ls
com.synconset.imagepicker 1.0.6 "ImagePicker"
cordova-plugin-camera 1.1.0 "Camera"
cordova-plugin-device 1.0.0 "Device"
cordova-plugin-dialogs 1.1.0 "Notification"
cordova-plugin-splashscreen 2.0.0 "Splashscreen"
cordova-plugin-statusbar 1.0.0 "StatusBar"
cordova-plugin-vibration 1.1.0 "Vibration"
cordova-plugin-whitelist 1.0.0 "Whitelist"
I created a new module:
angular.module('App.ImageSelect', [])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state('app.imageSelect', {
url: "/products/prints/pola/imageSelect",
views: {
'menuContent': {
templateUrl: "modules/products/prints/pola/imageSelect/imageSelect.html",
controller: 'ImageSelectController'
}
}
});
})
.controller('ImageSelectController', function ($scope, $cordovaImagePicker) {
$scope.images = [];
$scope.selectImages = function () {
$cordovaImagePicker.getPictures(
function (results) {
for (var i = 0; i < results.length; i++) {
console.log('Image URI: ' + results[i]);
$scope.images.push(results[i]);
}
if (!$scope.$$phase) {
$scope.$apply();
}
},
function (error) {
console.log('Error: ' + error);
}
);
};
});
As you can see it is EXACTLY the SAME controller which i copied from here which worked on the simple test project.
For any suspect reason this is NOT working. I always get the error:
TypeError: Cannot read property 'getPictures' of undefined
So what's the point of that? Im using EXACT the same code in both projects. In one everything is working and in the other nothing is working. I tried all the examples described here but its always the same.
I checked your project and your index.html is missing cordova.js . So none of your plugins are getting loaded or initialized.
Just add the below line in you index.html below where you load ng-cordova.js.
<script src="cordova.js"></script>
On you example your are injecting $cordovaCamera, however the iconic uses $cordovaImagePicker. Also , in your example your using the object imagePicker from the window object. I don't the window object is what you want.
Try injecting the correct dependency $cordovaImagePicker and use the method $cordovaImagePicker.getPictures from it instead.

Cordova + Angularjs + Device Ready

I am developing a mobile application using Cordova and AngularJS. How do I restrict bootstrapping of AngluarJS before Cordova device ready. Basically I don't want to use any of AngularJS controllers before device ready.
Manually bootstrap your Angular app:
Remove your ng-app attribute from your HTML code, so Angular doesn't start itself.
Add something like this to you JavaScript code:
document.addEventListener("deviceready", function() {
// retrieve the DOM element that had the ng-app attribute
var domElement = document.getElementById(...) / document.querySelector(...);
angular.bootstrap(domElement, ["angularAppName"]);
}, false);
Angular documentation for bootstrapping apps.
I'm using the following solution, which allows AngularJS to be bootstrapped when running with Cordova as well as when running directly in a browser, which is where much of my development takes place. You have to remove the ng-app directive from your main index.html page since that's what the manual bootstrapping is replacing.
UPDATE: I've since switched to the following method, which I think is cleaner. It works for Ionic as well as vanilla Cordova/PhoneGap. It should be the last bit of JavaScript to run - perhaps inside a script tag before the /body tag.
angular.element(document).ready(function () {
if (window.cordova) {
console.log("Running in Cordova, will bootstrap AngularJS once 'deviceready' event fires.");
document.addEventListener('deviceready', function () {
console.log("Deviceready event has fired, bootstrapping AngularJS.");
angular.bootstrap(document.body, ['app']);
}, false);
} else {
console.log("Running in browser, bootstrapping AngularJS now.");
angular.bootstrap(document.body, ['app']);
}
});
Here's the older solution I used:
// This is a function that bootstraps AngularJS, which is called from later code
function bootstrapAngular() {
console.log("Bootstrapping AngularJS");
// This assumes your app is named "app" and is on the body tag: <body ng-app="app">
// Change the selector from "body" to whatever you need
var domElement = document.querySelector('body');
// Change the application name from "app" if needed
angular.bootstrap(domElement, ['app']);
}
// This is my preferred Cordova detection method, as it doesn't require updating.
if (document.URL.indexOf( 'http://' ) === -1
&& document.URL.indexOf( 'https://' ) === -1) {
console.log("URL: Running in Cordova/PhoneGap");
document.addEventListener("deviceready", bootstrapAngular, false);
} else {
console.log("URL: Running in browser");
bootstrapAngular();
}
If you run into problems with the http/https detection method, due to, perhaps, loading a Cordova app into the phone from the web, you could use the following method instead:
function bootstrapAngular() {
console.log("Bootstrapping AngularJS");
// This assumes your app is named "app" and is on the body tag: <body ng-app="app">
// Change the selector from "body" to whatever you need
var domElement = document.querySelector('body');
// Change the application name from "app" if needed
angular.bootstrap(domElement, ['app']);
}
// This method of user agent detection also works, though it means you might have to maintain this UA list
if (navigator.userAgent.match(/(iOS|iPhone|iPod|iPad|Android|BlackBerry)/)) {
console.log("UA: Running in Cordova/PhoneGap");
document.addEventListener("deviceready", bootstrapAngular, false);
} else {
console.log("UA: Running in browser");
bootstrapAngular();
}
Note that you still need the same bootstrapAngular function from the first example.
Why manually bootstrap AngularJS with Cordova/PhoneGap/Ionic?
Some people getting here might not know why you would want to do this in the first place. The issue is that you could have AngularJS code that relies on Cordova/PhoneGap/Ionic plugins, and those plugins won't be ready until after AngularJS has started because Cordova takes longer to get up and running on a device than the plain old Javascript code for AngularJS does.
So in those cases we have to wait until Cordova/PhoneGap/Ionic is ready before starting up (bootstrapping) AngularJS so that Angular will have everything it needs to run.
For example, say you are using the NG-Persist Angular module, which makes use of local storage for saving data on a browser, iOS Keychain plugin when running on iOS, and the cordova-plugin-file when running on Android. If your Angular app tries to load/save something right off the bat, NG-Persist's check on window.device.platform (from the device plugin) will fail because the mobile code hasn't completed startup yet, and you'll get nothing but a white page instead of your pretty app.
If you are using Ionic, this solution works for browsers and devices. Credit to romgar on this thread.
window.ionic.Platform.ready(function() {
angular.bootstrap(document, ['<your_main_app']);
});
Still need to remove ng-app from your DOM element.
This solution became more robust when I used:
angular.element(document).ready(function () {
var domElement = document.getElementById('appElement');
angular.bootstrap(domElement, ["angularAppName"]);
});
UPDATE
My suggestion was to put the above within the appropriate deviceready function, e.g.:
document.addEventListener("deviceready", function() {
angular.element(document).ready(function () {
var domElement = document.getElementById('appElement');
angular.bootstrap(domElement, ["angularAppName"]);
});
}, false);
On using the solution from TheHippo:
document.addEventListener("deviceready", function() {
// retrieve the DOM element that had the ng-app attribute
var domElement = document.getElementById(...) / document.querySelector(...);
angular.bootstrap(domElement, ["angularAppName"]);
}, false);
It doesn't work in the browser because "cordova.js" gets resolved by the Cordova or Phonegap building process and is not available in your localhost or emulated testing environment.
Thus the "deviceready" event is never fired. You can simply fire it manually in your browsers console.
var customDeviceReadyEvent = new Event('deviceready');
document.dispatchEvent(customDeviceReadyEvent);
Also make sure, that the bootstrap of angular gets triggered after setting all of you angular modules/controllers/factories/directives etc.
In most cases you probably don't need to block loading your angular app until after deviceready (mind that it can take several seconds for deviceready to fire if you have a lot of plugins).
Instead you can use something like this lib (https://github.com/arnesson/angular-cordova) which solves the deviceready issues for you by automatically buffering calls and then execute them after deviceready has been fired.

Resources