I want to implement directives in my app, but I can't even start with the simplest one. Can someone tell me why?
JS:
angular
.module('app.admin.catalog.nutritional_facts')
.directive('nutritionalInfo', nutritionalInfo);
function nutritionalInfo(){
return{
restrict: 'E',
scope: {
quantity: '=',
unit: '='
},
template: "<div> Hello world {{ '{{quantity.qty}} {{unit.u}}' }}</div>"
};
}
HTML:
<nutritional-info quantity="{qty:4}" unit="{u:'g'}"></nutritional-info>
I'm somewhat new to Angular, so it is probably the simplest question ever. It only shows the empty label, it doesn't even show the Hello world. I already tried sending ints, strings and objects as attributes.
I've corrected your code as shown below to get your directive working as expected :
Working Fiddle
My Changes :
Corrected directive name to camel case
Corrected the angular binding in html
Corrected the objects syntax that are passed to the directive.
HTML :
<nutritional-info quantity="{qty:4}" unit="{u:'g'}"></nutritional-info>
Controller :
angular.module('app.admin.catalog.nutritional_facts', [])
.directive('nutritionalInfo', nutritionalInfo);
function nutritionalInfo(){
return{
restrict: 'E',
scope: {
quantity: '=',
unit: '='
},
template: "<div> Hello world {{quantity.qty}} {{unit.u}}</div>"
};
}
You have a few issues:
NutritionalInfo should be nutritionalInfo (camelCase). That's how Angular will know to associate that directive with the <nutritional-info> HTML tag. See Directive Normalization.
You're not passing in objects correctly to the directive. quantity="{qty=4}" should be quantity="{qty: 4}".
You're not evaluating the expression correctly in the template. {{ '{{quantity.qty}} {{unit.u}}' }} can simply be {{quantity.q}} {{unit.u}}. Angular expressions are interpreted like JavaScript code run on the current scope. So, you can even build expressions like {{quantity.q.toFixed(1) + ' ' + unit.u.toUpperCase()}} (resulting in 4.0 G).
With all those fixes, here's a working fiddle.
Here is my full solution:
<!doctype html>
<html lang="en" ng-app="app.admin.catalog.nutritional_facts">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body >
<nutritional-info quantity="{qty: 3}" unit="{u: 'g'}"></nutritional-info>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.js">
</script>
<script>
function nutritionalInfo(){
return {
restrict: 'E',
scope: {
quantity: '=',
unit: '='
},
template: "<div> Hello world '{{quantity.qty}} {{unit.u}}'</div>"
};
}
angular
.module('app.admin.catalog.nutritional_facts', [])
.directive('nutritionalInfo', nutritionalInfo);
</script>
</body>
</html>
Related
I am new to AngularJS. I want to return template to directive with addition and subtraction of two numbers. I am passing $scope in function but it is not working.
I'm learning from Angular Modules with Directive
here is the code :
<html>
<head>
<title>Angular JS </title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-app="Compl">
<input type=number ng-model="no1" placeholder="Enter the First Number" />
<input type=number ng-model="no2" placeholder="Enter the First Number" />
<NoSum></NoSum>
<NoSub></NoSub>
</div>
<script>
var app = angular.module("Compl", []);
app.directive("NoSum", function($scope) {
return {
template: "Sum of Two Number" + ($scope.no1 + $scope.no2)
};
});
app.directive("NoSub", function($scope) {
return {
template: "Sub of Two Number" + ($scope.no1 - $scope.no2)
};
});
</script>
</body>
</html>
If you're not using isolated scope, you should be able to just use no1 and no2 directly in the template. assuming those are variables in the parent scope.
<script>
var app = angular.module("Compl", []);
app.directive("noSum",function(){
return{
template : "Sum of Two Number {{(no1 + no2)}}"
};
});
app.directive("noSub",function(){
return{
template : "Sub of Two Number {{(no1 - no2)}}"
};
});
</script>
You should also rename your directives, since capitalized letters have special meaning in angular. So with my changed names above, your html should look like this:
<no-sum></no-sum>
<no-sub></no-sub>
Here is a Plunker showing it working as expected
This works because without isolated scope, your directives inherit the scope of their parent, which in your case is the $rootScope. If you used isolated scope instead, you would have to pass in the variables through html attributes.
What you can do is
a) use the 'parent scope' .. so te scope of the controller of the view which contains your directive and so like this:
app.directive("NoSum",function($scope){
return {
template: "Sum of Two Number" + (scope.no1 + scope.no2) //<-- don't use scope with $ ... but only scope
link: function(scope, element, attrs) {
element.bind('error', function() {
if (attrs.src !== attrs.errSrc) {
attrs.$set('src', attrs.errSrc);
}
});
}
};
});
2 - use 'isolated scope' .. so you force to pass the scope trought your item like so:
app.directive("noSum",function($scope){
return {
restrict:'EAC'
template: "Sum of Two Number" + (item.no1 + item.no2) //<-- here you use item and in html you use like: <no-sum item="myvarscoped"></no-sum>
scope:{ item : "="}
link: function(scope, element, attrs) {
element.bind('error', function() {
if (attrs.src !== attrs.errSrc) {
attrs.$set('src', attrs.errSrc);
}
});
}
};
});
As Vivz has already mentioned, you can't pass scopes. Best practice is to share data between controllers/directives is to use factories. See this link for particular example.
In the following simple example I am printing the name model from controller by directive on the view. The example is running fine, but what is the use of transclude I cannot understand. Can someone explain its usage?
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js" ></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<people></people>
<script>
//module declaration
var app = angular.module("myApp",[]);
//controller declaration
app.controller('myCtrl',function($scope){
$scope.name = "Peter";
});
//directives declaration
app.directive('people',function(){
return{
restric: 'E',
template: '<div>{{name}}</div>',
transclude: true
}
});
</script>
</body>
</html>
Your code doesn't really demonstrate what transclude does:
Look at this plunk and change the true/false value:
Plunk
You will notice the effect now hopefully. The source from plunkr, with a couple of modifications.
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.5.3" data-semver="1.5.3" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<people>HI there</people>
<script>
//module declaration
var app = angular.module("myApp",[]);
//controller declaration
app.controller('myCtrl',function($scope){
$scope.name = "Peter";
});
//directives declaration
app.directive('people',function(){
return{
restric: 'E',
template: '<div><ng-transclude></ng-transclude>: {{name}}</div>',
transclude: false
}
});
</script>
</body>
</html>
So when it is true, you will see that the contents are transcluded,
So it says HI There: Peter
When False, it removes the HI There, but keeps the name and my colon:
: Peter
Essentially, these are wrappers around any arbitrary content.
Supposing I have an accordion directive that shows or hides any content that you use it with with an animation.
app.directive('akordion', [function() {
return {
restrict: 'A',
replace: true,
transclude: true,
template: '<div class="accordion-wrapper">'
+'<div class="transcluded" ng-transclude></div>'
+'</div>',
link: function(scope, elem, attrs) {
scope.$watch(attrs.show, function(newVal){
toggle(newVal);
});
function toggle(show) {
var h = (show) ? 0 : '600px';
$(elem).css({ maxHeight: h });
}
}
}
}]);
You'd use it like this:
<div akordion="" id="league-admin">
<div>
foo
</div>
<my-directive></my-directive>
</div>
And the result (generated HTML) is:
<div class="accordion-wrapper" id="league-admin">
<div class="transcluded">
<div>
foo
</div>
<div id="my-directive">...</div>
</div>
</div>
The point is that by calling the akordion="", you take whatever is inside it and put it in the template (<div class="transcluded" ng-transclude>). In other words, the akordion directive wraps over (transcludes) the content you use it on.
Another example would be modal windows. You don't want to repeat the code that defines the modal each time you want to use it, so you define it once, and use transclusion to put any content into it. Check out modal in Bootstrap UI.
Basically If you have some content inside your directive it will be automatically replaced by the directive content
For Example, if you have<people>Test transclude</people> The Test transclude string will be automatically replace by angular when it process the directive. But what if you want 'Test transclude ' also to be displayed ? Here is where transclude come in to action.
Consider the following
app.directive('people',function(){
return{
restric: 'E',
template: '<div><div ng-transclude></div>{{name}}</div>',
transclude: true
}
});
Now the string 'Test transclude' will be also displayed inside tag
And this is the plunker link Plunk
i'm trying to include directives in my application, but even basic directives aren't rendering. what am i doing wrong?
angularloader.js:
var main = angular.module('ngMain', [])
.directive('myScrollable', function () {
return {
restrict: 'AE',
template: '<h3>Hello World!!</h3>'
};
});
My HTML:
<html ng-app dir="auto">
<head>
<meta name="viewport" content="width=device-width" />
<title>#Model.Title</title>
<script src="/Scripts/Libs/angular.js"></script>
<script src="/Scripts/Custom/angularloader.js"></script>
</head>
<body dir="auto">
<my-scrollable></my-scrollable>
</body>
</html>
tried also using tag or attribute ..
you should use module name in ng-app="moduleName"
like:
<html ng-app="ngMain" dir="auto">
if you assign angular module in a variable then use that variable like bellow:
var main = angular.module('ngMain', []);
main.directive('myScrollable', function () {
return {
restrict: 'AE',
template: '<h3>Hello Worlds!!</h3>'
};
});
Working PLUNKER Link
You have define your module but forget to use in html with ng-app= "you module Name". One extra thing you don't need to declare a variable main your code will work without that also.
angular
.module('myModule', [])
.directive('myDir', function{
your code
});
I'm trying to get my head around scopes and after dredging through a number of blogs, stack overflow answers and the docs I am still stuck.
angular.module('app', [])
.factory('alphabet', function () {
data = [
'c',
'b',
'a'
];
return {
get : function () {
return data;
},
set : function (val) {
data.push(val);
}
};
})
.controller('AlphaCtrl', function (alphabet) {
this.alphabet = alphabet;
})
.directive('sortableTable', function () {
return {
scope : {
"param" : '#'
},
link : function (scope) {
console.log(scope.param);
}
};
})
;
HTML:
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div ng-controller="AlphaCtrl as alpha">
<table sortable-table param="{{alpha.alphabet}}">
<thead>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</body>
</html>
What I would like to do is be able to access a service/factory that's being used in an outer controller from within a directive. So for example when I handle a click event I can add items to the data. That seems to be a good way of keeping things decoupled but I am open to suggestions there.
The problem at hand is that 'param' is undefined. I've also tried using '&' but that's not doing anything for me. Could someone put me on the path to Angular righteousness?
I would inject the service directly into the directive:
.directive('sortableTable', function (alphabet) {
return {
scope : {},
link : function (scope) {
console.log(alphabet);
}
};
})
This is indeed a good way of keeping things decoupled, if this is a directive that is used across controllers and views.
Edit for a bit more complex solution: It is possible to do it by injecting the service into the scope of the directive, though I would not recommend it if you don't need to switch services on the fly, since the method above is easier. I could see some use cases though, if you would want to input a different service (with the same get/set structure) in another controller for example. Here's how you could do it via scope:
.controller('myController', function($scope, alphabet) {
$scope.alphabet = alphabet;
})
.directive('myDirective', function(){
return {
scope: {
service: '='
},
template: '<div ng-bind="service.get()"></div>'
}
})
And in the template:
<div data-my-directive service="alphabet"></div>
The trick here is using service: '=' as this creates a two-way binding between the scope-variable in the controller (which is bound to the service) and the scope-variable in the directive. http://jsfiddle.net/vt52bauu/2/
I don't think the get/set is going to work the way you are expecting in an Angular factory.
this.alphabet = alphabet.get();
I'm trying to create a directive that will output a HTML-template that is using data from a controller.
In sample.js I've added a module, controller and directive
var app = angular.module("myApp", []);
app.controller("MyCtrl", function($scope) {
$scope.someProperty = true;
})
app.directive("myElement", function() {
return {
restrict: "E",
scope: {name: "#"},
template:
'<div ng-show="someProperty">' +
' <p>This element is called {{name}}</p>' +
'</div>',
replace : true,
transclude : false
}
})
I'm using the element with the following HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="angular.min.js"></script>
<script type="text/javascript" src="sample.js"></script>
</head>
<body ng-controller="MyCtrl">
<div><my-element name="Mark"></my-element></div>
<div><my-element name="Vink"></my-element></div>
</body>
</html>
Since the controller is created in the body, I would expect the child-element to be able to use it's properties/methods. But there's no data showing up (without the ng-show, the data shows fine).
In this simplified sample I could move the ng-show to the DOM-element in the HTML, but in my actual application this wouldn't be an option. I really need my directive to be able to use properties (and methods) from my controller.
Is this possible? And what did I miss to get it to work?
Since you are using an isolated scope you have to declare someProperty to use it like this
app.directive("myElement", function() {
return {
restrict: "E",
scope: {
name: "#",
someProperty: "="
},
template:
'<div ng-show="someProperty">' +
' <p>This element is called {{name}}</p>' +
'</div>',
replace : true,
transclude : false
}
});
and you can use it like this
<my-element name="Vink" some-property="someProperty"></my-element>