Attributes of a directive with A restrict - javascript

Considering a directive having an isolated scope (object), and restrict A, How can I pass their attributes?
For instance, when it comes to restrict E, if scope equals to {attr : '#'} , then the directive will be called like .

The attributes can be passed in same way as we pass for E type directives.
Refer: http://plnkr.co/edit/T2R91F0iR9GfttSav9Zq?p=preview
//HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-example12-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="docsSimpleDirective">
<div ng-controller="Controller">
<div my-customer customer="customer" testv="Hello"></div>
</div>
</body>
</html>
//JS
(function(angular) {
'use strict';
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
restrict: 'A',
scope: {
customer:'=',
testv: '#'
},
template: 'Name: {{customer.name}} Address: {{customer.address}} - {{v1}}',
link: function(scope, element, attrs) {
console.log(attrs);
scope.v1=attrs.testv;
}
};
});
})(window.angular);

When we create directive with restrict 'E' which stands for 'Element', then it will call like as -
<my-attr-directive attr="somevalue" ></my-attr-directive>

the same like with restrict E:
<div my-attr-directive attr="somevalue"></div>

Related

How to use angular listener when using ng-repeat?

When I click a button, the controller will get data from some $http service callback function and will $broadcast it on $scope. Then, in the directive, I have a listener to get the data and do some logic. But, when I am using ng-repeat on button for several formats, the listener will get fired for all ng-repeat items when I click on each button. How can I make the listener to get fired only for the clicked button? Please see the sample code below.
var app = angular.module('demoApp', []);
app.controller('MyCtrl', function($scope) {
var myCtrl = this;
myCtrl.getFile = function(){
var response = 'some data';
$scope.$broadcast('downloadFile', {'response': response});
}
});
app.directive('fileDownload', function(){
return {
restrict: 'A',
link: function(scope, elem, attrs){
var cancelEvent = scope.$on('downloadFile', function(event, args){
console.log('called', args);
});
scope.$on('$destroy', function(){
cancelEvent();
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp">
<div ng-controller="MyCtrl as myCtrl">
<button ng-repeat="format in ['TXT','PDF','CSV']" ng-click="myCtrl.getFile()" file-download>{{ format }}</button>
</div>
</div>
In this sample you can figure out how can create directive using scope, i create a sample to get all formats get all lists, get checked list, get download format, on directive.
About your codes, actually response is true, because when we use some functions like [$broadcast] or ... on app run all data already sets in our scopes. but remember in this case you don't need to use $broadcast that because our actions are in-time and we can get them when we click on a function.
hope helps you my friend
var app = angular.module('app', []);
app.controller('ctrl', function ($scope) {
var self = this;
self.lists = [
{ name: "A"},
{ name: "B"},
{ name: "C"},
{ name: "D"}
];
self.getFile = function () {
console.log('controller', "done");
}
});
app.directive('fileDownload', function ($filter) {
return {
restrict: 'A',
scope: {
fileDownload: "=",
list: "="
},
link: function (scope, elem) {
elem.on("click", function () {
var filter = $filter("filter")(scope.list, { checked: true });
console.log('from directive, all list', scope.list);
console.log('from directive, checked list', filter);
console.log('from directive, download format', scope.fileDownload);
});
}
}
});
<!DOCTYPE html>
<html ng-app="app" ng-controller="ctrl as self">
<head>
<title></title>
</head>
<body>
<small>list</small>
<ul>
<li ng-repeat="list in self.lists">
<input type="checkbox" ng-model="list.checked"/>
{{list.name}}
</li>
</ul>
<small>download format</small>
<button ng-repeat="format in ['TXT','PDF','CSV']" ng-click="self.getFile()" list="self.lists" file-download="format">{{ format }}</button>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
I think it will help you
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp">
<div ng-controller="MyCtrl as myCtrl">
<span ng-repeat="format in ['TXT','PDF','CSV']">
<span get-file="myCtrl.getFile({data: data})" file-download title="format"></span>
</span>
</div>
</div>
</body>
<script type="text/javascript">
var app = angular.module('demoApp', []);
app.controller('MyCtrl', function($scope) {
var myCtrl = this;
myCtrl.getFile = function(data) {
var response = 'some data';
console.log(response);
console.log(data);
// $scope.$broadcast('downloadFile', {'response': response});
}
});
app.directive('fileDownload', function() {
return {
restrict: 'A',
template: "<button ng-click='callFn()'>{{title}}</button>",
scope: {
title: '=',
getFile: '&'
},
link: function(scope, elem, attrs, ctrl) {
scope.callFn = function(){
scope.getFile({data: scope.title});
}
// var cancelEvent = scope.$on('downloadFile', function(event, args) {
// console.log('called', args);
// });
// scope.$on('$destroy', function() {
// cancelEvent();
// });
}
}
});
</script>
</html>

Angular directive attributes cause an error

I am trying write an angular directive to make a substring of an attribute that is passed in. Below is my code:
HTML:
<body ng-controller="MainCtrl">
<div><substring message="This is a test."></substring></div>
<div><substring message="So is this." ></substring></div>
</body>
Angular/Javascript:
var app = angular.module('myapp', []);
app.controller('MainCtrl', function($scope) {
});
app.directive('substring', function () {
return {
restrict: 'AE',
replace: true,
scope: { text: '=message' },
link: function (scope, elem, attrs) {
//alert(attrs.message);
var str = attrs.message;
scope.text = str.substring(1, 4);
},
template: '<H1>{{text}}</H1>'
};
});
When I try running this I get the following error:
HTML1300: Navigation occurred.
File: directive.html
Error: [$parse:syntax] Syntax Error: Token 'is' is an unexpected token at column 6 of the expression [This is a test.] starting at [is a test.].
Also, I have tried changing
'=message' to '#message'
but that just causes the substring stuff I am doing in the link function to get ignored.
Why the error? Is Angular not seeing that stuff in the quotation marks as a string and instead trying to parse out some command? Most importantly, how do I fix this?
Thanks
Simply use # for text binding and the rest of your code works perfectly.
Working example:
var app = angular.module('myapp', []);
app.controller('MainCtrl', function($scope) {
});
app.directive('substring', function() {
return {
restrict: 'AE',
replace: true,
scope: {
message: '#'
},
link: function(scope, elem, attrs) {
//alert(attrs.message);
var str = attrs.message;
scope.text = str.substring(1, 4);
},
template: '<H1>{{text}}</H1>'
};
});
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body ng-controller="MainCtrl">
<div>
<substring message="This is a test."></substring>
</div>
<div>
<substring message="So is this."></substring>
</div>
</body>
</html>

Is it possible to $watch a directive's transcluded scope or even two way bind it?

Within a directive with transcluded scope it appears that $watch listeners do not trigger. Two way bindings also appear not to work. I'll paste the code I have of a simple example illustrating the issue as well as it's jsbin link. My question is: Is this possible? If so what I'm doing wrong? Any help would be greatly appreciated.
Html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
<meta charset="utf-8">
<title>Angular tips</title>
</head>
<body ng-controller="MainCtrl">
<person header="header">
<h2>{{header}}</h2>
<p>Hello, I am {{person.name}} and,</p>
<p>I am a {{person.profession}}</p>
<input type="text" placeholder="Change me" ng-model="person.name" />
<input type="text" placeholder="Change me" ng-model="person.profession" />
</person>
</body>
</html>
JavaScript
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.person = {
name: 'John Doe',
profession: 'Fake name'
};
$scope.header = 'Person';
})
.directive('person', function() {
return {
restrict: 'EA',
scope: {
header: '='
},
transclude:true,
template: '<div ng-transclude></div>',
link: function(scope, element, attrs) {
scope.$watch('person', function(){
console.log('person changed');
}, true);
scope.person = {
name: 'Directive Joe',
profession: 'Scope guy'
};
scope.header = 'Directive\'s header';
}
};
});

Angular directive that requires another directive that uses an Attribute defined controller

I'm learning angular and when I was studying custom directives I got stuck in a situation that I don't know how to solve. Here are my custom direcives:
/**
* Created by Lucas on 11/06/2015.
*/
'use strict'
eventsApp
.directive('greeting',function() {
return {
restrict: 'E',
replace: true,
template: "<button class='btn' ng-click='sayHello()'>Say Hello</button>",
controller: function GreetingController($scope) {
var greetings = ['hello'];
$scope.sayHello = function() {
alert(greetings.join());
}
this.addGreeting = function(greeting) {
greetings.push(greeting);
}
}
};
})
.directive('finnish',function() {
return {
restrict: 'A',
require: 'greeting',
link: function(scope, element, attrs, controller) {
controller.addGreeting('hei');
}
}
})
.directive('hindi',function() {
return {
restrict: 'A',
require: 'greeting',
link: function(scope, element, attrs, controller) {
controller.addGreeting('नमस्ते');
}
}
});
These directives work fine, however, if I change the greeting controller to receive an external controller via an attribute like this:
.directive('greeting',function() {
return {
restrict: 'E',
replace: true,
template: "<button class='btn' ng-click='sayHello()'>Say Hello</button>",
controller: '#',
name: 'ctrl'
};
})
And make a reference in the HTML like this:
<!DOCTYPE html>
<html ng-app="eventsApp">
<head lang="en">
<meta charset="UTF-8">
<title>Event Registration</title>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/app.css"/>
</head>
<body>
<greeting ctrl="GreetingController">
<div finnish hindi></div>
</greeting>
<script src="lib/jquery.min.js"></script>
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-resource.js"></script>
<script src="lib/angular/angular-route.min.js"></script>
<script src="lib/underscore-1.4.4.min.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/GreetingController.js"></script>
<script src="js/directives/greeting.js"></script>
<script src="js/filters.js"></script>
<script src="lib/bootstrap.min.js"></script>
</body>
</html>
The other directives stop working, angular logs the following error:
Error: [$compile:ctreq] Controller 'greeting', required by directive 'hindi', can't be found!
I imagine that there is a way to fix this, but since I'm new in Angular I'm quite a bit lost.
If you are getting the controller as an attribute, the attribute name needs to be the name of the directive:
<greeting greeting="GreetingController" finnish="" hindi=""></greeting>
See this plunker

Passing method through a directive to a parent directive

edit: Modified the code as per stevuu's suggestion as well as added a plunkr to here
I'm currently attempting to have a child directive call a method(resolve) through another directive all the way up to a parent directive but I'm having difficulties identifying the problem with my approach.
The problem right now seems to be that although resolve() does get called as expected on click, selected remains undefined.
the html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Angular: directive using & - jsFiddle demo</title>
<script type='text/javascript' src='//code.jquery.com/jquery-1.9.1.js'></script>
<link rel="stylesheet" type="text/css" href="/css/normalize.css">
<link rel="stylesheet" type="text/css" href="/css/result-light.css">
<script type='text/javascript' src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<style type='text/css'>
</style>
</head>
<body ng-app="myApp">
<div grand-parent>
<span>selected: {{text}}</span>
<div parent resolve="resolve"></div>
</div>
</body>
</html>
And the js:
var myApp = angular.module('myApp',[]);
myApp.directive('grandParent', function() {
return {
scope:{
resolve: "&"
},
link: function($scope, $element) {
$scope.resolve = function(selected){
$scope.text = selected
}
}
};
});
myApp.directive('parent', function(){
return{
scope: {
resolve: "&"
},
template: "<div child resolve='resolve'></div>"
};
});
myApp.directive('child', function() {
return {
scope: {
resolve: "&"
},
template: "<div>Click me!</div>",
link: function($scope, $element) {
$element.on("click", function(){
$scope.$apply(function(){
$scope.resolve({selected: "Yahoo!!"});
});
});
}
};
});
resolve: "&" is a mapping. So here:
myApp.directive('grandParent', function() {
return {
scope:{
resolve: "&"
},
link: function($scope, $element) {
$scope.resolve = function(selected){
$scope.text = selected
}
}
};
});
you are trying to map "resolve" to ... nothing, because "grandParent" doesn't have any attr named "resolve".
If you want to share some staff betweens directives you should do something like that:
view
<div data-grand-parent resolve="resolved()">
<div data-parent ></div>
</div>
Directives
var app = angular.module('test');
app.directive('grandParent', function() {
return {
scope : {
resolve : "&" // in view we defined resolve attr
// with "resolve()" value, so now resolve=resolved()
// in grandParent scope too.
},
controller: function($scope){
this.getResolve = function(){
return $scope.resolve;
};
}
};
});
app.directive('parent', function() {
return {
require: "^grandParent",
link: function(scope, element, attr, grandParentCtrl){
grandParentCtrl.getResolve()();
},
template : ""
};
});
controller
angular.module('desktop')
.controller('MainCtrl', function ($scope, mocks) {
$scope.resolved = function(){
console.log("calling $scope.resolved() ...");
};
});
output
calling $scope.resolved() ...
So, how does it work?
We defined resolved function in our controller, then we sign this function to attr "resolve" in grandParent directive. Thx to resolve : "&" we could mapped that resolved() function to "resolve" property in grandParent scope. At the end we inject grandParent to other directives. That's all.
I recommend you to read angularJs by Brad Green, Shyam Seshadri. it's not the best book but could be worse and it's free. You can find very good tutorial too on http://www.egghead.io/
ps. Sorry for my english ;/

Categories