My HTML looks like this:
Controller HTML:
<div ng-controller="Ctrl">
<first-directive></first-directive>
</div>
first-directive HTML
<li>
<second-directive></second-directive>
</li>
Controller JS:
app.controller('Ctrl', (#scope) => {
$scope.foo = function() {
console.log('do smthn');
}
});
first directive:
app.directive('first-directive', function(){
return {
restrict: 'E',
templateUrl: '/partials/first-directive.html',
replace: true,
scope: {
// some data
}
controllerAs: function(){}
}
}
second directive:
app.directive('second-directive', function(){
return {
restrict: 'E',
templateUrl: '/partials/second-directive.html',
controllerAs: function(){}
}
}
So i have controller with nested directive and there is another nested directive. When i'm trying to call $parent.foo() from first-directive it works. When i'm trying to call $parent.$parent.foo() from second-directive it doesn't work. I tried also use ng-controller="Ctrl as ctrl" and ctrl.foo() from second-directive syntax, but it doesn't work either. Why?
have you added second directive inside
<div ng-controller="Ctrl">
are you using in ng-if before second directive? because ng-if also creates its own scope
You can use $rootScope.$broadcastin nested directive controller and then on parent controller use $rootScope.$on.
In second directive
app.directive('second-directive', function(){
return {
restrict: 'E',
templateUrl: '/partials/second-directive.html',
controller: function($rootScope){
$rootScope.$broadcast('parentCtrl',{});
}
}
}
In parent controller
app.controller('Ctrl', ($scope,$rootScope) => {
$scope.foo = function() {
console.log('do smthn');
}
$rootScope.$on('parentCtrl', function (event, data){
//do the parent task here
}
});
You can also use service function to communicate between the child controller and parent controller.
As second nested directive doesn't have isolated scope, try $parent.foo()
Related
So I have a directive and inside the directive view (html) I put a controller however its affecting the rest of the viewModel (vm). What's the best way to isolate a controller to only control specific viewModel?
That's the structure of the view model and directive, I thought ng-controller="ctrl as vm" would only find vm within the class of "controller" but instead its finding every vm on the page.
Directive:
var directive = {
templateUrl: '/Content/app/core/scaffolding/views/popup.html',
restrict: 'A',
link: function (scope, element, attributes) {
console.log('something')
}
};
view:
<div class="directive">
<div class="moreVm">
</div>
<div class="controller" ng-controller="ctrl as vm">
<button ng-click="vm.find()"></button>
</div>
</div>
I tried making "ctrl as jvm" but still the same haha, its just a guess.
<div class="controller" ng-controller="ctrl as jvm">
<button ng-click="jvm.find()"></button>
</div>
Try this.
var directive = {
restrict: "A",
scope: true,
bindToController: {},
controller: "ctrl as vm",
templateUrl: "/Content/app/core/scaffolding/views/popup.html"
};
I've come up with an example using directives which may be of some help - Plunker
As you can see clicking the button in directive2 does not set the value of $scope.aValue in directive1.
JS
var app = angular.module('plunker', [])
.directive("directive1", function accountDir() {
return {
restrict: "EA",
templateUrl: "directive1.html",
scope: {},
controller: function ($scope) {
$scope.$watch("aValue", function(newValue) {
console.log(newValue);
})
}
};
}
)
.directive("directive2", function accountDir() {
return {
restrict: "EA",
templateUrl: "directive2.html",
scope: {},
controller: function ($scope) {
$scope.setAValue = function () {
$scope.aValue = 42;
console.log($scope.aValue);
}
}
};
}
);
Markup
<body>
<directive1></directive1>
</body>
directive1.html
<directive2></directive2>
directive2.html
Directive2
<br>
<button ng-click="setAValue()">Set a value</button>
If I not guess wrong,you want do that when ctrl as different names, the directive console.log different value? or in vm but the value within directive is different with out of the directive?
if you want first ,you just make two controller and then set different value;
controller('ctrl1',function(){ this.name});
controller('ctrl2',function(){ this.name});
else want two
directive('myDir',function(){ return {restrict:'AE',scope:{},controller:function(){this.name='haha'}}})
and now the value is isolate with outer
I am currently writing an angular directive that uses a template in a different HTML file and an isolated template. The directive gets some string via # to its scope and that value is available in teh controller function.
Somehow its not available via {{}} in the HTML template. Why is that so? How can I change that? I read something about the template using the parent scope but I don't fully understand that.
Here is a code example:
angular.module('moduleName')
.directive('aGreatDirective', function () {
return {
restrict: 'E',
scope: {
mapid: '#'
},
templateUrl: "path/to/template.html",
controller: ['$scope', function (scope) {
console.log($scope.mapid); // is defined
}
}
});
And the html code for the template:
<div id="{{mapid}}"></div>
The result in the browser is exactly the same where it should be:
<div id="theValueOfmapid"></div>
Thanks for your help!
PS Here is a jsfiddle: fiddle
Your fiddle was incorrect since you didn't have your controller defined or $scope injected properly. The following will work just fine:
template:
<div ng-controller="MyCtrl">
<a-great-directive mapid="thisisthemapid"></a-great-directive>
Some other code
</div>
js:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function () {
});
myApp.directive('aGreatDirective', function() {
return {
restrict: 'E',
scope: {
mapid: '#'
},
template: "<div id='{{mapid}}'> {{mapid}} </div>",
controller: ['$scope', function($scope) {
console.log($scope.mapid); // is defined
}
]}
});
Fiddle
Note that in my example, the injected variable in your directive's controller should be $scope, not scope, for consistency reasons.
take a look at the following code:
html:
<body ng-app="myApp">
<div ng-controller="MainController">
<input type="button" ng-click="talk()" value="outside directive" />
<div my-element>
<input type="button" ng-click="talk()" value="inside directive" />
</div>
</div>
</body>
js:
var app = angular.module('myApp', []);
app.controller('MainController', function($scope){
$scope.talk = function() {
alert('HELLO1');
}
});
app.directive('myElement', function(){
return {
restrict: 'EA',
scope: {},
controller: function($scope) {
$scope.talk = function() {
alert('HELLO2');
}
}
};
});
as you can see, there's a controller, which nests a directive.
there are 2 buttons, one in controller level (outside of directive), and one is inside the directive my-element.
the main controller defines a scope method talk, the nested directive controller also defines a method - talk - but keep in mind that directive has isolated scope (i'd expect that talk method won't be inherited into directive's scope).
both buttons result an alert of 'HELLO 1', while i expected the second button (inside directive) to alert 'HELLO 2' as defined in directive controller, but it doesn't - WHY?
what am i missing here? how could i get a result when the second button will alert 'HELLO 2' but with the same method name ("talk") ?
thanks all
If you want the inner content to use the directive scope, you need to use manual transclusion:
app.directive('myElement', function(){
return {
restrict: 'EA',
scope: {},
transclude: true,
link: function(scope, element, attr, ctrl, transclude) {
transclude(scope, function(clone, scope) {
element.append(clone);
});
},
controller: function($scope) {
$scope.talk = function() {
alert('HELLO2');
}
}
};
});
By default, transcluded content uses a sibling of the directive scope. I actually don't know how angular handles DOM content for directives that don't use transclude (which is what makes this an interesting question), but I would assume from the behavior you are seeing that those elements use the directive's parent scope by default.
This will work for you
<body ng-app="myApp">
<div ng-controller="MainController">
<input type="button" ng-click="talk()" value="outside directive" />
<div my-element></div>
</div>
</body>
app.directive('myElement', function(){
return {
restrict: 'A',
template: '<input type="button" ng-click="talk()" value="inside directive">',
replace: true,
scope: {},
controller: function($scope) {
$scope.talk = function() {
alert('HELLO2');
}
}
};
});
My first try at angularjs.
I'm trying to create a directive that will, on click, call a function that is declared in the model's controller function.
Here is my simplified code: http://jsfiddle.net/vnj62xn8/
JS:
angular.module('tasks', [])
.controller('taskCtrl', function($scope){
$scope.complete = function(){
console.log('parent function');
}
})
.directive('taskList', function(){
return {
restrict: 'E',
scope: {
complete: '&'
},
template: '<button ng-click="complete()">Complete Task</button>',
controller: function($scope){
/*$scope.complete = function(){
console.log('child function');
}*/
}
}
});
HTML:
<div ng-app="tasks">
<task-list></task-list>
</div>
I've looked at other Q/As on SO and found that this seems to be the most generalized solution, although it will never call the complete() function found in the taskCtrl controller. It will, however, call the complete() function from the directive's controller, if uncommented. What am I missing?
You need to write the html as following:
<div ng-controller="taskCtrl">
<task-list complete="complete()"></task-list>
</div>
Here is the link to updated fiddle http://jsfiddle.net/paila/vnj62xn8/4/
Simply change your code to :
.directive('taskList', function(){
return {
restrict: 'E',
scope: {
complete: '&'
},
template: '<button ng-click="complete()">Complete Task</button>',
controller: 'taskCtrl' // Here you are referencing the taskCtrl
}
});
You just need to reference your existing controller inside the controller assignment
Angular directive;
.directive('ngFilemanager', function () {
return {
restrict: 'EA',
scope: {
thefilter: '=',
},
link: function (scope, element, attrs) {
},
templateUrl: '/templates/filemanager.html',
controller: FileManagerController
}
Html:
<div id="testcontainer" ng-controller="OtherController">
...
<div ng-click="vm.myfunction">Set Filter</div>
...
<div id="thefilemanager" ng-filemanager thefilter=""></div>
...
</div>
How can i set thefilter value in a function of OtherController?
I tried setting the attribute value by jquery but my ng-view isn't updated correctly then.
You've got bi-directional isolated scope so:
function OtherController($scope){
$scope.myfilter= "";
$scope.setFilter = function(what){
$scope.myfilter = what;
}
}
and HTML:
<div id="testcontainer" ng-controller="OtherController">
<div ng-click="setFilter('fun')">Set Filter</div>
<div id="thefilemanager" ng-filemanager thefilter="myfilter"></div>
</div>
Then when you change $scope.myfilter in the OtherController's scope, scope.thefilter changes in your directive's scope.
If the "other" controller is not a direct parent, you could use $emit or $broadcast depending on where the target is.
Here's an example using $broadcast instead:
app.controller('MainCtrl', function($scope) {
$scope.setFilter = function(what){
$scope.$broadcast('setFilter', what);
}
});
then inside your directive you can listen:
link: function (scope, element, attrs) {
scope.$on('setFilter', function(e, what){
scope.thefilter = what;
});
},
To make it work anywhere, you can $broadcast from $rootScope, but at that point you might want to re-evaluate why you have to do this. Angular itself does this a lot, for example, routeChangeSuccess event, but that doesn't mean you should do it.
This will work if the other controller is a parent of ngFilemanager
<div id="thefilemanager" ng-filemanager thefilter="theFilterValue"></div>
In some other controller
...
$scope.theFilterValue = 'some other value';
...
Look the doc's isolate scope on directives section