I am novice in AngularJS. I want to use one template for two directives. In deal, the first directive overrides the behavior of the second. But I've specified different controllers for each of them. I think the reason is isolation of scopes by controllers. I need that the first controller execute its own filterChanged() function and so does the second controller. Same with fields: montage, pay, cancel and inactivity. I tried to manipulate the scope (true, 'isolate', false, {}), transclude (true, false, 'element'), scope fields ('#', '=', '&'). 'controllerAs' and 'controllerBindTo' are unsuitable for my task, because I want to this throw separate controller files.
Help me plz. Hands fall.
Source code below.
filter.html
<div class="filter">
<p class="text-center"><b ng-bind="::title"></b></p>
<div class="contact-item-requires-filter">
<div class="contact-item-require">
<input id="contact-item-montage-filter" class="contact-item-require-montage" type="checkbox"
ng-model="filter.montage"
ng-change="filterChanged()">
<label title="Монтажи" for="contact-item-montage-filter"></label>
</div>
</div>
directive1.js
angular.module('qualityControl')
.directive('requiresFilterDirective', function() {
return {
templateUrl: '../templates/pages/quality/filter.html',
controller: 'requiresFilterController'
}
});
directive2.js
angular.module('qualityControl')
.directive('usersFilterDirective', function() {
return {
templateUrl: '../templates/pages/quality/filter.html',
controller: 'usersFilterController'
}
});
UPDATED.
Add variable with '&', this is function declaration
.directive('requiresFilterDirective', function () {
return {
restrict: 'AE',
scope: {
functionToCall: '&',
someData: '='
},
templateUrl: '../templates/pages/quality/filter.html',
link: function (scope, elem, attrs) {
scope.functionToCall();
console.log('scope.someData', scope.someData);
}
}
})
Usage:
<requires-filter-directive function-to-call="myFunctOne()" some-data="yourJsonObject"></requires-filter-directive>
<requires-filter-directive function-to-call="myFunctTwo()" some-data="yourJsonObject"></requires-filter-directive>
And declare these functions in your main controller:
$scope.myFunctOne = function() {
alert("111")
};
$scope.myFunctTwo = function() {
alert("222")
};
$scope.yourJsonObject = {'aaa':123};
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
Im having a hard time accessing the attributes passed in to my directive from the template of that directive. I want to be able to access 'companyId' from album.tmpl.html but no matter what i try i can't get it. The strangest part is i can see it has made its way in to the controller, but somehow it's not getting from the controller to the template. I know the template is correctly calling the controller as it can succesfully print out the value of 'testVar' which is initialised inside the controller. Any advice would be appreciated.
directive + directive controller
(function () {
'use strict';
angular.module('erCommon')
.directive('erAlbum', albumDirective)
.controller('AlbumController', AlbumController);
function AlbumController() {
var vm = this;
vm.testVar = "test var initiated";
}
function albumDirective($log) {
function albumLink(scope, element, attrs, AlbumController) {
//watch vars in here
}
return {
restrict: 'E',
scope: {
companyId: '=companyId'
},
bindToController: true,
templateUrl: 'components/temp/album.tmpl.html',
controller: 'AlbumController',
controllerAs: 'albumCtrl',
link: albumLink
};
}
})();
template ( album.tmpl.html
<div ng-controller="AlbumController as albumCtrl">
testVar: {{albumCtrl.testVar}}<BR>
companyId:{{albumCtrl.companyId}}<BR>
</div>
usage
<er-album company-id="2"></er-album>
output
test var: test var initiated
companyId:
You need to remove ng-controller from your template:
<div>
testVar: {{albumCtrl.testVar}}<BR>
companyId:{{albumCtrl.companyId}}<BR>
</div>
To achieve the result you wanted i had to modify the structure of your code slightly. Hope this helps you to understand the issue. Look for materials about isolated scopes which Angular uses with directives.
HTML:
<div ng-app="erCommon" ng-controller="AlbumController as albumCtrl">
<er-album company-id="2" test = "albumCtrl.testVar"></er-album>
</div>
Controller:
angular.module('erCommon', [])
.directive('erAlbum', albumDirective)
.controller('AlbumController', AlbumController);
function AlbumController() {
var vm = this;
vm.testVar = "test var initiated";
}
function albumDirective() {
return {
restrict: 'E',
scope: {
test: '=test',
companyId: '#companyId'
},
template: '<div> testVar: {{test}}<BR> companyId:{{companyId}}<BR> </div>', // it will work fine with templateUrl as well, just didn't want to cr8 another file...
link: function(scope, element, attrs){
//do whatever else you might need;
}
};
}
i've created a custom directive in angularjs:
directives.directive('myTop',function($compile) {
return {
restrict: 'E',
templateUrl: 'views/header.html',
}
})
Directive's code:
<div class="my-header">
<button ng-click="alert('x')" class="fa fa-chevron-left"></button>
<h1>SpeakZ</h1>
</div>
for some reason, ng-click doesen't trigger.
I searched over the internet and found that compile / link is the solution for this problem,
but I can't seem to reach a working solution.
I am not using jquery..
You'll need to add a link function to the directive definition for this to work. So basically,
var app = angular.module("myApp", [])
app.directive('myTop',function() {
return {
restrict: 'E',
template: '<button ng-click="clickFunc()">CLICK</button>',
link: function (scope) {
scope.clickFunc = function () {
alert('Hello, world!');
};
}
}
})
And the html:
<div ng-app="myApp">
<my-top></my-top>
</div>
And here's the fiddle: http://jsfiddle.net/4otpd8ah/
Either use link as answered by #Ashesh or just simply add scope. If you set scope false you will not have isolated scope and click will work on directive.
directives.directive('myTop',function($compile) {
return {
restrict: 'EA',
scope: false,
templateUrl: 'views/header.html',
}
})
i have a Article Item page that is composed of several re-usable directives. one section of the page has several of these directives that make the main article for the page.
<div data-ng-controller="ArticleItemController">
<article-breadcrumb data-bread-crumbs="model.breadCrumbs"></article-breadcrumb>
<article-title data-title="model.title"></article-title>
<div id="home-main">
<div id="post-area">
<social-box></social-box>
<article-content-area data-content="model.content"></article-content-area>
<article-author-info data-author="model.author"></article-author-info>
<article-tags data-tags="model.tags"></article-tags>
<social-box></social-box>
</div>
<prev-next-article data-articles="model.prevNextArticle"></prev-next-article>
<related-article data-articles="model.relatedArticles"></related-article>
<comments data-comments="model.comments"></comments>
</div>
</div>
my controller to gets the promise, then i pass parts of model to my directives via attributes.
app.controller('ArticleItemController', function ($scope, genApi)
{
$scope.model = $scope.model || {};
genApi.Articles.get({ Id: 60 }).$promise.then(function (data) {
$scope.model = data;
});
});
but this doesn't seem to work or it's sometimey. the only way i can see the data from the directives is if i do this and force the $apply.
app.directive('articleBreadcrumb', function ($timeout)
{
return {
restrict: 'EA',
replace: true,
scope: { breadCrumbs: '=' },
templateUrl: '/app/directives/articleItem/articleBreadcrumb/articleBreadcrumb.html',
link: function (scope) {
$timeout(function() {
$timeout(function () {
console.log(scope.breadCrumbs);
}, 0);
},0);
}
};
});
what are some better ways of doing this?
Your way of thinking is right, indeed the best way to pass data to your directives is using attributes, or if your directive is very simple you can even inherit the data from your parent scope.
Here are 2 example directives, one for each case:
app.directive('myScopedDirective', function() {
return {
restrict: 'E',
scope: {content: '='},
replace: true,
template: '<div>{{content}}</div>'};
});
app.directive('myInheritedDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<div>{{content}}</div>'};
});
And here is a working plunkr demonstrating the promise resolving:
http://plnkr.co/edit/a1MDQpjtWAfTYfLpiypC?p=preview
Hope that helps
I want to know how to invoke a function residing in controller on the ng-click event of template element. I have to use this directive in many pages.Hence I need to handle the click event in respective controller pages.The below code invokes the click function (moreitemdetails) residing within the directive.I tried setting the scope as moreitemdetails: '=' . It is also not working.
I have been using the directive
app.directive('groceryList', function){
return {
restrict: 'E',
scope: {
array: '=',
listItemClick:'&',
moreitemdetails: '&',
},
templateUrl: 'list.html',
link: function(scope, element, attrs) {
scope.label = attrs.label;
scope.listItemClick=function(e){
$(e.currentTarget).find('.next-items').slideToggle('fast');
}
scope.moreitemdetails=function(name,type){
//other code
}
}
};
});
The call for directive is
<grocery-list array="items"></grocery-list>
This is the template file
<div ng-click="listItemClick($event)">
<div>
<div class="item">
<span class="item-details">
{{array[0].Item}}
</span>
<span class="down-arrow"></span>
</div>
<div class="next-items">
<ul>
<li class="item" ng-repeat="list in array">
<div class="item-details" ng-click="moreitemdetails(list.Name,list.Type)">{{list.Item}}</div>
</li>
</ul>
</div>
Is there a way to get around?
I also would like to know the use of $location within another directive. Quoting the previous example (everythin is same except the directive definition and action in moreitemdetails() )
app.ui.directive('groceryList', ['$location', function(location){
return {
restrict: 'E',
scope: {
array: '=',
listItemClick:'&',
moreitemdetails: '&',
},
templateUrl: 'list.html',
link: function(scope, element, attrs) {
scope.label = attrs.label;
scope.listItemClick=function(e){
$(e.currentTarget).find('.next-items').slideToggle('fast');
}
scope.moreitemdetails=function(name,type){
$location.path('/home/');
}
}
};
}]);
Thanks in advance
So by declaring
scope: {
array: '=',
listItemClick:'&',
moreitemdetails: '&',
},
you are creating an isolated scope for your directive. One solution might be to not declare this scope in your directive. This would mean that your ng-click="moreitemdetails(list.Name,list.Type) would trigger the function on your controllers scope.
Alternatively you could use an emit and listener. To do this, in your directive you could call:
scope.moreitemdetails=function(name,type){
var deets = {
name: name,
type: type
};
scope.emit('moreitemdetails',deets)
}
Then in your various controllers you implement:
scope.$on('moreitemdetails',function(event,details){
// do some code with your name and type
}
I'm not sure exactly what you would like to know about $location, if you could be a bit more specific I might be able to help a more.
Hope this helps in some way!
EDIT:
The directive without any scope declared would look like this:
return {
restrict: 'E',
templateUrl: 'list.html',
link: function(scope, element, attrs) {
scope.label = attrs.label;
scope.listItemClick=function(e){
$(e.currentTarget).find('.next-items').slideToggle('fast');
}
scope.moreitemdetails=function(name,type){
//other code
}
}
};