Custom directive should pass function to parent scope? - angularjs

I have a search box which I want to use as a custom directive. This is the code for it :
(function(angular) {
'use strict';
angular.module('searchApp', [])
.directive('searchBox', function () {
return {
restrict: 'E',
transclude: true,
scope: {
'btnclick': '&onClick'
},
link: function(scope, elem, attrs) {
});
});
},
templateUrl: 'search-box.html'
}
});
})(window.angular);
In the link part, I need a function that has some JSON data. And then, a directive should have a controller that invokes that function and passes it to the parent scope.
Please show me code for the link function and the controller.

Related

custom directives - child directives do not show up when enclosed within parent directive

Note: ui-grid is name of my custom grid. Sorry about the confusion.
I have a custom directive which will have a child custom directive and will be called in this fashion in the html.
<ui-grid resource="/api/data.json">
<ui-gridcolumns>
</ui-gridcolumns>
</ui-grid>
When the child directive is enclosed within the parent directive, the console statements do not print, but when the child directive is outside of the parent directive, it prints console.log just fine. Any insight into how to make it work with the child directive within the parent directive is appreciated.
parent directive:
module.exports = function () {
return {
restrict: 'E',
templateUrl: 'app/ui-grid/grid.template.html',
link: function (scope, element, attrs) {
console.log('linked Grid');
},
controller: ['$scope', function ($scope) {
$scope.onthescreen = 'test value';
}]
};
};
Child directive:
module.exports = function () {
return {
restrict: 'E',
templateUrl: 'app/ui-grid/gridcolumns/grid.columns.template.html',
link: function (scope, element, attrs) {
console.log('linked Grid Columns');
},
controller: ['$scope', function ($scope) {
console.log('calling Grid Columns');
}]
};
};
The entire code base is in git for reference.
https://github.com/eshrinivasan/angular-gulp-browserify-boilerplate
To achieve desired behavior use transclusion:
config:
restrict: 'E',
templateUrl: 'app/ui-grid/grid.template.html',
link: function (scope, element, attrs) {
console.log('linked Grid');
},
controller: ['$scope', function ($scope) {
$scope.onthescreen = 'test value';
}],
transclude: true
and somewhere in template:
<div ng-transclude>
child directives will be placed here
</div>

AngularJS: Directive communicating with other other directives via controller API

Child directive communicating with the parent directive
The following code below works perfectly, except when I uncomment the template line in the parent directive (parentD)
.directive('parentD', ['$window', function($window) {
return {
restrict: 'E',
scope: {},
controller: function($scope) {
this.testvar = 'Hello';
this.doSomething = function() {
$window.alert("This is an alert from the parent");
return this.testvar;
}
},
//template: '<h1>Parent Template</h1>'
}
}])
.directive('childD', ['$window', function($window) {
return {
restrict: 'E',
require: '^parentD',
scope: {},
template: '<h2>Child Template</h2>',
link: function(scope, element, attribute, controller) {
$window.alert('The parent passes this message ' + controller.doSomething());
}
}
It seems to not execute the child directive when this line is uncommented.
http://plnkr.co/edit/h3bMe5mJ0QnbRHIla8l9
Thanks for any help, I'm sure I have made a mistake somewhere, I just need an extra set of eyes on it.
(function(angular) {
'use strict';
angular.module('directiveExample', [])
.directive('parentD', ['$window', function($window) {
return {
restrict: 'E',
scope: {},
replace:true,
transclude: true,
controller: function($scope) {
this.testvar = 'Hello';
this.doSomething = function() {
$window.alert("This is an alert from the parent");
return this.testvar;
}
},
template: '<div><h1>Parent Template</h1><div ng-transclude></div></div>'
}
}])
.directive('childD', ['$window', function($window) {
return {
restrict: 'E',
require: '^parentD',
replace:true,
scope: {},
template: '<div><h2>Child Template</h2></div>',
link: function(scope, element, attribute, controller) {
$window.alert('The parent passes this message ' + controller.doSomething());
}
}
}])
})(window.angular);
I think you'll understand what I've done.
But feel free to ask any question.
Now check your both templates are working properly.
Here, I have used ng-transclude in parent template to show parent template content as well as child template (with its content) because we have parent-child scenario.
You can check this working link,
http://plnkr.co/edit/pIkN5Uc3JYQpsbKOMcY1?p=preview

combining transclude and directive inheritance in AngularJS

i have this html
<div ng-app="myApp">
<parent>
<child></child>
</parent>
</div>
and the following Angular code
var myApp = angular.module('myApp',[]);
myApp.directive('parent', function() {
return {
transclude: true,
link: function(scope, element, attrs) {
scope.getContent = function () {
console.log('called getContent');
}
},
restrict: 'E',
template: '<span>parent <span ng-transclude></span></span>'
}
});
myApp.directive('child', function() {
return {
restrict: 'E',
scope:true,
template: '<div>child</div>',
link: function(scope, element, attrs) {
scope.getContent();
}
}
});
JSfiddle of the above is here
my problem in this example is i can see the inheritance working and transclusion working in isolation but when i try to combine the two, the child directive has no knowledge of the parent scope and hence the function getContent. So no console.log and before that the child directive errors that scope.getContent is undefined.
I realise that this might be that the child directive is no longer a child having been transcluded so i was thinking i need to start playing with post and prelink functions in the compile method maybe? or do i need to define a custom transclude function in the parent?
Any pointers for the code or further reading appreciated - i have read and similar questions on here about this kind of thing but am finding it difficult to follow and hoping some one can solve my hello world to kickstart my understanding
thanks in advance
You should read that article: http://www.undefinednull.com/2014/07/07/practical-guide-to-prelink-postlink-and-controller-methods-of-angular-directives/
Basically, your child link is called before the parent one. What you want to do is use your parent pre-link function so scope.getContent is defined beforte the child is linked.
link: {
pre: function (scope, element, attrs) {
scope.getContent = function () {
console.log('called');
}
}
}
JSfiddle: http://jsfiddle.net/floribon/gpwasrkz/3/
Have a look at "Creating Directives that Communicate" in the docs. Maybe this is a solution for what you are trying o achieve. You can require the parent controller and call it's functions:
var myApp = angular.module('myApp', []);
myApp.directive('parent', function () {
return {
transclude: true,
controller: function ($scope) {
this.getContent = function () {
console.log('called')
}
},
link: function (scope, element, attrs) {},
restrict: 'E',
template: '<span>parent <span ng-transclude></span></span>'
}
});
myApp.directive('child', function () {
return {
restrict: 'E',
scope: true,
require: '^parent',
template: '<div>child</div>',
link: function (scope, element, attrs, ctrl) {
ctrl.getContent();
}
}
});
See this fiddle.

How can I get my directive to access the controllers scope

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");
}
};
});

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