Invoked from a directive, angular growl not show - angularjs

I was using angular growl, which is quite good for showing message.
(https://github.com/marcorinck/angular-growl)
It OK to add a message in a controller, but when add a message in a directive, it's not show, why?
Here is my test code.
a.html
<?xml version="1.0" encoding="UTF-8" ?>
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://raw.github.com/marcorinck/angular-growl/master/src/growl.css" />
<script type="text/javascript" src="../lib/angular/angular.js"></script>
<script type="text/javascript" src="../lib/angular-growl/angular-growl.js"> </script>
<script type="text/javascript" src="../lib/angular-route/angular-route.js"> </script>
<script type="text/javascript" src="a.js"></script>
</head>
<body>
<div ng-view=""></div>
<div growl="" class='growl-container'></div>
</body>
</html>
a.js
'use strict';
var module = angular.module('a', ['ngRoute', 'angular-growl']);
module.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
controller: 'IndexCtrl',
template: '<button aaa>aaaa</button>'
});
}]);
module.controller('IndexCtrl', ['growl', function (growl) {
growl.addErrorMessage('haha');
}]);
module.directive('aaa', ['growl', function (growl) {
return {
restrict: 'A',
scope: {},
link: function (scope, element, attrs) {
element.bind('click', function (e) {
console.log('aaa');
growl.addErrorMessage('aaa');
growl.addErrorMessage('bbb');
});
}
};
}]);
var $html = angular.element(document);
$html.ready(function () {
angular.bootstrap($html, ['a']);
$html.addClass('ng-app');
});

Whenever you have events outside of angular that change angular scopes you need to use $apply to inform angular that changes are made and to run a digest cycle.
If you were to use ng-click instead you wouldn't run into this problem.
To resolve with current external event code:
element.bind('click', function (e) {
scope.$apply(function(){
growl.addErrorMessage('aaa');
})
});

Related

Google Signin button in AngularJS sometimes does not show up

