I am very new to Angular. I am trying to read/pass some data to my angular directive from the template.
<div class="col-md-6" approver-picker="partner.approverPlan.data" data-pickerType="PLAN"></div>
I have this in my angular template and I have this in different places. So I want to know in my Angular code, which picker is being clicked.
I am thinking to read the data-pickerType value in my directive.(I am able to read this in jQuery but do not know how to in Angular)
This is my directive code.
Partner.Editor.App.directive('approverPicker', [
'$compile', function ($compile) {
return {
scope: {
"approvers": "=approverPicker"
},
templateUrl: '/template/assets/directive/ApproverPicker.html',
restrict: 'EA',
link: function ($scope, element) {
...........
}
};
}
]);
How can I read the data-pickerType value in the directive or is there a better way of doing this?
The data attributes can be accessed in Angular directive by passing attrs variable in the link function.
Partner.Editor.App.directive('approverPicker', [
'$compile', function ($compile) {
return {
scope: {
"approvers": "=approverPicker"
},
templateUrl: '/template/assets/directive/ApproverPicker.html',
restrict: 'EA',
link: function ($scope, element, attrs) { //passing attrs variable to the function
//accessing the data values
console.log(attrs.pickertype);
//you can access any html attribute value for the element
console.log(attrs.class);
}
};
}
]);
Related
I'm trying to pass a boolean value from my controller into my isolated scope directive. When I console.log(attrs) from the directive's link function, the someBoolean attribute is a string, rendering the actual text "main.bool" instead of a true or false value. When I toggle the boolean value from the outer controller, I want it to be updated in the directive.
https://plnkr.co/edit/80cvLKhFvljnFL6g7fg9?p=preview
app.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
scope: {
someBoolean: '='
},
templateUrl: 'myDirective.html',
link: function(scope, element, attrs) {
console.log(scope);
console.log(attrs);
},
controller: function($scope, $element, $attrs) {
console.log(this);
},
controllerAs: 'directiveCtrl',
bindToController: true
};
});
Controller
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.bool = true;
vm.change = function() {
vm.bool = !vm.bool;
}
});
The template
<div>
Inside directive: {{someBoolean}}
</div>
As you have attached your directive Controller to directiveCtrl instead of mainCtrl, you'll access the variable someBoolean using directiveCtrl.someBoolean.
In this case, change the HTML to:
<div>
Inside directive: {{directiveCtrl.someBoolean}}
</div>
Plunker.
Another solution would be to remove the bindToController property inside your directive. With this, you don't need to use the controller name before the variable. Working Plunker.
Read more about this bindToController feature here.
I have two different custom directive and wanted to pass data from one directive to another. The data is coming from server call. Problem is http being a asyn call doesn't return data upfront and controller of another widget doesnt receive it and it renders it's html without having it. here is the complete code (I have removed some code that might not make sense in the problem)-
The service which hits server is -
angular.module('myModule')
.service('MyService', [
'$http',
function($http) {
this.getData = (someId) => {
var url = someUrl + '/' + someId;
return $http.get(url);
};
}
]);
and the first directive that calls service and set "anotherData" in the scope to be transferred to another directive is -
angular.module('myModule')
.directive('myDirective', ['MyService',
function(MyService) {
return {
restrict: 'E',
scope: {
data: '='
},
templateUrl: 'my-template.html',
controller: ['$scope', function($scope) {
MyService.getData ($scope.data.id).then((response) => {
$scope.anotherData = response.data;
});
}]
}
}]);
and my-template.html from which i am calling another directive is (notice anotherData is passed here -
<other-directive mode="display" data="data" anotherData="anotherData" ></other-directive>
The other directive that should receive "anotherData" but giving me no result is -
angular.module('otherModule')
.directive('otherDirective', [function() {
return {
restrict: 'E',
scope: {
id: '#',
data: '=',
mode: '#',
anotherData: '#'
},
templateUrl: 'other-template.html',
controller: ['$scope', '$element', function ($scope, $element) {
console.log("other data in widget after server call:");
///THIS IS UNDEFINED.
console.log($scope.anotherData);
}],
link: function ($scope, $element) {
}
}
}]);
and other-template.html has iframe to display youtube widget -
<iframe width="{{anotherData.videoWidth}}"
height="{{anotherData.videoHeight}}"
src="{{anotherData.videoURL}}" frameborder="0" allowfullscreen></iframe>
You should use dashes instead of camel case, like this:
<other-directive mode="display" data="data" another-data="anotherData" ></other-directive>
Also, you are binding for text instead of two-way binding an object, so change the definition in your directive to this:
anotherData: '='
This should do the trick
<other-directive another-data=anotherData></other-directive>
You need to be caarefull with the camel case in html!
I have a directive i'm using to do the same search filtering across multiple pages. So the directive will be using a service and get pretty hefty with code. Because of that I want to link to a controller instead of have the controller inside the directive like this:
.directive('searchDirective', function($rootScope) {
return {
restrict: 'E',
templateUrl:'searchtemplate.html',
controller: 'searchCtrl',
controllerAs: 'search'
};
});
I also want access to parent scope data inside the template, so I don't want to use a isolated scope.
Anyway here's what i'm not sure how to do. My directive looks like this:
<search-directive filter="foo"/>
How do I pass in the value in the filter attribute so that I can access it in my controller using $scope.filter or this.filter?
If I were using an isolated scope it'd be simple. If i had the controller in the same page I could use $attrs. But since i'm using a controller from another spot and don't want an isolated scope i'm not sure how to get the attrs values into the controller.
Any suggestions?
What about using the link function and passing the value to the scope?
return {
restrict: 'E',
templateUrl:'searchtemplate.html',
controller: 'searchCtrl',
controllerAs: 'search',
link: function (scope, element, attr) {
scope.filter = attr.filter;
}
};
searchDirective.js
angular
.module('searchDirective', []).controller('SearchCtrl', SearchCtrl)
.directive('SearchDirective', directive);
function directive () {
var directive = {
templateUrl:'searchtemplate.html',
restrict: "E",
replace: true,
bindToController: true,
controller: 'searchCtrl as search',
link: link,
scope: { filter:'=' } // <-- like so here
};
return directive;
function link(scope, element, attrs) {}
}
SearchCtrl.$inject = [
'$scope',
'$filter'];
function SearchCtrl(
$scope,
$filter) {
/** Init SearchCtrl scope */
/** ----------------------------------------------------------------- */
var vs = $scope;
// ....
Also I highly recommend checking out this AngularJS style guide, how you are writing your directive above is how I use to do it too. John Papa shows some way better ways: https://github.com/johnpapa/angular-styleguide
Directives:
https://github.com/johnpapa/angular-styleguide#directives
Controllers:
https://github.com/johnpapa/angular-styleguide#controllers
Flip the values of bindToController and scope around.
{
....
scope: true,
bindToController: { filter:'=' }
...
}
I have just hit the same issue over the weekend, and made a simple complete example here: bindToController Not Working? Here’s the right way to use it! (Angular 1.4+)
I have directive that dynamically sets the header bar content for a given application state.
I would like to be able to access the functions and variables in the Controller of the current view, but I am only ever able to access my RootCtrl.
The directive looks like this.
return {
restrict: 'EA',
template: "<div ng-include='getState()'></div>",
transclude: true,
scope: false,
controller: ['$scope', '$state', function($scope, $state) {
//some logic to retrieve and return the correct header template html
}],
link: function(scope, element, attrs){
console.log(scope.test);
console.log(scope.test2);
}
}
And the controllers.
.controller('RootCtrl', function($scope, $state, $location, $rootScope) {
$scope.test = 'hello';
//...
})
.controller('ContactsCtrl', function($scope, $state, CustomerService) {
console.log('Contacts init');
$scope.test2 = 'hello 2';
//...
})
And when I navigate to the contacts state, the output looks like this.
hello
undefined
Contacts init
What should I do if I want to be able to access the test2 variable?
You will need to use the require property inside your directive.
This will make the scope of the defined controllers available inside the link function as 4th argument. You can access the scopes as an array inside the link function then.
Your code may look like:
return {
restrict: 'EA',
template: "<div ng-include='getState()'></div>",
transclude: true,
scope: false,
require:['^RootCtrl', '^ContactsCtrl'],
controller: ['$scope', '$state', function($scope, $state) {
//some logic to retrieve and return the correct header template html
}],
link: function(scope, element, attrs, requiredControllers){
console.log(requiredControllers[0].test);
console.log(requiredControllers[1].test2);
}
}
See the Angular documentation for Directives for some more examples (under the title Creating Directives that Communicate) and the explanation of the ^controller syntax.
I am trying to write a simple json pretty-printer directive in angular.js. I have:
(function(_name) {
function prettyJson() {
return {
restrict: 'E',
template: '',
link: function($scope, $element, $attr) {
console.log($element.text());
//$element.html(angular.toJson(angular.fromJson($element.text()), true));
}
};
}
angular
.module('ourApp')
.directive(_name, prettyJson);
})('prettyJson');
In my view I am doing:
<pretty-json>{{ auth.get() }}</pretty-json>
The problem is that console.log($element.text()) comes back as {{ auth.get() }} not the angular compiled result of the function call auth.get().
How do I make the directive use the result of the function call auth.get()?
I would swap to using an attribute directive and use the $attr.$observe() function to set up a $watch-like mechanism that will call a listener function every time the interpolated value of the attribute changes.
The directive code:
(function(_name) {
function _directive() {
return {
restrict: 'A',
link: function($scope, $element, $attr) {
$attr.$observe(_name, function (json) {
$element.text(angular.toJson(angular.fromJson(json), true));
});
}
};
}
angular
.module('ourApp')
.directive(_name, _directive);
})('prettyJson');
Usage in markup:
<pre pretty-json="{{ auth.get() }}"></pre>
See my Plunkr example.
You could just pass the content you want to format in as a parameter to your directive. e.g.:
JS
(function(_name) {
function prettyJson() {
return {
restrict: 'E',
scope: {
prettyJson: '='
},
template: '<pre>{{prettyJson | json}}</pre>',
};
}
angular
.module('ourApp')
.directive(_name, prettyJson);
})('prettyJson');
HTML
<pretty-json="auth.get()"></pretty-json>