How can I get my directive to access the controllers scope - angularjs

I have a setup like this:
<controller>
<directive>
in my controller that has a function that returns an html string. How can I get my directive to render this by accessing the controllers scope?
Or maybe I should just put the controller in the directive?
app.controller('controller', ['$scope', 'DataService', function ($scope, DataService) {
$scope.parseJson = function () {
//returns the html
};
}]);
directive
app.directive('Output', function () {
return {
restrict: 'A',
replace: true,
template: '<need html from controller>',
link: function(scope, element, attr) {
//render
//scope.parseJson();
}
};
});

You should use the isolated scope: '&' option
app.directive('output', ['$sce', function ($sce) {
return {
restrict: 'A',
replace: true,
template: "<div ng-bind-html='parsed'></div>",
scope:{
output: "&"
},
link: function(scope){
scope.parsed = $sce.trustAsHtml(scope.output());
}
};
}]);
Template:
<div output="parseJson()"></div>

The directive and the controller should be sharing the scope already. Don't bother using a template for the directive, just get the HTML string in you linking function (you already have the method call in there) and modify the element directly using element.html(). Take a look at the element docs for more info.

app.directive('Output', function ($compile) {
return {
restrict: 'A',
link: function(scope, element, attr) {
var templateString = scope.parseJson();
var compiledTemplate = $compile(templateString)(scope);
compiledTemplate.appendTo("TheElementYouWishtoAppendYourDirectiveTo");
}
};
});

Related

Is there any ways to update directive link with scope or some other values?

I have dC directive
app.directive('dC', function($rootScope) {
return {
restrict: 'AE',
link: function(scope, element, attrs) {},
templateUrl: function(elem, attrs) {
return $rootScope.somePosiT
}
}
});
And I want to access inside of my controller as function is there anyway can I achieve it in order to change my directive location dynamically when click fired
app.controller('appCtrl', function($scope, $rootScope) {
clk: function() {
$rootScope.somePosiT = 'views/1.html'
}
})
I think you could do it using template and ng-include - rather than templateUrl. I think templateUrl is called before the scope values are available. You could try something like this:
app.directive('dC', function($rootScope) {
return {
restrict: 'AE',
link: function(scope, element, attrs) {},
template: '<div ng-include="somePosiT"></div>'
};
});
app.controller('appCtrl', function($scope, $rootScope) {
$scope.clk = {
somePosiT: "path/to/template.html"
};
});

scope variable of the controller is not recognized in nested directives

I have created two directives and inserted the first directive into the second one. The content of template attribute works fine but the scope variable of the controller is not recognized. Please provide me solution on this
sample link: http://jsbin.com/zugeginihe/2/
You didn't provide the attribute for the second directive.
HTML
<div second-dir first-dir-scope="content">
<div first-dir first-dir-scope="content"></div>
</div>
Link demo: http://jsbin.com/jotagiwolu/2/edit
The best option would using parent directive, We could take use of require option of directive like require: '?secondDir' in firstDir
Code
var myApp = angular.module("myApp", []);
myApp.controller("myController", function($scope) {
$scope.content = "test1";
});
myApp.directive("firstDir", function() {
return {
restrict: "AE",
require: '?secondDir',
scope: {
firstDirScope: "="
},
template: "<div>first content</div>",
link: function(scope, element, attrs, secondDir) {
console.log(scope.firstDirScope, 'first');
}
};
});
myApp.directive("secondDir", function() {
return {
restrict: "AE",
scope: {
firstDirScope: "="
},
controller: function($scope) {
console.log($scope.firstDirScope, 'second');
}
};
});
Working JSBin

Cannot $compile template with same class as directive even though directive is declared as restrict "E"

Say I have a directive "foo":
app.directive("foo", function($compile) {
var innerTemplate = $compile('<div class="foo"></div>');
return {
restrict: "E";
};
}));
Why is it that the $compile call will fail, complaining that fooDirective depends on fooDirective, even though the directive is declared to be restricted to "E"?
Edit: Added example fiddle: https://jsfiddle.net/n4bvkbp7/1/
The directive "foo" must be fully defined before you can compile it. Try putting your compile statement in your directives link function:
app.directive("foo", function($compile) {
return {
restrict: "E",
link: function() {
var linkFn = $compile('<div class="foo"></div>');
}
};
}));
I don't see why you need a $compile service here:
ngModule.directive('foo', ['$compile', function($compile) {
return {
restrict: 'E',
template: '<div class="foo">foo</div>',
link: function(scope, element, attrs){
//TODO:
}
}
}]);
You were using $compile function outside of return statement, that means that will execute in its compile time, you can compile your element postLink function only.
Directive
var app = angular.module("app", []);
app.directive("foo", function($compile) {
return {
restrict: "E",
link: function(scope, element, attrs){
var innerTemplate = $compile('<div class="foo">HELLO WORLD</div>');
element.append(innerTemplate(scope));
//do other logic here
}
};
});
JsFiddle

