I'm passing through a JavaScript object to an Angular.js directive. When logging attrs in the link function, I see my attribute there, but when logging attrs.myOptions there is no data:
var directive = function() {
return {
restrict: 'E',
replace: true,
scope: {
myOptions: '='
},
link: function(scope, element, attrs) {
console.log(scope)
console.log(attrs)
console.log(attrs.myOptions)
}
}
}
And i'm implementing it in my template like so:
<directive my-options="myObject" />
myObject is a JavaScript object that's set in the controller for the template.
And I'm getting this error in the console:
Syntax Error: Token 'myObject' is unexpected, expecting [:] at column 3 of the expression [{{myObject}}] starting at [myObject}}].
As suggested above you can use like this. only change that you have to access model though scope.
var myApp = angular.module('myApp', []);
myApp.directive("directive",function() {
return {
restrict: 'E',
replace: true,
scope: {
myOptions: '='
},
link: function(scope, element, attrs) {
console.log(scope)
console.log(attrs)
console.log(scope.myOptions)
}
}
});
myApp.controller('myCtrl', function($scope) {
$scope.myObject = [1,2,3,4,5];
console.log("app controller");
});
<!doctype html>
<html>
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<head>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<directive my-options="myObject" />
</div>
</body>
</html>
Related
I am trying to access my scope variables in link but they appear undefined
/** #ngInject */
function tablePagination() {
return {
restrict: 'E',
template: require('./tablePagination.html'),
scope: {
currentPage: '=',
totalPages: '=',
totalCount: '=',
perPage: '='
},
link: function (scope) {
console.log(scope.currentPage, scope) // scope.currentPage is undefined
}
}
}
// controller for authlogin
module.exports = tablePagination
I also tried using # rather than = and changed the binding to using {{}} but its still undefined. I could use $observe but I want to get values for multiple attributes at once to do some computation. Whats the best way to do this?
HTML Code
<table-pagination
current-page="$ctrl.tableMeta.currentPage"
total-count="$ctrl.tableMeta.totalCount"
total-pages="$ctrl.tableMeta.totalPages"
per-page="$ctrl.tableMeta.perPage"></table-pagination>
UPDATE: I wonder if its because the directive is not getting updated values from $ctrl.tableMeta which is coming from API/Async
SOLUTION!: Oh I discovered my mistake was I need to use $watch otherwise it gets the old value which is by default undefined, since its not set async by API yet
scope.$watch('currentPage', () => {
scope.start = (scope.currentPage - 1) * scope.perPage + 1
scope.end = Math.min(scope.currentPage * scope.perPage, scope.totalCount)
})
Its just an example i hope it will clear few things up.
gridPagination.html
<label>current Page:</label><span>{{ currentPage }}</span>
<br>
<label>Total Pages:</label> {{ totalPages }}
app.js
var app = angular.module("myApp", []);
mainController.js
app.controller('mainController', ['$scope', function($scope) {
$scope.title = 'My Grid';
}]);
gridDirective.js
app.directive('grid', gridPagination);
function gridPagination() {
return {
restrict: 'E',
scope: {
currentPage: '=',
totalPages: '=',
totalCount: '=',
perPage: '='
},
templateUrl: 'gridPagination.html',
link: function(scope, element, attrs) {
console.log(scope.currentPage);
console.log(scope.totalPages);
console.log(scope.totalCount);
console.log(scope.perPage);
}
};
};
index.html
<html>
<head>
<link rel="stylesheet" href="main.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="mainController">
<grid current-page="3" total-pages= "30" total-count="10" per-page="2"></grid>
</div>
<script src="app.js"></script>
<script src="mainController.js"></script>
<script src="gridDirective.js"></script>
</body>
</html>
plunker
I've created some basic directive. It works well if I use it with some objects in html file
<some-directive some-data="123"></some-directive>
But if I dynamically load this object to my webpage:
//getting html source as a string, then appending it to DOM:
elem.html("<some-directive some-data='123'></some-directive>");
The directive doesn't work (object is being added properly to DOM)
app.directive('someDirective', function (notes, parts) {
return {
restrict: 'AE',
scope: {
someData: '='
},
link: function (scope, elem, attrs) {
console.log("directive fired");
}
};
});
What can I do to make it work properly?
For dynamic directives, you have to use $compile service that compiles scope into template. Look at sample below, <some-directive-wrapper /> will add <some-directive /> element into itself and compile scope value
var app = angular.module('app', []);
app.directive('someDirective', function () {
return {
restrict: 'AE',
scope: {
someData: '='
},
template: '<h2>someDirective compiled, someData is {{someData}}</h2>',
link: function (scope, elem, attrs) {
console.log("directive fired");
}
};
});
app.directive('someDirectiveWrapper', function ($compile) {
return {
restrict: 'AE',
link: function (scope, elem, attrs) {
//get value from ajax maybe
//and set to scope
scope.data = 123;
//replace directive with another directive
elem.html('<h1>someDirectiveWrapper compiled </h1>\n<some-directive some-data="data"></some-directive>');
//compile scope value into template
$compile(elem.contents())(scope);
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<some-directive-wrapper></some-directive-wrapper>
</div>
I have a directive like
testApp.directive('changeValue', function(){
alert("coming");
return {
restrict: 'E',
link: function (scope, element, attrs) {
element.text(attrs.val);
},
replace: true
};
});
and I have my views as follows
<change-value val="{{test.val}}"/>
When I refresh my page, I could see the values and I get the alerts. But when the value is changed I don't get it applied to the directive but it binds to the view as I could see it being changed outside when simply called like
<span>{{test.val}}</span>
I am not sure how this works. Thanks in Advance!
In your code, the link function is executed only once so the value is updated only when the directive instance is created. Since you want to have a watch of its value and keep updating the text you can use $observe()
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.test = {
val: "Welcome"
};
});
app.directive('changeValue', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
attrs.$observe('val', function() {
element.text(attrs.val);
})
},
replace: true
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app" ng-controller="AppController">
<change-value val="{{test.val}}"></change-value>
<input ng-model="test.val" />
</div>
I'm trying to bind to ng-change on an element created by a directive up through two other directives that wrap it to a method on the controller using & bindings in an isolate scope, but I can't figure out how to get arguments to pass all the way through. Here's a plunk that demonstrates the problem.
In short, I have an HTML structure like this:
<body ng-app="ExampleApp">
<div ng-controller="Controller">
<button ng-click="doSomething('Called directly')">Call Function Directly</button>
<br />
<outer on-outer-model-changed="doSomething('Called from Outer in HTML')"></outer>
</div>
</body>
The controller:
var app = angular.module('ExampleApp', []);
app.controller('Controller', ['$scope',
function($scope) {
$scope.doSomething = function(one, two, three) {
console.log(arguments);
};
}
]);
The outer directive:
app.directive('outer', function($compile) {
return {
restrict: 'E',
scope: {
outerModelChanged: '&onOuterModelChanged'
},
link: function(scope, element, attrs) {
var innerElement = angular.element('<inner></inner>');
innerElement.attr('on-inner-model-changed', 'outerModelChanged(\'Called from Outer\')');
element.after(innerElement);
$compile(innerElement)(scope);
console.log(arguments);
}
}
});
And the inner directive that the outer directive creates:
app.directive('inner', function() {
return {
scope: {
innerModelChanged: '&onInnerModelChanged'
},
restrict: 'E',
template: '<button ng-click="innerModelChanged(\'Called from Inner\')">Call from Inner</button>'
}
});
I understand that I'm getting the output ["Called from Outer in HTML"] because this is hardcoded into the <outer> tag. What I don't understand is how to pass arguments all the way up from the inner directive.
I'm not sure I 100% get what you want to accomplish but this is how you would make the ["Called from Inner"] message appear.
Change the html so the on-outer-model-changed expression does not use a hardcoded string.
<body ng-app="ExampleApp">
<div ng-controller="Controller">
<button ng-click="doSomething('Called directly')">Call Function Directly</button>
<br />
<outer on-outer-model-changed="doSomething(outerParam)"></outer>
</div>
</body>
Then change the outer directive to call outerModelChanged with a parameter. And set the outerParam to the innerParam.
app.directive('outer', function($compile) {
return {
restrict: 'E',
scope: {
outerModelChanged: '&onOuterModelChanged'
},
link: function(scope, element, attrs, controller) {
var innerElement = angular.element('<inner></inner>');
innerElement.attr('on-inner-model-changed', 'outerModelChanged({outerParam:innerParam})');
element.after(innerElement);
$compile(innerElement)(scope);
console.log(arguments);
}
}
});
Finally call the innerModelChanged from the inner directive with the innerParam set to your message.
app.directive('inner', function() {
return {
scope: {
innerModelChanged: '&onInnerModelChanged'
},
restrict: 'E',
template: '<button ng-click="innerModelChanged({innerParam:\'Called from Inner\'})">Call from Inner</button>'
}
});
Here is a plunk to the above code.
I'm new to AngularJS. I'm trying to write a directive that will set the background-color of a <div> based on some scenario. Essentially, in my view, I want to be able to write this code:
<div effect-color="#2D2F2A">content here</div>
or
<div effect-color="{{effectColor}}">content here</div>
I know I need a directive. Currently, I'm doing this:
.directive('effectColor', [
function () {
return {
restrict: 'A',
controller: [
'$scope', '$element', '$attrs', '$location',
function ($scope, $element, $attrs, $location) {
// how do I get the value of effect-color here?
}
]
}
}
]);
I'm not sure how to get the value of the attribute itself. Do I need to add a scope? I just want the attribute value.
Thank you!
Here are two methods... First gets the attribute value through looking at the elements attribute value of your directive. The second gets passed the attribute value and attached to the isolated scope of your directive. Please note I have replaced your controller with a linking function. I suggest you give this article a read: https://docs.angularjs.org/guide/directive
Codepen: http://codepen.io/anon/pen/cGEex
HTML:
<div ng-app="myApp">
<div effect-color-one="#123456"></div>
<div effect-color-two="#123456"></div>
</div>
JavaScript:
angular.module('myApp', [])
.directive('effectColorOne', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
console.log('example 1: ' + attrs.effectColorOne);
}
}
}
)
.directive('effectColorTwo', function () {
return {
restrict: 'A',
scope: {
effectColorTwo: '#'
},
link:function (scope) {
console.log('example 2: ' + scope.effectColorTwo);
}
}
}
);
Another example
combining the above example and the ability to change the background colour of the element which the directive attribute resides is below:
Codepen: http://codepen.io/anon/pen/HospA
HTML:
<div ng-app="myApp">
<div effect-color="red">Hello</div>
</div>
JavaScript:
angular.module('myApp', [])
.directive('effectColor', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.css('background-color', attrs.effectColor);
}
}
}
);
You can get the value in your directive controller using $attrs parameter object
$attrs.effectColor // #2D2F2A
From the docs:
attrs is a hash object with key-value pairs of normalized attribute
names and their corresponding attribute values.
Also if you are going to modify the DOM (in your case applying background color) you should use link option.
DEMO
Seems like a duplicate of How to get attribute value of a custom tag in angularjs?
I think you need something like scope: { data: "=data" } in the definition of your directive
Please see here :http://jsfiddle.net/MP8ch/
<div ng-app="app">
<div ng-controller="firstCtrl">
<div effect-color="#fc9696">
<P>content here</P>
</div>
</div>
</div>
JS:
var app = angular.module('app', []);
app.directive('effectColor', function () {
return {
restrict: 'AE',
transclude: true,
// replace:'true',
scope: {
color: '#effectColor'
},
restrict: 'AE',
template: '<div style="background-color:{{color}}" ng-transclude></div>'
};
});
app.controller('firstCtrl', function ($scope) {
});
You can create an isolate scope and bind the attribute to it:
myApp.directive('effectColor', [
function () {
return {
restrict: 'A',
scope: {
effectColor: '='
},
link: function (scope, element, attrs) {
element.css({
color: scope.effectColor
});
},
controller: [
'$scope', '$element', '$attrs', '$location',
function ($scope, $element, $attrs, $location) {
console.log($scope.effectColor);
}]
}
}]);
http://jsfiddle.net/R7Rb6/
It's a scenario of a directive with itself as the attribute. See here that how can you actually get value in your directive.