I followed this link https://developers.google.com/identity/sign-in/web/sign-in to get Google Signin on Angular-based website.
I have seen some weird behavior. The signin button sometimes show but not always. When I refresh a page, only 1 in 5 refreshes, the button appears.
I tried in Chrome and Safari and both has same behavior.
Code:
index.html
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="my_client_id">
login.html
<div class="g-signin2" data-onsuccess="onSignIn"></div>
login.js
angular.module('app').controller('LoginCtrl', function($scope) {
window.onSignIn = function(googleUser) {
// Get some info
}
});
My guess is that the platform.js script waits for the DOM-ready event and then looks for your div with the "g-signin2"-class. Though, in Angularjs things work a little different. The reason that it works sometimes, is because sometimes your div has been rendered by Angular and sometimes is hasn't been rendered before the Dom-ready event.
There's documentation on how to get the same result with your own javascript.
I made an example that follows your routing.
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div ng-view></div>
<script src="https://apis.google.com/js/platform.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.6/angular-route.min.js"></script>
<script>
angular.module('app',['ngRoute'])
.config(['$routeProvider',function($routeProvider){
$routeProvider
.when('/log-in', {
template: '<button ng-click="logInCtrl.onLogInButtonClick()">Log In</button>',
controller: 'LogInController',
controllerAs: 'logInCtrl'
}).otherwise({
redirectTo:'/log-in'
});
}])
.controller('LogInController',function(){
var self = this; //to be able to reference to it in a callback, you could use $scope instead
gapi.load('auth2', function() {//load in the auth2 api's, without it gapi.auth2 will be undefined
gapi.auth2.init(
{
client_id: 'CLIENT_ID.apps.googleusercontent.com'
}
);
var GoogleAuth = gapi.auth2.getAuthInstance();//get's a GoogleAuth instance with your client-id, needs to be called after gapi.auth2.init
self.onLogInButtonClick=function(){//add a function to the controller so ng-click can bind to it
GoogleAuth.signIn().then(function(response){//request to sign in
console.log(response);
});
};
});
});
</script>
</body>
</html>
Or as a directive:
<!doctype html>
<html lang="en" ng-app="app" ng-controller="MainController">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<google-sign-in-button on-sign-in="onSignIn(response)" g-client-id="CLIENTID.apps.googleusercontent.com"></google-sign-in-button>
<script src="https://apis.google.com/js/platform.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script>
angular.module('app',[])
.controller('MainController',['$scope', function ($scope) {
$scope.onSignIn=function(response){
console.log(response);
}
}])
.directive('googleSignInButton',function(){
return {
scope:{
gClientId:'#',
callback: '&onSignIn'
},
template: '<button ng-click="onSignInButtonClick()">Sign in</button>',
controller: ['$scope','$attrs',function($scope, $attrs){
gapi.load('auth2', function() {//load in the auth2 api's, without it gapi.auth2 will be undefined
gapi.auth2.init(
{
client_id: $attrs.gClientId
}
);
var GoogleAuth = gapi.auth2.getAuthInstance();//get's a GoogleAuth instance with your client-id, needs to be called after gapi.auth2.init
$scope.onSignInButtonClick=function(){//add a function to the controller so ng-click can bind to it
GoogleAuth.signIn().then(function(response){//request to sign in
$scope.callback({response:response});
});
};
});
}]
};
});
</script>
</body>
</html>
After writing the previous examples I found a better and easier way to implement it. With this code you inherit the same button as you normally would.
<!doctype html>
<html lang="en" ng-app="app" ng-controller="MainController">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta name="google-signin-client_id" content="CLIENTID.apps.googleusercontent.com">
</head>
<body>
<google-sign-in-button button-id="uniqueid" options="options"></google-sign-in-button>
<script src="https://apis.google.com/js/platform.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script>
angular.module('app', [])
.controller('MainController', ['$scope',
function($scope) {
//for more options visit https://developers.google.com/identity/sign-in/web/reference#gapisignin2renderwzxhzdk114idwzxhzdk115_wzxhzdk116optionswzxhzdk117
$scope.options = {
'onsuccess': function(response) {
console.log(response);
}
}
}
])
.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()); //render a google button, first argument is an id, second options
}
};
});
</script>
</body>
</html>
I found another way to solve the problem a liitle bit simply.
The explanation from #sniel is perfect but I will let you know more simple solution.
you can use below sample code very simiraliry with using $watch
https://developers.google.com/identity/sign-in/web/build-button
<!-- html part -->
<div id="signInButton"></div>
//gapi is Asynchronously loaded so you need to watch
$scope.$watch('gapi', function(newValue,oldVale){
if(newValue !== oldVale){
if(gapi){
gapi.signin2.render('signInButton',
{
'onsuccess': $scope.onSuccess,
'onfailure': $scope.onFailure,
'scope':'https://www.googleapis.com/auth/plus.login'
}
);
}
}
});

initializing scope using ng-init is not binding in directive

Hi I am trying to bind a value to a directive using '#' which is defined in the ng-init event. but this doesn't comes into my directive and it returns undefined. When does this property actually resolves is it in Compile, link? Also, why is it returning undefined always? What am I doing wrong here?
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="demoController" ng-init="init()">
<h1>Confused directives!!!</h1>
<my-user userName="{{user.name}}"></my-user>
<br>
{{user.name}}
</body>
</html>
(function(){
'use strict';
var app = angular.module('app', []);
app.controller('demoController', ['$scope', demoController])
function demoController($scope){
console.log('Im in the controller');
$scope.init = function (){
$scope.user = {
name: 'Argo'
}
console.log('Im in init method of controller')
}
}
app.directive('myUser', myUser);
function myUser(){
return {
restrict: 'AE',
replace: true,
scope: {
userName: '#'
},
template: '<div><b>{{userName}} is defined from init method </b></div>',
link: function(scope, ele, attr){
console.log('Im in link method of directive');
console.log('this is loaded' + scope.userName);
attr.$observe('userName', function(newValue){
console.log(newValue);
})
}
}
}
})();
http://plnkr.co/edit/vAKMNub8HRcphiaMMauR?p=preview

scope variable value change asyn

