I create a directive, and want to use dynamic template with attribute wm.data.typeName.
wm.data.typeName = "<span>html code</span>"
<fill-choose model-input="wm.data.modelInput" text="wm.data.typeName"></fill-choose>
and directive fillChoose is
(function() {
'use strict';
angular
.module('learn')
.directive('fillChoose', fillChoose);
/** #ngInject */
function fillChoose($showdown) {
var directive = {
restrict: 'AE',
template: function(elem, attr) {
//return $showdown.makeHtml(fill.modelInput);
return '<div>'+ attr.modelInput +'</div>';
},
scope: {
modelInput: '=',
text: '='
},
controller: FillChooseController,
controllerAs: 'fill',
bindToController: true
};
return directive;
/** #ngInject */
function FillChooseController($scope) {
var vm = this;
}
}
})();
But in this way, template will be <div>wm.data.modelInput</div>.
How to make the template be <div><span>html code</span></div> ?
link: function(scope, elem, attr) {
//return $showdown.makeHtml(fill.modelInput);
elem.html($compile('<div>{{fill.modelInput}}</div>')(scope));
}
Now for this very case a simple
template:'<div>{{fill.modelInput}}</div>';
Would work, but i gave the $compile thing because you may gave only a simplified version of what you're really trying to do.
you have to print it
<fill-choose model-input="{{ wm.data.modelInput }}" text="wm.data.typeName"></fill-choose>
but this will work once, because template function will call once, when directive is initialized (when angular calles compile to compile template), that's why you need to pass it through directive's scope
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 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 an Angular 1.3 module that looks something like this (directive that requires the presence of a parent directive, using controllerAs):
angular.module('fooModule', [])
.controller('FooController', function ($scope) {
this.doSomething = function () {
// Accessing parentDirectiveCtrl via $scope
$scope.parentDirectiveCtrl();
};
})
.directive('fooDirective', function () {
return {
// Passing in parentDirectiveCtrl into $scope here
link: function link(scope, element, attrs, parentDirectiveCtrl) {
scope.parentDirectiveCtrl = parentDirectiveCtrl;
},
controller: 'FooController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'
};
});
Here I'm just using $scope to pass through parentDirectiveCtrl, which seems a little clunky.
Is there another way to access the require-ed controller from the directive's controller without the linking function?
You must use the link function to acquire the require-ed controllers, but you don't need to use the scope to pass the reference of the controller to your own. Instead, pass it directly to your own controller:
.directive('fooDirective', function () {
return {
require: ["fooDirective", "^parentDirective"],
link: function link(scope, element, attrs, ctrls) {
var me = ctrls[0],
parent = ctrls[1];
me.parent = parent;
},
controller: function(){...},
};
});
Be careful, though, since the controller runs prior to link, so within the controller this.parent is undefined, until after the link function runs. If you need to know exactly when that happens, you can always use a controller function to pass the parentDirective controller to:
link: function link(scope, element, attrs, ctrls) {
//...
me.registerParent(parent);
},
controller: function(){
this.registerParent = function(parent){
//...
}
}
There is a way to avoid using $scope to access parent controller, but you have to use link function.
Angular's documentation says:
Require
Require another directive and inject its controller as the fourth
argument to the linking function...
Option 1
Since controllerAs creates namespace in scope of your controller, you can access this namespace inside your link function and put required controller directly on controller of childDirective instead of using $scope. Then the code will look like this.
angular.module('app', []).
controller('parentController', function() {
this.doSomething = function() {
alert('parent');
};
}).
controller('childController', function() {
this.click = function() {
this.parentDirectiveCtrl.doSomething();
}
}).
directive('parentDirective', function() {
return {
controller: 'parentController'
}
}).
directive('childDirective', function() {
return {
template: '<button ng-click="controller.click()">Click me</button>',
link: function link(scope, element, attrs, parentDirectiveCtrl) {
scope.controller.parentDirectiveCtrl = parentDirectiveCtrl;
},
controller: 'childController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'
}
});
Plunker:
http://plnkr.co/edit/YwakJATaeuvUV2RBDTGr?p=preview
Option 2
I usually don't use controllers in my directives at all and share functionality via services. If you don't need to mess with isolated scopes of parent and child directives, simply inject the same service to both of them and put all functionality to service.
angular.module('app', []).
service('srv', function() {
this.value = '';
this.doSomething = function(source) {
this.value = source;
}
}).
directive('parentDirective', ['srv', function(srv) {
return {
template: '<div>' +
'<span ng-click="srv.doSomething(\'parent\')">Parent {{srv.value}}</span>' +
'<span ng-transclude></span>' +
'</div>',
transclude: true,
link: function(scope) { scope.srv = srv; }
};
}]).
directive('childDirective', ['srv', function(srv) {
return {
template: '<button ng-click="srv.doSomething(\'child\')">Click me</button>',
link: function link(scope) { scope.srv = srv; }
}
}]);
Plunker
http://plnkr.co/edit/R4zrXz2DBzyOuhugRU5U?p=preview
Good question! Angular lets you pass "parent" controller. You already have it as a parameter on your link function. It is the fourth parameter. I named it ctrl for simplicity. You do not need the scope.parentDirectiveCtrl=parentDirectiveCtrl line that you have.
.directive('fooDirective', function () {
return {
// Passing in parentDirectiveCtrl into $scope here
link: function link(scope, element, attrs, ctrl) {
// What you had here is not required.
},
controller: 'FooController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'};});
Now on your parent controller you have
this.doSomething=function().
You can access this doSomething as
ctrl.doSomething().
How we can get particular isolated scope of the directive while calling link function from controller(parent)?
I am having a directive and repeating it using ng-repeat. Whenever a button in the directive template is clicked it will call a function- Stop() in directive controller which in-turn calls function test() in parent controller, inside test() it will call a method dirSample () in directive's link function.
When I print the scope inside dirSample(), it prints the scope of the last created directive not the one which called it.
How can I get the scope of the directive which called it?
Find the pluker here
.directive('stopwatch', function() {
return {
restrict: 'AE',
scope: {
meri : '&',
control: '='
},
templateUrl: 'text.html',
link: function(scope, element, attrs, ctrl) {
scope.internalControl = scope.control || {};
scope.internalControl.dirSample = function(){
console.log(scope)
console.log(element)
console.log(attrs)
console.log(ctrl)
}
},
controllerAs: 'swctrl',
controller: function($scope, $interval)
{
var self = this;
self.stop = function()
{
console.log($scope)
$scope.meri(1)
};
}
}});
full code in plunker
I've changed the binding of your function from & to = since you need to pass a parameter. This means some syntax changes are in order, and also you need to pass the scope along the chain if you want to have it all the way at the end:
HTML:
<div stopwatch control="dashControl" meri="test"></div>
Controller:
$scope.test = function(scope)
{
console.log(scope);
$scope.dashControl.dirSample(scope);
}
Directive:
.directive('stopwatch', function() {
return {
restrict: 'AE',
scope: {
meri : '=',
control: '='
},
templateUrl: 'text.html',
link: function(scope, element, attrs, ctrl) {
scope.internalControl = scope.control || {};
scope.internalControl.dirSample = function(_scope){
console.log(_scope);
}
},
controllerAs: 'swctrl',
controller: function($scope, $interval)
{
var self = this;
self.stop = function()
{
console.log($scope);
$scope.meri($scope);
};
}
}});
Plunker
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>