how to pass variable from controller to directive using click event in angularjs

i am using directive concept in angularjs to pass data varible from controller to directive.i am writing one html page and controller,directive in angularjs.
test.html:
<div ng-controller="myController"
data-angular-treeview="true"
data-tree-model="roleList"
data-node-id="roleId"
data-tree-id="mytree"
data-node-label="roleName"
data-node-children="children"
data-ng-click="selectNode(currentNode)"
>
</div>
testcontroller.js:
(function(){
app.controller('myController', function($scope,$http,TreeService){
$scope.selectNode=function(val)
{
$scope.nodeval=val.roleName;
alert("select:"+$scope.nodeval);
};
});
})();
testdirective.js:
app.directive('tree1', function($rootScope) {
function compile(scope, element, attributes) {
return {
post:function(scope, iElement, iAttrs) {
iElement.bind('click', function() {
alert("click: "+scope.node);
});
}
};
}
return {
compile: compile,
scope: {
},
restrict: 'AE',
};
});
here i am getting selected node name in testcontroller.js but i want to pass that nodename in my directive so please suggest me how to this.
Thanks
What i would do is define inside the directive isolated scope an attribute like this:
scope: {
node: '='
}
And inside the view controller have a node initialized as $scope.node = {}; and with the click event change the value of the local $scope.node to the node you are interested in, and as the directive recieved the reference to the $scope.node attribute inside the view controller, it would automatically update itself
<div test-directive node-value="node"></div>
isolate scope directive:
directive('testDirective', function(){
return {
restrict: 'EA',
scope: {
nodeValue: '='
},
link: function(scope, element, attrs){
console.log(scope.nodeValue);
}
}
Access controller scope:
directive('testDirective', function(){
return {
restrict: 'EA',
link: function(scope, element, attrs){
console.log(scope.$eval(attrs['nodeValue']));
}
}

Angularjs: set parent directive scope value with child directive

I'm not sure this is the way to do this, but my goal is the following:
I have a parent directive
Inside the parent directive's block, I have a child directive that will get some input from the user
The child directive will set a value in the parent directive's scope
I can take it from there
Of course the problem is that the parent and child directives are siblings. So I don't know how to do this. Note - I do not want to set data in the
Fiddle: http://jsfiddle.net/rrosen326/CZWS4/
html:
<div ng-controller="parentController">
<parent-dir dir-data="display this data">
<child-dir></child-dir>
</parent-dir>
</div>
Javascript
var testapp = angular.module('testapp', []);
testapp.controller('parentController', ['$scope', '$window', function ($scope, $window) {
console.log('parentController scope id = ', $scope.$id);
$scope.ctrl_data = "irrelevant ctrl data";
}]);
testapp.directive('parentDir', function factory() {
return {
restrict: 'ECA',
scope: {
ctrl_data: '#'
},
template: '<div><b>parentDir scope.dirData:</b> {{dirData}} <div class="offset1" ng-transclude></div> </div>',
replace: false,
transclude: true,
link: function (scope, element, attrs) {
scope.dirData = attrs.dirData;
console.log("parent_dir scope: ", scope.$id);
}
};
});
testapp.directive('childDir', function factory() {
return {
restrict: 'ECA',
template: '<h4>Begin child directive</h4><input type="text" ng-model="dirData" /></br><div><b>childDir scope.dirData:</b> {{dirData}}</div>',
replace: false,
transclude: false,
link: function (scope, element, attrs) {
console.log("child_dir scope: ", scope.$id);
scope.dirData = "No, THIS data!"; // default text
}
};
});
If you want that kind of communication, you need to use require in the child directive. That will require the parent controller so you need a controller there with the functionality you want the children directives to use.
For example:
app.directive('parent', function() {
return {
restrict: 'E',
transclude: true,
template: '<div>{{message}}<span ng-transclude></span></div>',
controller: function($scope) {
$scope.message = "Original parent message"
this.setMessage = function(message) {
$scope.message = message;
}
}
}
});
The controller has a message in the $scope and you have a method to change it.
Why one in $scope and one using this? You can't access the $scope in the child directive, so you need to use this in the function so your child directive will be able to call it.
app.directive('child', function($timeout) {
return {
restrict: 'E',
require: '^parent',
link: function(scope, elem, attrs, parentCtrl) {
$timeout(function() {
parentCtrl.setMessage('I am the child!')
}, 3000)
}
}
})
As you see, the link receives a fourth param with the parentCtrl (or if there is more than one, an array). Here we just wait 3 seconds until we call that method we defined in the parent controller to change its message.
See it live here: http://plnkr.co/edit/72PjQSOlckGyUQnH7zOA?p=preview
First, watch this video. It explains it all.
Basically, you need to require: '^parentDir' and then it will get passed into your link function:
link: function (scope, element, attrs, ParentCtrl) {
ParentCtrl.$scope.something = '';
}

Resources