Unable to use Cordova Plugin - angularjs

I have an AngularJS app that I want to deploy as an app to mobile devices. I had heard about Cordova (and its AngularJS counterpart ngCordova). I will be using multiple Cordova plugins. The first one I'm trying is to detect if the user is online or not. To do that, I'm using the cordova-network-informtion plugin in the following controller via ngCordova:
'use strict';
myApp.controller('MyController', function($scope, $cordovaNetwork) {
$scope.isOnline = null;
$scope.init = function() {
// Detect if the user is on a network
console.log($cordovaNetwork.isOnline());
$scope.isOnline = $cordovaNetwork.isOnline();
console.log($scope.isOnline);
};
$scope.init();
});
When the init function gets called, I see the following in the console:
Object {getNetwork: function, isOnline: function, isOffline: function}
TypeError {stack: (...), message: "Cannot read property 'type' of undefined"}
That type error is printed thanks to global error handler. Either way, it is a result of calling $scope.isOnline = $cordovaNetwork.isOnline();. I don't understand what I'm doing wrong.
I believe the root cause is that I'm not referencing cordova.js in any way. All of the examples I see reference cordova.js. However, when I look at the package, I only see vendor specific implementations of Cordova. For instance:
cordova.windowsphone.js
cordova.android.js
cordova.ios.js
That makes sense from a deployment perspective. However, I'm still trying to do development in my browser. For that reason, I was thinking I could use ngCordova. I also thought there would be a generic cordova.js that served as an abstraction. However, I don't see one. Can someone please help me get over this hump? I sincerely appreciate it.

Your problem is, like you mentioned in your last paragraph, that you are trying to use Cordova Plugins within your browser.
This is not possible because here is no phonegap abstraction layer for your browser.
So i think you have some opportunities:
The most reliable would be to deploy it every time on your device an test it there.
Yes i know, that always takes a few seconds and is not the best if you are trying a lot of different thinks.
Another option could be to create your own mocked $cordovaNetwork in ngCordovaMocks.
Example:
angular.module('ngCordovaMocks', [])
.factory('$cordovaNetwork', [function () {
return {
getNetwork: function () {
return "Edge"
},
isOnline: function () {
return true;
},
isOffline: function () {
return false
}
}
}]);
In the app.js you then include your ngCordovaMocks instead of ngCordova and all services will be mocked ( Be sure, that only your mocked services will be available and not all ngCordova functionalities).
angular.module('myApp', ['ngCordovaMocks']);
Yes, this is a lot of work and you have to change it before your deployment. And don't forget: It's just a mock for local development. It's essential to test it on your device with the ngCordova module and cordova device connection.
Another option would be to use the Ripple Emulator , which offers some Cordova features in your browser. But i don't know if the connection is a supported one.
But then you have to integrate the cordova.js file to your index.html.
I don't what the differences between the vendor specific files are, but you should download the plain and neutral cordova.js and include it.

First off, ngCordova isn't the counterpart to cordova.js. ngCordova is a set of extensions that are meant to be used on top of Cordova. You still have to use Cordova in your app to be able to deploy your app to mobile devices.
I would recommend taking a look at ionicframework.com. The makers of ngCordova also built Ionic and it will provide you with all of the tools that you would need to be able to build out a mobile app with angular.js.

Related

Django REST Framework + django-rest-auth: Error during setup of Angular helper module

I'm trying to setup the angular-django-registration-auth AngularJS module to help smooth the login/logout process for my in-progress web app, which has an AngularJS frontend consuming a Django REST Framework API and django-rest-auth for authentication/registration.
The rest-auth endpoints for login and logout work just fine, however I'm having issues injecting the Angular helper module as described on the module's github page. I've added the requisite dependency to my main app declaration:
var app = angular.module('myApp', ['ui.router', 'ngRoute', 'xeditable', 'angularDjangoRegistrationAuthApp']);
But I get several of the following errors on load:
Uncaught Error: [$injector:nomod] http://errors.angularjs.org/1.5.0/$injector/nomod?p0=angularDjangoRegistrationAuthApp
This error seems pretty clear initially- that the app hasn't been declared, however I'm not sure how to do so beyond the injection above (I'm new to a lot of this in general, and definitely the frontend part). Even if I remove the angularDjangoRegistrationAuthApp dependency from the var app = declaration above, I still get instances of the $injector:nomod error, which seem to originate from the included djangoAuth.js file that contains all of the helper functions, and comes straight from the provided module.
The module repo hasn't been active since early last year, but a recently opened issue notes some changes that have to be made for Angular 1.4+ (I'm using 1.5) so it seems that it largely still works. I made those syntax changes but still hit the error. Have I neglected to do something simple as far as declaring the auth helper app?
I know this app has it's own dependencies, so could that be what I missed? I thought the files I added would handle those, so I haven't installed anything outside of angularDjangoRegistrationAuthApp
I ended up figuring this out, I believe it's related to something with my development environment (Windows, Python 3.4, Visual Studio 2015 + Python Tools for Visual Studio).
I simply declared the angularDjangoRegistrationAuthApp at the top of my JS file, above the line where I declared my own app with the registration app as a dependency. So it looks like this:
angular.module('angularDjangoRegistrationAuthApp', []);
var app = angular.module('myApp', ['ui.router', 'ngRoute', 'xeditable', 'angularDjangoRegistrationAuthApp']);
I'm not sure why this is necessary, as the person I'm working with (not using VS + PTVS) doesn't require the extra declaration in order to successfully load the module. I've had to add similar declarations for a couple other Angular modules I'm using, while my friend has had no issue simply adding them as dependencies in the main app declaration.

