I am new in angular and stuck in a conceptual problem. I am not able to access "game" service in "helloWorld" directive.
expected = Name : WarCraft
Actual = Name :
Here is my js and html file :
JS code :
var app = angular.module("app",[]);
app.provider("game", function () {
var type;
return {
setType: function (value) {
type = value;
},
$get: function () {
return {
title: type + "Craft"
};
}
};
});
app.config(function (gameProvider) {
gameProvider.setType("War");
});
app.controller("AppCtrl", function ($scope,game) {
$scope.title = game.title;
});
app.directive('helloWorld', ["game",function (game) {
return {
template: 'Name : {{game.title}}'
};
}])
HTML :
<title>Services</title>
<script src="angular.min.js"></script>
<script src="my-file.js"></script>
</head>
<body ng-app="app">
<div ng-controller="AppCtrl">{{title}} </div>
<hello-world></hello-world>
</body>
something like this:
app.directive('helloWorld', ["game",function (game) {
return {
restrict: 'E',
scope: {},
link: function (scope, elem, attrs, ctrl) {
scope.title = game.title;
},
template: 'Name : {{title}}'
};
}])
Access your game service in controller, which will be available in your template. If you need it only in template, inject it only in controller... your link or other function need not know.
app.directive('helloWorld', function () {
return {
controller: function($scope, game) {
$scope.game = game;
},
template: 'Name : {{game.title}}'
};
}])
Here is solution on plunker, to play around.
Just put define variable which will be used by view and set to it needed value.
app.directive('helloWorld', ["game", function(game) {
return {
template: 'Name : {{game.title}}',
link: function(scope) {
scope.game = game;
}
};
}])
Related
How to expose directive methods without using $broadcast or '=' between modules?
Using $broadcast (events) if there are multiple directives all will be notified. It cannot return value too.
Exposing directive's function by html attribute I think it is not that best that Angular has to offer.
Angular Bootstrap UI do it using services (I guess): It have a service named "$uibModal".
You can call a function "$uibModal.open()" of Modal Directive by injecting $uibModal service.
Is that the right way?
An example of a directive that registers its API with a service:
app.service("apiService", function() {
var apiHash = {};
this.addApi = function (name,api) {
apiHash[name] = api;
};
this.removeApi = function (name) {
delete apiHash[name];
};
this.getApi = function (name) {
return apiHash[name];
};
});
app.directive("myDirective", function (apiService) {
return {
restrict: 'E',
scope: {},
template: `<h1>{{title}}</h1>`,
link: postLink
};
function postLink(scope, elem, attrs)
var name = attrs.name || 'myDirective';
var api = {};
api.setTitle = function(value) {
scope.title = value;
};
apiService.addApi(name, api);
scope.$on("$destroy", function() {
apiService.removeApi(name);
});
}
});
Elsewhere in the app, the title of the directive can be set with:
apiService.getApi('myDirective').setTitle("New Title");
Notice that the directive registers the api with a name determined by the name attribute of the directive. To avoid memory leaks, it unregisters itself when the scope is destroyed.
Update
How could I use it from a controller?
app.controller('home', function($scope,apiService) {
$scope.title = "New Title";
$scope.setTitle = function() {
apiService.getApi('mainTitle').setTitle($scope.title);
};
})
<body ng-controller="home">
<my-directive name="mainTitle"></my-directive>
<p>
<input ng-model="title" />
<button ng-click="setTitle()">Set Title
</button>
</p>
</body>
The DEMO
angular.module('myApp', [])
.service("apiService", function() {
var apiHash = {};
this.addApi = function(name, api) {
apiHash[name] = api;
};
this.getApi = function(name) {
return apiHash[name];
};
})
.directive("myDirective", function(apiService) {
return {
restrict: 'E',
scope: {},
template: `<h1>{{title}}</h1>`,
link: postLink
};
function postLink(scope, elem, attrs) {
var name = attrs.name || 'myDirective';
var api = {};
api.setTitle = function(value) {
scope.title = value;
};
apiService.addApi(name, api);
scope.$on("$destroy", function() {
apiService.addApi(name, null);
});
}
})
.controller('home', function($scope,apiService) {
$scope.title = "New Title";
$scope.setTitle = function() {
apiService.getApi('mainTitle').setTitle($scope.title);
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myApp" ng-controller="home">
<my-directive name="mainTitle"></my-directive>
<p>
<input ng-model="title" />
<button ng-click="setTitle()">Set Title
</button>
</p>
</body>
.factory('myService', [function() {
return {
charCount: function(inputString) {
return inputString.length;
}
}
}])
this service exposes function charCount();
in your directive you have to inject it like this
.directive('testDirective', ['myService', function(myService) {
return {
restrict: 'A',
replace: true,
template: "<div>'{{myTestString}}' has length {{strLen}}</div>",
link: function($scope, el, attrs) {
$scope.myTestString = 'string of length 19';
$scope.strLen = myService.charCount( $scope.myTestString );
}
}
}])
and, of course call it
$scope.strLen = myService.charCount( $scope.myTestString );
<html>
<style>
#out {
width:96%;
height:25%;
padding:10px;
border:3px dashed blue;
font-family: monospace;
font-size: 15px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script>
var APP = angular.module('MYAPP', []);
APP.controller('main', ['$scope', '$element', '$compile', 'myService', function($scope, $element, $compile, myService) {
$scope.test = 'my Test Controller';
$scope.directiveTest = "directive test";
var testSvc = myService.charCount($scope.test);
$scope.showTestDir = true;
}])
.directive('testDirective', ['myService', function(myService) {
return {
restrict: 'A',
replace: true,
template: "<div>'{{myTestString}}' has length {{strLen}}</div>",
link: function($scope, el, attrs) {
$scope.myTestString = 'string of length 19';
$scope.strLen = myService.charCount( $scope.myTestString );
}
}
}])
.factory('myService', [function() {
return {
charCount: function(inputString) {
return inputString.length;
}
}
}])
.filter('toUpper', function() {
return function(input) {
return input.toUpperCase();
}
})
.filter('toLower', function() {
return function(input) {
return input.toLowerCase();
}
})
;
</script>
<body ng-app="MYAPP">
<div id="out" ng-controller="main">
{{test}} - not filtered
<br/>
{{test|toUpper}} - filtered toUpper
<br/>
{{test|toLower}} - filtered toLower
<br/>
<br/>
<div test-directive ng-if="showTestDir"></div>
</div>
</body>
</html>
I need to bind custom events in angularjs(1.x) and I tried with the following code,
HTML
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://www.polymer-project.org/components/polymer/polymer.html" rel="import">
<link href="https://www.polymer-project.org/components/paper-button/paper-button.html" rel="import">
<div ng-app="demo-app">
<div ng-controller="DemoController">
<template bind-angular-scope is="auto-binding">
<paper-button raised on-tap="{{clickMe}}" on-mouseover="{{mouseOver}}">click me</paper-button>
</template>
<pre><code>{[{text}]}</code></pre>
</div>
</div>
Script
<script>
angular.module('demo-app', [])
.config(function ($interpolateProvider) {
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
})
.directive('bindAngularScope', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
for (k in scope) {
if (!element[0][k]) {
element[0][k] = scope[k];
}
}
}
}
})
.controller('DemoController', function ($scope) {
$scope.text = '';
$scope.clickMe = function () {
$scope.text += '\nyou clicked me!!';
$scope.$apply();
};
$scope.mouseOver = function () {
$scope.text += '\nyou hovered me!!';
$scope.$apply();
}
});
</script>
This is not working.Could you point out me the issue or Is there is any solution for binding custom events(multiple) ? Do we need to create a custom directive for each of them ?
Note:
The above code is referred from the following url,
How to bind custom events in AngularJS?
Thanks in advance!
angular.module('demo-app', [])
.config(function ($interpolateProvider) {
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
})
.directive('bindAngularScope', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
for (k in scope) {
if (!element[0][k]) {
element[0][k] = scope[k];
}
}
elem.bind('click', function() {
/* Place your click logic here * /
});
}
}
})
I have this trigger / bind code:
service:
$('body').trigger('ready');
directive:
$('body').bind("ready", function(){
alert("Ready was triggered");
});
Can I do the exact same thing only using angular? If yes, how?
You need to use events in AngularJS check the below sample example I hope it will be of help to you, please check this article for more information on $emit, $on and $broadcast event system in AngularJS
angular
.module('demo', [])
.controller('DefaultController', DefaultController)
.factory('helloService', helloService)
.directive('hello', hello);
function DefaultController() {
var vm = this;
}
helloService.$inject = ['$rootScope'];
function helloService($rootScope) {
var service = {
sendHello: sendHello
};
return service;
function sendHello() {
$rootScope.$broadcast('helloEvent', 'Hello, World!');
}
}
hello.$inject = ['$rootScope', 'helloService'];
function hello($rootScope, helloService) {
var directive = {
restrict: 'E',
scope: {
message: '='
},
link: linkFunc
}
return directive;
function linkFunc(scope, element, attrs, ngModelCtrl) {
scope.$on('helloEvent', function (event, data) {
element.text(data);
});
sendHello();
function sendHello() {
helloService.sendHello();
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<hello></hello>
</div>
</div>
I am trying to implement the directive, in the directive, I want to $eval the values which contains the function name and parameter value:
Html page:
<select mydirective="action('pValue')">
AngularJS directive code:
app.directive('mydirective', function ($timeout) {
return {
restrict: 'A',
link: function ($scope, element, attr) {
$timeout(function () {
$scope.$eval(attr.mydirective);
});
}
}
What I am expected is it will invoke the action function define in scope and pass the pValue as function parameter. How can I make it work please?
What you want happen automatically, the function will invoke with the value, this is the purpose of eval:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.action = function(val) {
alert(val);
}
});
app.directive('mydirective', function($timeout) {
return {
restrict: 'A',
link: function($scope, element, attr) {
$timeout(function() {
$scope.$eval(attr.mydirective);
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
<select mydirective="action('pValue')"></select>
</div>
For those whom looking for a way to pass $event info to custom directive method see example below:
TEMPLATE:
<div on-touch-end="onTouchEnd( 'some data' )">
TOUCH ME!
</div>
CONTROLLER:
$scope.onTouchEnd = function( data ) {
console.log("onTouchEnd event with data", data, event );
};
DIRECTIVE:
.directive('onTouchEnd', function() {
return {
restrict : 'A',
link : function( $scope, $element, $attr ) {
$element.on('touchend', function( event ) {
$scope.$apply(function() {
$scope.$eval( $attr.onTouchEnd );
});
});
}
}
})
I cannot get the parent function call from the isolated scope..The purpose of this code is to create a widget directive which can be used multiple times on the same page... I tried some other option, but doesn't work either. It works using the parent scope.
What am I missing here.
var app = angular.module("winApp", []);
app.controller("winCtrl", function($scope, dataFactory) {
$scope.getData = function() {
dataFactory.get('accounts.json').then(
function(data) {
$scope.items = data;
});
};
});
app.directive("windowSmall", function() {
return {
restrict : 'EA',
replace : 'true',
scope : {
type : '&'
},
transclude: 'true',
templateUrl : 'windowtemplate.html',
link : function(scope, element, attrs) {
element.bind("load", function(){
console.log(attrs.type);
if (angular.equals(attrs.type, 'getData()')) {
scope.active = 'accounts';
console.log(attrs.type);
// scope.getData();
scope.$apply(function() {
scope.$eval(attrs.type);
});
}
});
}
};
});
app.factory('dataFactory', function($http) {
return {
get : function(url) {
return $http.get(url).then(function(resp) {
return resp.data;
});
}
};
});
HTML:
<div ng-app="winApp" ng-controller="winCtrl">
<window-small type = "getData()"> </window-small>
<br> <br>
<!--
<window-small type = "bulletin"> </window-small> -->
You can also use $rootScope for a full proof solution. Due to the fact that an application can have multiple parents but only one $rootScope.
https://docs.angularjs.org/api/ng/service/$rootScope
Replace your link function with :
link : function(scope, element, attrs) {
element.bind("load", function(){
console.log(attrs.type);
if (angular.equals(attrs.type, 'getData()')) {
scope.active = 'accounts';
console.log(attrs.type);
scope.type();
}
});
}
Fiddle : http://jsfiddle.net/X7Fjm/3/