I'm a bit frustrated because I can't figure out whats up with the AngularJS $log service. I don't use it often but I have it working on another part of my site, the only reason I could think it wouldn't be working would be something to do with the block scope inside the then function. In my console I get the following error when trying to run $log.debug:
TypeError: $log.debug is not a function
at analysis.client.controller.js:23
at processQueue (angular.js:14551)
at angular.js:14567
at Scope.$get.Scope.$eval (angular.js:15830)
at Scope.$get.Scope.$digest (angular.js:15641)
at angular.js:15869
at completeOutstandingRequest (angular.js:5387)
at angular.js:5659
Heres my analysis.client.controller.js file:
'use strict';
angular.module('analysis').controller('AnalysisController', ['$scope', '$timeout', '$mdSidenav', '$mdComponentRegistry', '$log', 'Authentication',
function($scope, $timeout, $mdSidenav, $mdComponentRegistry, $log, Authentication) {
$scope.user = Authentication.user;
// Option #1
//
// $scope.isOpen = function() { return $mdSidenav('right').isOpen(); };
// $scope.toggle = function() { $mdSidenav('right').toggle() };
// Option #2 - See https://github.com/angular/material/issues/974
$scope.toggle = angular.noop;
$scope.isOpen = function() {
return false;
};
$scope.toggleLeft = function() {
$mdSidenav('left').toggle()
.then(function() {
$log.debug('toggle left is done');
});
};
}
]);
Thanks in advance for any help!
The debug method is not enabled by default because not all browsers support console.debug, but you can enable it in the configuration phase of your app with the $logProvider.
'use strict';
angular.module('analysis')
.config(function($logProvider){
$logProvider.debugEnabled(true);
})
.controller('AnalysisController', function(
$scope,
$timeout,
$mdSidenav,
$mdComponentRegistry,
$log,
Authentication
) {
$scope.user = Authentication.user;
// Option #1
//
// $scope.isOpen = function() { return $mdSidenav('right').isOpen(); };
// $scope.toggle = function() { $mdSidenav('right').toggle() };
// Option #2 - See https://github.com/angular/material/issues/974
$scope.toggle = angular.noop;
$scope.isOpen = function() {
return false;
};
$scope.toggleLeft = function() {
$mdSidenav('left').toggle().then(function() {
$log.debug('toggle left is done');
});
};
});
$log's debug method is disabled by default. You need to enable $log from app config phase like below.
app.config(function($logProvider){
$logProvider.debugEnabled(true);
});
FYI, I got this same error when I inadvertently reassigned the debug method instead of calling it.
$log.debug = 'My log message'
Instead of:
$log.debug('My log message')
After browsing to the page that had the bad statement, I would get "TypeError: $log.debug is not a function" on my other pages that had log statements.
Related
So I have tried the following templates trying to integrate this:
HTML:
<google-sign-in-button button-id="login-button" options="options"></google-sign-in-button>
CSS:
.directive('googleSignInButton', function() {
return {
scope: { buttonId: '#', options: '&' },
template: '<div></div>',
link: function(scope, element, attrs) {
var div = element.find('div')[0];
div.id = attrs.buttonId;
gapi.signin2.render(div.id, scope.options());
}
};
})
--
I've also just tried doing this in the header and using the regular sign in button:
HTML:
<div class="g-signin2" data-onsuccess="onSignIn"></div>
IN THE HEADER:
<script>
window.onLoadCallback = function(){
gapi.auth2.init({
client_id: '123.apps.googleusercontent.com'
});
}
</script>
No matter what I do, i can't figure out how to log a user out. In my controller, when i try and do gapi.auth.signOut(); it says gapi is undefined
EDIT:
I've also tried dabbling in this to log a person out on run but ideally i'd want to make a log out work anywhere and not just when the page loads. I just don't really know where to put it or the correct way to make it happen:
.run(function ($rootScope, $state) {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init();
auth2.then(function(){
auth2.signOut();
});
});
})
EDIT #2:
I also tried to create this factory with a resolve on my ui-router but it's not getting the data in time or at all
.factory('Auth', function($http, $state, $q, $rootScope) {
var factory = { loggedIn: loggedIn };
return factory;
function loggedIn() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init();
auth2.then(function(){
return auth2.isSignedIn.get();
});
});
}
})
EDIT #3:
I tried creating a service but I keep getting the following error for some reason to even test it:
Error: undefined is not an object (evaluating 'gapi.auth2.init')
.service('googleService', ['$http', '$rootScope', '$q', function ($http, $rootScope, $q) {
var self = this;
this.signedIn = function() {
auth2 = gapi.auth2.init();
auth2.then(function(){
return auth2.isSignedIn.get();
});
}
this.signOut = function(){
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
});
}
}])
.controller('login', ['$rootScope', '$scope', '$q', 'googleService', function ($rootScope, $scope, $q, googleService) {
console.log(googleService.signedIn());
}])
I build upon my fiddle from my previous answer on a related question.
Basically what I added was a function to the controller scope that would be called when a user clicks on the signout button.
angular.module('app', [])
.controller('MainController', ['$scope',
function($scope) {
$scope.isSignedIn = false;
...
$scope.signOut = function(){
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
$scope.$apply(function(){
$scope.isSignedIn = false;
console.log('User signed out.');
});
});
}
}
])
I used the code snippet provided by Google documentation and that seemed to work immediately.
Do pay attention when changing variables in scope, you have to wrap your scope changes in $scope.$apply for angular to force to check changes in scope.
You can find the full code in this fiddle.
(I will be removing this Google api project at some point, so replace the API Key with your own if it doesn't work)
This is demo code, so if you would actually put this in project, I'd recommend hiding some of the complexity behind services and directives.
Update: if you want to use a service, you'll have to use angulars promises heavily, see $q docs.
Here's a sample on how you could create a service using promises and callbacks.
There's no simple way to get around the callback hell. But I hope wrapping these things into a service will solve that partially.
Here's an updated fiddle taking advantage of the service.
This is the js code:
angular.module('app', [])
.controller('MainController', ['$scope','googleService',
function($scope, googleService) {
$scope.isSignedIn = false;
googleService.load().then(function(){
$scope.signIn = function(){
googleService.signIn().then(function(){
$scope.isSignedIn = googleService.isSignedIn();
});
};
$scope.signOut = function(){
googleService.signOut().then(function(){
$scope.isSignedIn = googleService.isSignedIn();
});
};
});
}
])
.service('googleService', ['$q', function ($q) {
var self = this;
this.load = function(){
var deferred = $q.defer();
gapi.load('auth2', function(){
var auth2 = gapi.auth2.init();
//normally I'd just pass resolve and reject, but page keeps crashing (probably gapi bug)
auth2.then(function(){
deferred.resolve();
});
addAuth2Functions(auth2);
});
return deferred.promise;
};
function addAuth2Functions(auth2){
self.signIn = function() {
var deferred = $q.defer();
auth2.signIn().then(deferred.resolve, deferred.reject);
return deferred.promise;
};
self.isSignedIn = function(){
return auth2.isSignedIn.get();
}
self.signOut = function(){
var deferred = $q.defer();
auth2.signOut().then(deferred.resolve, deferred.reject);
return deferred.promise;
};
}
}]);
Basically, inside the load function you wrap the complexity of loading gapi, and auth2. After the load promise resolved in your controller, you are certain that the signIn, signOut, etc will work because it is loaded.
I took a slightly different approach. Though, I am not good enough to explain why your code does not work and this works for me. Hopefully, someone else can help on this.
Here is my approach. Let me know if this helps.
login.html
<script>var gapiOnLoadCallback = function() { window.gapiOnLoadCallback(); }</script>
<script src="https://apis.google.com/js/platform.js?onload=gapiOnLoadCallback" async defer></script>
<div id="googleLoginButton"></div>
<button ng-show="signedIn" ng-click="signOut()">Sign Out</button>
login.js
angular.module('app', [])
.controller('LoginController', ['$window','$scope', function($window, $scope) {
$window.gapiOnLoadCallback = function() {
gapi.signin2.render('googleLoginButton', {
'onsuccess': onSuccess,
'onfailure': onFailure
});
}
var onSuccess = function(googleUser) {
// Success handling here
};
var onFailure = function() {
// Failure handling here
};
$scope.signOut = function() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
// Some UI update
});
};
};
login-directive.js
angular.module('app', []).directive("loginButton", function() {
return {
restrict: 'E',
scope: {},
templateUrl: 'login/login.html',
controller: 'LoginController'
}
});
First of all, I know this error has been covered many times around here, and I read thoroughly many questions about this but no one seems to fit my problem exactly. Why? Well most of them are not related to the Angular UI modal and the way it asks for the resources to display.
I'll start showing you my controller:
'use strict';
// Customers controller
angular.module('customers').controller('CustomersController',
['$scope', '$stateParams', '$location', '$filter', 'Authentication', 'Customers', '$modal', '$log',
function($scope, $stateParams, $location, $filter, Authentication, Customers, $modal, $log ) {
// Find a list of Customers
$scope.find = function() {
Customers.query(function (data) {
$scope.customers = data;
$scope.buildPager();
});
};
// Find existing Customer
$scope.findOne = function() {
$scope.customer = Customers.get({
customerId: $stateParams.customerId
});
};
//List Pager
$scope.buildPager = function () {
$scope.pagedItems = [];
$scope.itemsPerPage = 15;
$scope.currentPage = 1;
$scope.figureOutItemsToDisplay();
};
/* Modal stuff */
$scope.animationsEnabled = true;
$scope.openUpdateModal = function (size, selectedCustomer) {
var modalInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'modules/customers/views/edit-customer.client.view.html',
controller: function ($scope, $modalInstance, upcustomer) {
$scope.upcustomer = upcustomer;
},
size: size,
resolve: {
upcustomer: function () {
return selectedCustomer;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
//Controller Closing brackets
}
]);
In the view I have a list of customers, so if I click one of them I want the modal to open:
<a data-ng-repeat="customer in pagedItems" ng-click="openUpdateModal('lg', customer)" class="list-group-item"></a>
I did this thing based on a Bossable.com video tutorial called: MEAN Stack: 20 - Pass Customer Details to an Angular UI Modal
The only difference is that I got this error when clicking a customer:
[$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array
Thanks for your time.
Just remove the $scope.findOne function because it uses the get method and returns and array. If you look back at her tutorial, she kept it commented.
Your problem is to do with your Customer.query() or Customer.get() call. These are $resource calls and expect to be told what the response is.
Usually a get method expects an object while the query method expects an array. If you're not return one of those for those methods you need to configure it using the isArray: true/false option depending on your needs.
Documentation on this can be found:
https://docs.angularjs.org/api/ngResource/service/$resource
$resource( 'apiendpoint', {}, {
query: {
isArray: false
}
});
}
I've created a service to pass a boolean flag between controllers.
Service looks like this :
angular.module('MyApp')
.service('sharedProperties', function () {
var flag = false;
return {
getProperty: function () {
return flag;
},
setProperty: function(value) {
flag = value;
}
};
});
First controller where flag is set is this
angular.module('MyApp')
.controller('test1', function($scope, $location, $http, $window, sharedProperties) {
$scope.flag1 = function () {
if ($location.path() == '/') {
sharedProperties.setProperty(false);
return false;
}else {
sharedProperties.setProperty(true);
return true;
};
};
});
And controller receiving argument is this
angular.module('MyApp')
.controller('test2', function($scope, $location, $http, $window, sharedProperties) {
$scope.flag2 = sharedProperties.getProperty();
});
flag1 in test1 takes a correct value, but test2 is always false. If I initialize flag at service as true - it's always true at test2. If I don't initialize it - it's undefined at test2.
This behaviour is totally expected and is not linked to angularjs in particular, it works like this in vanilla javascript. The issue you encounter is due to the fact that javascript primitives are passed by value and not by reference. You can read more about it here: Is JavaScript a pass-by-reference or pass-by-value language?
How to fix your code? Use an object which will be passed by reference.
Could you try this:
angular.module('MyApp')
.service('sharedProperties', function () {
var flag = {
value: false
};
return {
getProperty: function () {
return flag;
},
setProperty: function(value) {
flag.value = value;
}
};
});
angular.module('MyApp')
.controller('test1', function($scope, $location, $http, $window, sharedProperties) {
$scope.flag1 = function () {
if ($location.path() == '/') {
sharedProperties.setProperty(false);
return false;
}else {
sharedProperties.setProperty(true);
return true;
};
};
});
angular.module('MyApp')
.controller('test2', function($scope, $location, $http, $window, sharedProperties) {
$scope.flag2 = sharedProperties.getProperty();
// use flag2.value in your markup
});
The reason being is I believe that Angular initializes a service with new when added to a controller.
So when manipulating in test1, its an instance of the service in that controller which is not shared in the other controller. I could be wrong though and would recommend firstly using this.flag instead of var flag. In addition, your test2 controller makes a call on angular load, rendering false but it doesn't watch for changes.
Created a JSBIN to solve it for you: http://jsbin.com/xoqup/1/edit
angular.module('pipelineChromeApp', [
'ngResource',
'ngSanitize',
'ngRoute',
'LocalStorageModule'
])
angular.module('pipelineChromeApp')
.factory('Profile', [
'$http',
'apiUrl',
'localStorageService',
function ($http, apiUrl, localStorageService) {
var baseUrl = apiUrl + 'profile.json?api_key=';
return {
login: function(apiKey) {
return $http.get(baseUrl + apiKey);
},
logout: function() {
localStorageService.clearAll();
localStorageService.set('loggedIn', false);
console.log("cleared local storage");
return true;
}
}
}]);
angular.module('pipelineChromeApp')
.controller('LoginController', [
'$scope',
'Profile',
'$location',
function ($scope, Profile, $location) {
$scope.apiKey = "";
$scope.login = function(){
debugger
// Profile.login().then({
// $location.path( "/actions" );
// });
};
}]);
For some reason Profile isn't available in LoginController. Have I loaded things wrong?
As you mentioned in your comment, the problem you have is in the console, and I assume the browser you're using is chrome. In chrome/v8, the javascript engine tries very hard to optimize your code, it will remove any unused function parameters. In your case, Profile isn't used anywhere in your function, so v8 has removed it.
That's also the reason why it works fine when you have some code to do with the Profile.
Usually I will add a console.log() to an empty function if I want to check some variables in the chrome console, like this:
$scope.login = function() {
debugger;
console.log(Profile);
};
I want to use a dependency in listener but the websocket was undefined
$rootScope.$on('websocket.connected', function() {
$websocket.request(.....).then();
});
and a want to call a service method (who depend on asyncron method) when it ready
app.controller('MyCtrl', function(myServ, $log) {
myServ.getInfos();
});
thank you.
Code in jsfiddle http://jsfiddle.net/8DHfY/3/ or here
var app = angular.module('myApp', ['myServ'])
.config(['$websocketProvider', function ($websocketProvider) {
$websocketProvider.setHost('ws://echo.websocket.org/');
}])
.controller('MyCtrl', function(myServ, $log) {
$log.log('I want to call myServ.getInfos() from a controler');
});
angular.module('myServ', ['websocket']).service('myServ', ['$log', '$rootScope', '$websocket', function($log, $rootScope, $websocket) {
$log.error('websocket is %o ... ???', $websocket); // return undefined
$rootScope.$on('websocket.connected', function() {
$log.error('websocket is still %o', $websocket); // return undefined
});
return {
getInfos: function() {
$websocket.request(JSON.stringify({'key': 'value'}));
}
};
}]);
angular.module('websocket', []).provider('$websocket', [function() {
var _this = this;
_this.host = '';
_this.connection = null;
_this.setHost = function(host) {
this.host = host;
return this;
};
_this.request = function(request) {
//request method for websocket
};
this.$get = ['$log', '$rootScope', function($log, $rootScope) {
_this.connection = new WebSocket(this.host);
_this.connection.onopen = function(){
$log.log('Websocket connected to %s', _this.host);
$rootScope.$emit('websocket.connected');
};
}];
}]);
Providers invoke the $get function upon injection and use the singleton of whatever is returned from that function.
This means since you do not return anything from the $get function, it uses undefined.
Here's an updated fiddle: http://jsfiddle.net/8DHfY/4/
this.$get = ['$log', '$rootScope', function($log, $rootScope) {
_this.connection = new WebSocket(this.host);
_this.connection.onopen = function(){
$log.log('Websocket connected to %s', _this.host);
$rootScope.$emit('websocket.connected');
};
return _this;
}];