Webpack with angular 1.x and ES5

After reading hundreds of lines about browserify vs webpack and several how to of both I decided to go for webpack. The main reason it's because I liked the idea of bundling everything into a js file.
I have an angular project already working and I want to refactor it for webpack. The problem? My project is using angular 1.4.7, ng-animate and plain javascript (ES5) and all the tutorials and manuals are for ES6. I don't want to refactor my project so much. What's the way to go? I would like an example of each angular module : factory, directive, controller and so on. Many thanks
I typically have a feature.module.js file which has my module definition and requires all of the directives / services contained within the module. Also has the external dependancies.
/* module.js */
angular.module('my.module',['dependancy1', 'dependancy2']);
//External libraries
require('./dependancy1.module.js');
require('./dependancy2.module.js');
//Internal components
require('./thing.directive');
require('./thing.service';
/* service.js */
angular.module('my.module')
.directive('yourDir', function myDir(){...});
I'm dealing with the same problem now. And I found something that works (work in progress, but at least I can see progress). My steps:
Install yeoman
Run this angular-webpack generator. Select 'ES5' when asked (the other option is 'ES2015', which I guess is the same that 'ES6')
Start modifying the automatically generated boilerplate with your Angular code
Yes, you still need to learn about gulp and sass, but at least you can run a simple AngularJS app using the old ES5 syntax, and start modifying it.
I'm probably blogging about this. So, I'll update this answer then.
I tend to do this:
app.js:
require('/any/angular/deps');
var subModule = require('/some/sub/module');
var app = angular.module('myApp', []);
// pass the app module in sub modules to allow them to define their own config
subModule.configure(app);
/subModule/module.js:
var someSubDirective = require('./subDir/directive');
export function configure(app) {
someSubDirective.configure(app);
}
/subModule/subDir/directive.js:
export function configure(app) {
app.directive('myDir', myDir);
}
function myDir() {
}
My idea is to let all sub modules handle their own configuration, so declaring config or constant, factories or providers. Letting this then bubble up to the app.js. This means its really easy to delete a folder from your structure, because it is one line removal from it's parent module.
This also makes relevant file paths a lot shorter and easier to handle.

ngCordova PROGRESS INDICATOR doesn't works

I'm trying create ionic app project with ngCordova plugin progress indicator, but it doesn't works. Somone know How to do to make it work ?
angular.module('starter')
.controller('MyController',
function ($scope,$ionicPlatform, $state, $cordovaProgress, PopupService, $cordovaCamera) {
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
}
$scope.login = function()
{
$cordovaProgress.showDeterminateWithLabel(true, 50000, "Loading");
}
If we look at the official ngCordova documentation found here:
http://ngcordova.com/docs/plugins/progressIndicator/
It says that it works for Android and iOS, however as of right now, this is not true.
Let's dig a big deeper.
ngCordova is just a wrapper for Apache Cordova plugins, so if we visit the plugin developers page found here:
http://paolobernasconi.com/cordova-progressIndicator/
It says that only iOS is supported and Android is coming soon. However, this is not entirely true either. I personally made a revision to ngCordova found here:
https://github.com/driftyco/ng-cordova/commit/67f5f0dd2359aee3e53b0adf91c2f6c0d2c30854
The only Android ProgressIndicator commands are show and hide.
Example:
$cordovaProgress.show(message)
This might change in the future (or already has?), but as of right now there are plenty of iOS commands for ProgressIndicator, but only two for Android.
I suggest tracking the module to see if it changes since it is still alpha.
Regards,
I tried $cordovaProgress.show(message) - $cordovaProgress.show("Searching...") to be exact and it's still not working on Android.
Tested on both android emulator and physical Asus zenphone.
However definitely working for IOS.

Cordova + Angular: How to test?

I've just recently started fooling around with Cordova for a mobile App. For now the code base is quite small. I've also used AngularJS to drive my javascript. Now that I have reached a stable state, I would like to investigate ways to unit test the code I just wrote. Thing is, I'm not finding any useful resource for the pair. Angular suggests either Karma (unit) or Protractor (scenarios), but I'm finding quite hard to bootstrap them both with a Cordova App, since this is not supposed to run inside the browser, but within some kind of container where cordova can be loaded. Are there already some good test-driven approaches in the open source market regarding test driven development of hybrid apps?
I think that correct approach would be to have cordova.mocks.js included in tests that will mock out cordova dependencies. And then unittest as usual.
I think there is no way at the moment to test the parts of cordova that would call functionality from plugins.
But you could use Karma or Protractor as you would in the browser (eventually with some mocks for cordova and cordova plugins), which require some additional if conditionals to run the app without a physical device
Ie if (window.cordova && cordova.plugins.thePluginExample) { /* Code that uses plugins [...] */ }
You can use "phonegap server" even if you're using cordova, also you can run on the device with cordova run <platform> --device.
You can track issues on the CLI output of both methods.
To help others who get here with the same question as I did...
You probably don't need to bootstrap with Cordova. Use mocks as stand-ins.
Since Cordova attaches to window, you can write your app code to inject $window and mock cordova with with standard mocking.
Example with mocha / chai:
/**
* Test case for AngularJS module that does something when platform = 'ios'
*/
describe('platform = "ios"', function() {
var $window;
beforeEach('inject', inject(function(_$window_) {
$window = _$window_;
$window.cordova = {
platformId: 'ios',
}
}));
it('verifies cordova mock platform = "ios"', function() {
expect($window.cordova.platformId).to.equal('ios');
});
it('does something', function() {
// ...
});
});

Loading mocks into an AngularJS unit test

I'm trying to setup my AngularJS application to test out controllers, routes, templates and so on, but I'm having an issue getting some of the helper methods provided by the angular-mocks.js to work (namely module and inject).
I'm using testacular to load up the test suite with the following files added before the specs:
files = [
MOCHA,
MOCHA_ADAPTER,
'../application/lib/angular.min.js',
'./lib/angular/angular-mocks.js',
'./lib/angular/angular-scenario.js',
'../application/application.js',
'./lib/chai.js',
'./lib/chai-should.js',
'./lib/chai-expect.js',
'./spec/**/*.js'
];
So far so good, but when I run the tests I get this issue:
ReferenceError: Can't find variable: module
Not sure where this is loaded. Am I missing something?
First thing to check is that all those files are getting loaded in the test browser. It's surprisingly easy to get a path wrong in your config and not realize it. If you're running testacular with autowatch, you can navigate to http://localhost:9876/context.html with a browser and use developer tools inspect elements/resources/network and see if anything is missing.
If everything is good there and you're still having problems, post some of your test code and I'll take a look.
UPDATE: It appears (strangely) from the comments in the source for angular-mocks.js (line 1635) that window.module is only available with Jasmine. It looks like you're using Mocha instead of Jasmine. This is very likely the culprit.
ANSWER:
I can't rightly take credit for this Matsko, since you figured it out yourself... but it turns out that the current AngularJS stable download and angular-seed contain an older version of ngMock that doesn't support Mocha. Manually replacing the mock file with the latest from the github repo solves the problem. Glad I could help ;-)
I ran into this issue today and I wanted to provide others with a complete summary of the required steps to get this working. First let's say you have a module named myApp. Inside that that module there is a service called myModel. the myModel service has a method named getItems().
Currently, the angular-mocks.js (I am using AngularJS 1.0.6) does not support Mocha. You will need to visit this link and replace the 1.0.6 version with the one in the master branch from the AngularJS GitHub project. An easy way to do this (if you have wget) is wget https://raw.github.com/angular/angular.js/master/src/ngMock/angular-mocks.js in the correct directory. If you use a properly configured Sublime or vim it can also easily pull it down for you.
Make sure your karma.conf.js file includes the angular-mocks.js file in files array
Somewhere in your tests.js file (maybe at the top level describe) include beforeEach(module('myApp')); or whatever you named your main module.
If you plan to use the service (or whatever you want to include in the test) in more than one place you can call another beforeEach where needed like this:
beforeEach(inject(function(myModel) {
mymodel = myModel;
}));
otherwise you just can inject where it is needed. Now the mymodel variable (notice this is the variable you assigned in the beforeEach above) will be available to you for testing in your next blocks. For example, you can now write:
describe('when fetched', function() {
it('should return 3 items', function() {
// console.log(mymodel.getItems());
expect(mymodel.getItems()).to.have.length(3);
});
});

Resources