I'm having an issue using the Google Api in my angularjs 1.3 (SPA using ui.router). Per the google api instructions, I added a reference to the client.js file with a call back in my index.html head,
<html ng-app="myApp">
<head>
<script src="Scripts/jquery-2.1.3.min.js"></script>
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/angular-ui-router.min.js"></script>
<script>
function LoadGAPI() {
}
</script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=LoadGAPI"></script>
As I understand, client.js will asynchronously load the full client api, and when complete call the defined function LoadGAPI.
Sometimes LoadGAPI is called before my angular app .run is called, and sometimes it is not. I don't mind that it loads asynchonously.. but how can I alert my angular app that it is indeed ready for use?
I faced something similar before and there are two ways of solving it, one is delaying the whole angular's bootstrapping till the other library gets loaded by triggering it manually after LoadGAPI and dom ready, something like:
var n = 0;
function LoadGAPI () {
// Only pass after the first call
if (n++) {
angular.bootstrap(angular.element(document).find('html'), ['app']);
}
};
angular.element(document).ready(LoadGAPI);
and the other one is ensuring the library's presence only for the ui-router states needing it using resolve:
State
$stateProvider
...
.state('some.state', {
url : '/some',
templateUrl: 'view/some.state.html',
controller : 'some.state',
resolve : GAPI.resolver
})
...
Resolver
var GAPI = {
ready : false,
resolver: {
api: ['$q', function($q) {
if (!GAPI.deferred) {
GAPI.deferred = $q.defer();
}
if (GAPI.ready) {
GAPI.deferred.resolve();
}
return GAPI.deferred.promise;
}]
}
};
window.LoadGAPI = function () {
GAPI.ready = true;
if (GAPI.deferred) {
GAPI.deferred.resolve();
}
};
The second one can be simplified, but I hope you get the idea.
Related
since last week I'm triying to get notifications from FCM, using Phonegap and AngularJS .
I could do it with cordova-fcm-plugin, so now I would like to get the data from the message, they suggest use this code:
FCMPlugin.onNotification(
function(data){
if(data.wasTapped){
//Notification was received on device tray and tapped by the user.
alert( JSON.stringify(data) );
}else{
//Notification was received in foreground. Maybe the user needs to be notified.
alert( JSON.stringify(data) );
}
},
function(msg){
console.log('onNotification callback successfully registered: ' + msg);
},
function(err){
console.log('Error registering onNotification callback: ' + err);
}
);
My problem was that I have no idea how to added that code to an angular controller, so I searched on internet something similar and I found this factory
angular.module('rhoAppApp')
.factory('$FCMPlugin', $FCMPlugin);
$FCMPlugin.$inject = [];
function $FCMPlugin() {
var service = {
getToken: function(successCallback, failCallback) {
FCMPlugin.getToken(successCallback, failCallback);
},
onNotification: function(onNotification, onCallbackSuccesSet, onCallbackFailSet) {
FCMPlugin.onNotification(onNotification,
onCallbackSuccesSet, onCallbackFailSet);
}
};
return service;
}
So now my problem is use that factory in my controller, I know (maybe I'm wrong) that you have to call it from:
.controller('MainCtrl', function ($FCMPlugin) {
$FCMPlugin.something
})
But I'm not sure how to use that factory, I have never used one before.
I could solve this problem with this:
I made a build using phonegap + yeoman angular, one of the problem building with this method is that you have to include cordova.js
My problema was, that i include condorva.js inside this line
<!-- build:js(.) scripts/vendor.js -->
<!-- bower:js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
<!-- endbower -->
<!-- endbuild -->
And it is a problem because you dont want to build it in vendor.js, instead I added cordova.js out of that line:
Then I added this code to app.js to indetify when you are inside of a mobile device or web:
angular.element(document).ready(function () {
if (navigator.userAgent.match(/(iOS|iPhone|iPod|iPad|Android|BlackBerry)/)) {
document.addEventListener('deviceready', function () {
console.log('This is mobile app');
angular.bootstrap(document.body, ['moodleAppApp']);
}, false);
} else {
console.log('This is web app');
angular.bootstrap(document.body, ['moodleAppApp']);
}
});
Also I remove ng-app from index.html
All this make my angular app work with cordova.
My code is given below. The below code shows dependancy error when executes following code. Any help would be great. Cookies dependancies also required...
Error is
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.3.15/$injector/modulerr?p0=achieverpayroll&p1…A%2F%2Flocalhost%3A8080%2Fachieverpayroll%2Fjs%2Fangular.min.js%3A17%3A381)
Code app.js
(function(){
var app=angular.module('achieverpayroll',['ngRoute']);
app.provider('loginChek',function(){
this.logFn=function(){
console.log('test');
};
});
app.config(['$routeProvider', '$httpProvider','loginChekProvider', function($routeProvider, $httpProvider,loginChekProvider){
loginChekProvider.logFn();
$routeProvider.when('/home',{
templateUrl: 'templates/home.html',
controller: 'categoryController'
}).
otherwise({
redirectTo: '/home'
});
}]);
app.controller('categoryController', function($scope, $http) {
});
})();
HTML:
<!DOCTYPE html>
<html ng-app="achieverpayroll">
<head>
<meta charset="ISO-8859-1">
<META http-equiv="X-UA-Compatible" content="IE=10">
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<script src="js/angular.min.js" type="text/javascript"></script>
<script type="text/javascript" src="js/angular-route.min.js"></script>
<script type="text/javascript" src="js/angular-cookies.js"></script>
<script src="js/app.js" type="text/javascript"></script>
....
Whenever you get an angular error and you could not really decode what error message means. Try to load non min version of angular and that will provide you a more descriptive error message, for example in your case you might see something like:
Uncaught Error: [$injector:modulerr] Failed to instantiate module plunker due to:
Error: [$injector:pget] Provider 'loginChek' must define $get factory method.
Which is very evident that your provider does not have a service constructor associated with it. It just defines a provider function that can be accessed during the config phase which is not enough. For example:
app.provider('loginChek',function(){
var loggedIn = false;
//This is accessible only during the config phase before the
//service loginCheck is even instantiated
this.logFn=function(){
loggedIn = true;
console.log('test');
};
//When you inject loginCheck anywhere else you will get a service instance
//with one method hasLoggedIn
this.$get = function(){
return {
//You can inject services stuffs here like
//hasLoggedIn:function($http, $q...)
hasLoggedIn:function(){
return loggedIn;
}
}
}
});
plnkr
Doc says:
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.
Provider method logFn cannot really make use of any services because the services are not instantiated yet (for example you cannot inject $http service directly in a provider function, i.e .provider('loginChek',function($http){), but you can inject other providers as you need. So they are generally used only for simple configuration for your service.
Try declaring your provider like this:
app.provider('loginChek',function(){
this.$get = function(){
return {
logFn: function() { console.log('test') }
};
};
});
This error occurs when a module fails to load due to some exception.
Have you installed the ngRoute module?
https://code.angularjs.org/1.3.15/docs/api/ngRoute
I have generated a angular app using yo angular. I then add the <script src="https://apis.google.com/js/client.js?onload=init">
</script> and
<script type="text/javascript">
function init(){
window.init();
}
</script>
to the generated index.html. In the generated controller I add
$window.init= function() {
$scope.$apply($scope.loadScoreboardLib);
};
$scope.loadScoreboardLib = function() {
var ROOT = 'https://id.appspot.com/_ah/api';
gapi.client.load('name', 'v1', function() {
$scope.isBackendReady = true;
$scope.list();
}, ROOT);
};
But when saving the file I get gapi not defined. Have I placed the code in the wrong place or what is the problem? I see that gapi isn't declared but viewing some examples it seems as no one is declaring it explicitly, so I just assumed it was google magic or the lack of knowledge I have.
How can I start fetching data from the server as quickly as possible with Angular?
Currently, most of my page is populated asynchronously via a directive "fooload" placed at the root element:
<html lang="en" ng-app="myapp" fooload ng-controller="MyAppCtrl">
<head>
/* bunch of CSS, and other resources */
</head>
Which loads data into the scope via an http GET request:
angular.module('myapp.directives').
directive('fooload', function ($http) {
return {
link: function (scope, elm, attrs) {
$http.get('/foo').success(function (data) {
scope.foo = data;
});
}
};
});
Looking at the network panel, this call is being made in the browser AFTER the requests for the resources referenced in head. How can I make the call to load /foo data as quickly as possible on page load (if possible, even before loading angular itself)?
This is not really related to Angular, obviously Angular cannot start loading files before Angular has loaded itself. But if the resource (eg /foo) is cacheable by the browser you could add it to a manifest file: http://www.html5rocks.com/en/tutorials/appcache/beginner/
I solved this by:
a) fetching the data even before angular loads and storing it in a global variable (I hate using a global variable, but I couldn't think of another way.)
b) manually bootstrapping angular upon load of this data (my app doesn't work at all without the data)
var $data;
var ajax_transport = new XMLHttpRequest();
// Callback for AJAX call
function responseProcess() {
if (ajax_transport.readyState !== 4) {
return;
}
if (ajax_transport.responseText) {
$data = JSON.parse(ajax_transport.responseText);
angular.bootstrap(document, ['myApp']);
});
}
}
// Sending request
ajax_transport.open("GET", "/mydata", true);
ajax_transport.onreadystatechange = responseProcess;
ajax_transport.send();
Note: it's important to remove the tag ng-app="myapp" in your template to avoid automatic bootstrapping.
c) Using the data in my angular app:
scope.setupSomething($data);
d) Also, to ensure that this data call begins before any other resource load, I started using a resource loader. I liked HeadJs (http://headjs.com/) the most, but the angular folks seem to like script.js (https://github.com/angular/angular-phonecat/blob/master/app/index-async.html)
Criticism or improvements welcome.
Start by creating a new service that gets the resource and then bootstraps the document for angular upon success callback from the server.
angular.element(document).ready(function() {
calllService(function () {
angular.bootstrap(document);
});
});
https://stackoverflow.com/a/12657669/1885896
So, in my Index.cshtml page, when I initially load up the page I have:
#inherits ViewPage
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="ext-all-debug.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="app.ext.js"></script>
<script type="text/javascript" src="dump.js"></script>
#ServiceStack.MiniProfiler.Profiler.RenderIncludes().AsRaw()
</head>
<body>
</body>
</html>
All good, I can see it profiling index, a bunch of ExtJS, and the 1st ajax call to my ServiceStack on server side (in /api/session).
Now, in my ExtJS form I have a Customers tab when I click it sends ajax request to /api/customers and I have a tab when I click it calls /api/orders.
But, then when I start to click on, say Customers tab, Miniprofiler does not add any subsequent ajax requests into the list any more? I thought Miniprofiler can log ajax requests nothing special needs to be done? Why is it not logging subsequent ajax requests for me? I am missing something?
I know this is a little bit old, but if anyone is interested the implementation for using miniprofiler with angularjs is as follows:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(["$q", function ($q) {
return {
'response': function (response) {
if (typeof (MiniProfiler) != 'undefined' && response.config.url.indexOf(".html") < 0) {
var stringIds = response.headers('X-MiniProfiler-Ids');
if (stringIds) {
MiniProfiler.fetchResultsExposed(angular.fromJson(stringIds));
}
}
return response || $q.when(response);
}
};
}]);
}]);
The current version available through Nuget doesn't support intercepting ExtJS ajax calls.
It seems that there is a pull request for that feature, but it isn't available yet.
Here's what I had to do to get around that:
Ext.require('Ext.Ajax');
Ext.onReady(function () {
Ext.Ajax.on('requestcomplete', function (e, xhr, settings) {
if (typeof (MiniProfiler) != 'undefined') {
var stringIds = xhr.getResponseHeader('X-MiniProfiler-Ids');
if (stringIds) {
var ids = typeof JSON != 'undefined' ? JSON.parse(stringIds) : eval(stringIds);
MiniProfiler.fetchResultsExposed(ids);
}
}
});
});