Can't bind object to directive scope from another directive - javascript

I have started to use directives with ui-router:
$stateProvider
.state('book', {
abstract: true,
url: '/:book',
template: '<book-tabs />'
})
.state('book.about', {
url: '',
template: '<book-about />'
})
.state('book.stats', {
url: '/statistics',
template: '<book-stats />'
});
Here is one of the directives:
export default function(app) {
app.directive('bookStats', function() {
return {
restrict: 'E',
controllerAs: 'statsTab',
templateUrl: 'book-stats.tpl.html',
controller: 'BookStatsCtrl'
};
});
};
Inside of book-stats directive I want to call stats-list directive and pass book object.
<stats-list review="statsTab.book"></stats-list>
And here is stats-list directive:
export default function(app) {
app.directive('statsList', function() {
return {
restrict: 'E',
scope: {
book: '='
},
templateUrl: 'stats-list.tpl.html',
controller: 'CircleRankListCtrl'
};
});
};
The problem is that $scope.book is undefined in stats-list directive even though that statsTab.book not undefined in book-stats directive.
What am I doing wrong?

Related

Unknown provider: $uibModalProvider <- $uibModal <- modalPopDirective

I am using Angular's $uibModal and trying to create popup while page has been loaded. It is not working. I think problem in directive. This is my code:
angular.module('myModule', ['ui.bootstrap'])
.directive('modalPop', ModalDirective)
.controller('ModalController', ModalController);
function ModalDirective($uibModal) {
return {
scope: {},
restrict: 'E',
templateUrl: 'directives/modal/tutorial.html',
controller: function () {
return $uibModal.open({
controller: 'ModalController',
windowClass: 'outside ' + size,
animation: true,
templateUrl: './client/dialogs/' + template + '.html',
resolve: {
dialogParams: function () {
return {
title: 'title',
message: 'message'
};
}
}
});
}
};
}
function ModalController($uibModalInstance) {
$scope.close = function () {
$uibModalInstance.dismiss();
};
}
How can I get this to work?
You are not injecting the provider into the directive's controller. Also try explicitly injecting the provider into the directive:
ModalDirective.$inject = ['$uibModal'];
function ModalDirective($uibModal) {
return {
scope: {},
restrict: 'E',
templateUrl: 'directives/modal/tutorial.html',
controller: function ($uibModal) {
return $uibModal.open({
controller: 'ModalController',
windowClass: 'outside ' + size,
animation: true,
templateUrl: './client/dialogs/' + template + '.html',
resolve: {
dialogParams: function () {
return {
title: 'title',
message: 'message'
};
}
}
});
}
};
}
If that doesn't work, then you have not properly included the JS file for Angular UI Bootstrap. (This is most likely the cause)

angular scope.$watch not working

I have a directive where i bind the tabInfo to tabdata which is an array.
angular.module('widgets')
.directive('tabs', function() {
return {
restrict: 'E',
require: 'info',
transclude: true,
scope: {},
controllerAs: 'tabs',
bindToController: {
tabInfo: '=tabdata'
},
templateUrl: 'Template.html',
link: function(scope, element, attrs, tabs) {
scope.$watch('tabs.tabInfo', function() {
tabs.populateDataProvider();
}, true);
},
controller: ['$filter', '$state', function($filter, $state) {
}]
};
});
I need to watch on the "tabInfo" for any change and populate some data. However , my watch is not called at all. Is there something wrong here , in the way that I am refering to tabs.tabInfo?
A better solution to this would be to have an ng-if along with the directive so as to make sure that the directive is rendered only when there is data to populate . This avoids the need of having a watcher inside the directive .
So you could use ,
<tabs ng-if="$ctrl.tableData.length" tab-info="$ctrl.tableData"></tabs>
For your question above , you need to bind this to a variable to tabs
to get it work .
var tabs = this;
EDIT:
There is also a correction on your code . It should be ,
angular.module('widgets')
.directive('tabs', function() {
return {
restrict: 'E',
require: 'info',
transclude: true,
bindToController: true,
controllerAs: 'tabs',
scope: {
tabInfo: '=tabdata'
},
templateUrl: 'Template.html',
link: function(scope, element, attrs, tabs) {
scope.$watch('tabs.tabInfo', function() {
tabs.populateDataProvider();
}, true);
},
controller: ['$filter', '$state', function($filter, $state) {
}]
};
});

Md-dialog not loading the controller associated with it