All,
Right now, I am learning AngularJS directive and for simple tryout purpose I wrote a small script which is:
<html ng-app="vp">
<head>
<title>try container</title>
<link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.min.css" />
</head>
<body ng-controller="dashboard">
<testscope info="info.name"></testscope>
<script type="text/javascript" src="jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="https://code.angularjs.org/1.2.15/angular-route.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript">
var app = angular.module("vp", []);
app.controller("dashboard",["$scope", function($scope){
$scope.info = {
name:"scope",
value:"scopevalue"
};
$scope.$on("showcontrollerscope", function(){
console.log("scope in controller:", $scope.info.name);
});
$scope.$watch("info", function(newn, oldn){
console.log("after change", $scope.info.name);
}, true);
}]);
app.directive("testscope", function(){
return {
restrict: "AE",
scope:{
info: "="
},
controller: function($scope, $element, $attrs){
console.log($scope);
$scope.$emit("showcontrollerscope");
$scope.info = "changed scope";
$scope.$emit("showcontrollerscope");
}
};
});
</script>
</body>
</html>
My question is why the $on outputs are both scope rather than scope and changed scope? like in $watch.
I originally think the $emit is asyn, but someone said it is sync
They are synchronous.
See also https://groups.google.com/d/msg/angular/yyH3FYAy5ZY/APANNMnolD8J
I found many people suggest not use $watch in controller, so how can I do this?
Thanks

angularJs custom directive not invoked

I am new to AngularJs. I have created a simple custom directive in Angular to print out some text. The code is below:
var demoApp = angular.module('demo-app', ['ngRoute']);
demoApp.directive('helloWorld', function() {
return {
restrict: 'E',
template: '<h1>Hello World!!</h1>'
};
});
In the html file I am using it like below:
<hello-world/>
<script type="text/javascript" src="js/demo-app.js"></script>
I am not seeing the output "Hello World!". Please let me know where I am going wrong? I am using Angular 1.3 version.
I did it following way in my project, and it is working fine.
customDirective.js
myApp.directive('viewTodoSuccessModal', function () {
return {
restrict: 'E',
templateUrl: '/scripts/app-angular/directives/templates/view-todo-success-modal.html'
};
});
app.js
angular.module('myApp', [
'myAppControllers'
, 'myAppDirectives'
]);
included/referenced in html page
<script src="#Url.Content("~/Scripts/app-angular/app.js")"></script>
<script src="#Url.Content("~/Scripts/app-angular/Directives/CustomDirectives.js")"></script>
Hope it helps
Just check whether your module name is 'demo-app' in html or not.If it is not then make it correct.module name in script file should be same as html file.
<html ng-app="demo-app">
<head>
<script src="angular.js"></script>
</head>
<body>
<hello-world />
<script type="text/javascript">
angular.module('demo-app',[]);
angular.module('demo-app')
.directive('helloWorld', function() {
return {
restrict: 'E',
template: '<h1>Hello World!!</h1>'
};
});
</script>
</body>
</html>
JS Fiddle: http://jsfiddle.net/vSpR4/1/

Watch not working when HTML loaded from Directive in AngularJS

I am loading a partial in Angular dependant on the route of the URL.
When I load the partial it loads, and responds to the Controllers functions. However I have a directive which has a watcher. This does not work when I use the
It works fine when I load the HTML inside the main page. I have a Plunker of this here
http://plnkr.co/edit/DK33pIrp0HyhUOjwm5X2?p=preview
Essentially clicking "hello" should change the $scope.origin and the watcher should then fire its event. It does not.
My HTML:
<!DOCTYPE html>
<html ng-app="App">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/coffee-script/1.1.2/coffee-script.min.js"></script>
<script src="app.js"></script>
<script src="directive.js"></script>
</head>
<body ng-controller="MapCtrl">
<ng-view></ng-view>
</body>
</html>
app.js
var app;
app = angular.module("App", []);
app.config(function($routeProvider) {
return $routeProvider.when("/", {
templateUrl: "home.html",
controller: MapCtrl
});
});
this.MapCtrl = function($scope) {
return $scope.clicked = function() {
console.log("clicked");
$scope.origin = Math.floor(Math.random() * 11);
return console.log($scope.origin);
};
};
directive.js
(function(angular) {
var app;
app = angular.module("App");
return app.directive("leaflet", function() {
return {
restrict: "E",
replace: true,
transclude: true,
template: "<section id='map' class='map'></section>",
scope: {
origin: "=origin"
},
controller: function($scope, $attrs) {
return $scope.$watch("origin", (function(newValue, oldValue) {
return alert("its changed");
}), true);
}
};
});
})(angular);
home.html
<button ng-click="clicked()">hello</button>
how can I get this working?
edit: I have just made this pure JS and not coffeescript.
Thanks so all who helped me find the issue.
This can be done by setting the
<button ng-click="clicked()">hello</button>
to
<button ng-click="$parent.clicked()">hello</button>
This is because the ng-view will be a child. This simple fix is now working.

Resources