I am trying to load md-dialog in angular js1.5 when on click of button and all i see is the html markup in modal pop up but not the controller loads for that component. Following is my markup for showing the md-dialog
File which calls the dialog
$mdDialog.show ({
template: require('../traderdialog/traderdialog.html'),
controller: Controller,
controllerAs: 'vm',
locals : {
traderId : traderId
},
clickOutsideToClose : true
});
}
So when I do controller :Controller it goes to different component as I have in my directory structure . My code for traderdialog.js follows as
angular.module('dashboard')
.component('traderdialog', {
template: require('./traderdialog.html'),
controller: Controller,
controllerAs: 'vm',
bindings: {
}
});
function Controller( $mdDialog) { *some code* }
$mdDialog.show ({
template: require('../traderdialog/traderdialog.html'),
controller: function ControllerName($scope){
$scope.data = "Controller Loaded";
},
locals : {
traderId : traderId
},
clickOutsideToClose : true
});
}
OR
$mdDialog.show ({
template: require('../traderdialog/traderdialog.html'),
controller: controllerName,
locals : {
traderId : traderId
},
clickOutsideToClose : true
});
}
function controllerName($scope){
$scope.data = "Controller Loaded";
}
There is two way to use controller in mdDialog, one of them is use same scope with the parent in preserve scope:
$mdDialog.show({
controller: function () {
return self;
},
templateUrl: 'templates/mdDialog.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: false,
bindToController: true,
scope: $scope,
hasBackdrop: true,
preserveScope: true
});
another one is use with controllerAs attribute, and initialize it:
$mdDialog.show({
controller: DialogController,
templateUrl: 'templates/mdDialog.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true,
controllerAs: 'DlgCtrl',
bindToController: true,
locals: {
formData: $scope.formData,
}
})
and you can reach your locals with DlgCtrl.formData syntax.
You should inject the data you want from the parent controller to the the scope of modal. When modal opens it has its own scope.
$mdDialog.show ({
template: require('../traderdialog/traderdialog.html'),
controller: 'MyCtrl',
locals : {
traderId : traderId
},
clickOutsideToClose : true
});
}
Now, lets define your controller for you modal traderdialog.html.
angular.module('app').controller('MyCtrl',['traderId', function(traderId){
console.log(traderId);
}]);
Now the traderId will reflect on your modal.

angularjs: vm is undefined, when using contronllerAs syntax in directive

I can not access the vm.screensize property from the relevant controller. The error I am receiving is the vm is not defined. Below are the directive and controller.
angular.module('app.ain.directives')
.directive('ainProjectWizardExplanations', function() {
return {
restrict: 'E',
bindToController: true,
scope : {
sidenavHidden : '='
},
controller: 'ProjectWizardExplanationsController as vm',
templateUrl: function() {
console.log(vm.screensize, vm.animate);
if(vm.screensize) {
return 'app/ain/shared/directives/projectWizardExplanationsMobile.html';
}else {
return 'app/ain/shared/directives/projectWizardExplanations.html';
}
}
};
});
//controller
angular
.module('app.ain.directives')
.controller('ProjectWizardExplanationsController', ProjectWizardExplanationsController);
function ProjectWizardExplanationsController($mdMedia,$scope,$rootScope, $timeout) {
var vm = this;
vm.animate = true;
$scope.$watch(function() { return $mdMedia('sm'); }, function(small) {
vm.screensize = small;
});
}
Try setting the "controllerAs" option when declaring the directive instead.
.directive('ainProjectWizardExplanations', function() {
return {
restrict: 'E',
bindToController: true,
scope : {
sidenavHidden : '='
},
controller: 'ProjectWizardExplanationsController',
controllerAs: 'vm',
templateUrl: function() {
console.log(vm.screensize, vm.animate);
if(vm.screensize) {
return 'app/ain/shared/directives/projectWizardExplanationsMobile.html';
}else {
return 'app/ain/shared/directives/projectWizardExplanations.html';
}
}
};
});
Hope that works for you :)

error while passing data to directive in Angular

I have this simple directive:
angular.module('app')
.directive('ppBubble', function () {
function PpBubble($scope, $element, $attrs) {
var vm = this;
vm.message = $attrs.message;
vm.isSent = $attrs.sent;
}
return {
templateUrl: '../views/directives/ppBubble.html',
restrict: 'E',
controller: PpBubble,
controllerAs: 'vm',
bindToController: true
};
});
And here is how I use it:
<pp-bubble ng-repeat="msg in vm.messages" sent="{{msg.sent}}" message="{{msg.message}}"></pp-bubble>
The problem is that I see this "msg.message" instead of the string this object attribute hold:
Here is the messages array:
vm.messages = [
{
sent: true,
message: "aasdasd dsfsdfd"
}, ...
]
I am probably missing something stupid :(
The problem is that you're doing vm.message = $attrs.message; and you're taking the string literally, which means: {{msg.message}}, since that's the text that's written in that attribute:
message="{{msg.message}}".
You need to work with a scope to make Angular work its binding magic, and take the data from there:
function PpBubble($scope, $element, $attrs) {
var vm = this;
vm.message = $scope.message;
vm.isSent = $scope.sent;
}
return {
templateUrl: '../views/directives/ppBubble.html',
restrict: 'E',
scope: { message: "=", sent: "=" },
controller: PpBubble,
controllerAs: 'vm',
bindToController: true
};
Here is the messages array:
vm.messages = [
{
sent: true,
message: "aasdasd dsfsdfd"
}, ...
]
EDIT: Another thing is that now that you're binding from the directive, you need to bind to the variable itself, and not to its string literal, meaning to remove the {{}} from the directive HTML:
<pp-bubble ng-repeat="msg in messages" sent="msg.sent" message="msg.message"></pp-bubble>
Fiddle
Here is what worked for me:
function PpBubble($scope, $element, $attrs) {
var vm = this;
}
return {
templateUrl: '../views/directives/ppBubble.html',
restrict: 'E',
controller: PpBubble,
controllerAs: 'vm',
bindToController: true
};
});
Also i removed the {{}} from the html:
Thanks to #Omri Aharon

Categories