I've used $mdDialog.show() within a custom directive with a templateUrl property to access a custom template for the the dialog itself, in which I've included two buttons; a 'Cancel' button and a 'Confirm' button.
For each of these I've added an ng-click with calls to 'cancelLeaver()' and 'confirmLeaver()' functions, which I need to be able to write in the directive, but have no idea how I would do.
I've attempted to use the $mdDialog.then() functionality, but this didn't work because of having buttons in a custom view template.
How can I call functions from a view template's ng-click attribute that are written inside a separate directive?
HTML:
<md-dialog ng-controller="mainController" style="min-width: 30vw">
<md-dialog-content>
<h2 class="md-title">Confirm leaver status</h2>
</md-dialog-content>
<md-dialog-content class="minus-padding-top">
<p>Enter employee's leave date below</p>
<br>
<md-input-container class="md-prompt-input-container">
<input id="leaveDate" name="leaveDate" ng-model="employee.leaveDate" ng-init="employee.leaveDate = currentDate" aria-label="Leave Date" required>
</md-input-container>
</md-dialog-content>
<md-dialog-actions>
<md-button ng-click="cancelLeaver()">Cancel</md-button>
<md-button ng-click="confirmLeaver()" ng-disabled="!employee.leaveDate.length">Confirm</md-button>
</md-dialog-actions>
</md-dialog>
Directive:
app.directive('makeLeaver', function($window, $mdDialog, $mdToast, $timeout, $state) {
return {
restrict: 'A',
scope: {
employee: '=',
},
controller: 'employeeDetailsController',
controllerAs: 'employeeDetails',
bindToController: true,
link: function(scope, element, attrs) {
element.bind('click', function() {
console.log('makeLeaver(' + '#' + scope.employee.id + ')');
/* Show confirmation prompt dialog */
$mdDialog.show({
parent: angular.element('body'),
clickOutsideToClose: true,
templateUrl: 'views/employees/employeeDetails/dialogs/makeLeaver.html',
targetEvent: element
})
/* ---------------- TRIED THIS BUT DIDN'T WORK ---------------- */
scope.cancelLeaver = function() {
console.log('cancelLeaver()');
$mdDialog.hide();
}
scope.confirmLeaver = function() {
console.log('confirmlLeaver()');
}
})
}
}
})
You can use $rootScope.$broadcast('foo')
and then receive it elsewher like $rootScope.on('foo').
another way would be to pass the scope through the function.
Check out this tutorial.
Related
I know it is possible to put Controller inside the Directive but I can't make it work of how it should be.
Added plunker link below.
My Working Directive and Controller in One Javascript File
This code works perfectly but I want to modify the app.controller and move it inside my app.directive
app.controller('NameCtrl', function () {
var vm = this;
vm.namePattern = '/^[a-zA-Z ]{1,25}$/';
});
app.directive('nameDirective', function () {
return {
restrict: 'AE',
templateUrl: '/name.html'
}
});
some codes in my Index HTML file
the first <div> is for the above code, and the second <div> is for my directive that I am working on(below).
<div ng-controller="NameCtrl" name-directive></div>
<!--<div name-directive></div> -->
codes in templateURl name.html file
it seems that ng-pattern="ctrl.namePattern" is not working at all, but it is completely working when I use the first JS code above and just modify it to ng-pattern="namePattern".
<input type="text" name="username" class="form-control" placeholder="Enter your first name"
ng-model="username"
ng-minlength="2"
ng-maxlength="20"
required
ng-pattern="ctrl.namePattern"/>
The codes I am working on my JS file (from the codes above)
app.directive('nameDirective', function () {
return {
restrict: 'AE',
scope: {
},
controller: function($scope) {
$scope.namePattern = '/^[a-zA-Z ]{1,25}$/';
},
controllerAs: 'ctrl',
bindToController: true,
templateUrl: '/name.html'
}
});
I hope, I explain clearly my problem.
This is the link of my sample code that I am working on.
If aren't using isolated scope, just remove it from your directive or use scope: true...
app.directive('nameDirective', function () {
return {
restrict: 'AE',
//scope: {}, //Or you can use scope: true (It hasn't much sense in your case)
controllerAs: 'ctrl',
bindToController: true,
controller: function() {
var vm = this;
vm.namePattern = '/^[a-zA-Z ]{1,25}$/';
},
templateUrl: '/name.html'
}
});
See your directive working, I've updated your PLUNKER.
I have an anonymous controller within a directive. That controller, upon a particular event, opens a generic dialog and provides a partial template that is used to add some buttons to the generic dialog via ng-include.
Now within the generic dialog, once the user clicks on any of the provided buttons, I want a particular function in the anonymous controller be called. Any thoughts on how this could be achieved?
Controller:
angular.module('abc')
.directive('xyz', [function() {
return {
restrict: 'E',
scope: {},
controller: ['$scope', function($scope) {
$scope.callThisFunc = function(){};
}]
}
}
Partial template:
<div>
<button label="CANCEL"
ng-click="callThisFunc()">
</button>
</div>
Generic dialog template (different module than the abc module above):
<div ng-include="partial"></div>
Try to use "controllerAs" syntax
angular.module('abc')
.directive('xyz', [function() {
return {
restrict: 'E',
scope: {},
controller: function() {
var vm = this;
vm.callThisFunc = function(){};
return vm;
}],
controllerAs: 'xyzCtrl'
}
}
partial template
<div>
<button label="CANCEL"
ng-click="xyzCtrl.callThisFunc()">
</button>
</div>
generic dialog template
<div ng-include="partial" xyz></div>
</div>
I am trying to build a Slider as an Angular directive. The Problem is, that I need the value of the Slider in my Controller, so I can send it via Json to a Service. The value is used in the Directive to update the length of a corresponding span and should get updated whenever the Slider is moved the value should be updated in the Directive and in the Controller. Right now it just updates the variable to the value I set in the Controller once and then it just stays as it is.
Controller:
angular.module('MyApp')
.controller('SliderController', ['$scope', '$http', function($scope, $http) {
$scope.m = 5;
$scope.m2 = 45;
}]);
Directive:
angular.module('MyApp')
.directive('slider', function ($rootScope) {
return {
replace: true,
restrict: 'E',
scope:{
value: '='
},
link: function (scope, element, attrs) {
scope.header = attrs.header;
scope.unit = attrs.unit;
scope.min = attrs.min;
scope.max = attrs.max;
scope.step = attrs.step;
// scope.value = attrs.value;
// scope.model = attrs.ngModel;
var calculation = function () {
// console.log(scope.value);
return scope.value / scope.max * 100;
};
scope.onChange = function () {
if( isNaN(scope.value) || parseInt(scope.value) > parseInt(scope.max)) {
scope.value = scope.max;
}
scope.width = calculation();
};
},
templateUrl: '../html/slider.html'
};
});
HTML Template
<div class="slider">
<h3>{{header}}</h3>
<div class="progress">
<div class="span-back">
<span style="width:{{width}}%"></span>
</div>
<input class="input-range" type="range" min="{{min}}" max="{{max}}" step="{{step}}" data-ng-model="model" data-ng-change="onChange()" >
</div>
<div class="input-group">
<input type="text" class="input-value" ng-model="model" data-ng-change="onChange()">
<div class="input-base">{{unit}}</div>
</div>
Index HTML
<div ng-controller="SliderController">
<slider id="floating-div" header="My Slider" min="1" max="250" step="1" unit="testunit" data-ng-model="m2" value="m2"></slider>
</div>
If it's the directive's controller, you should declare it as such. And use the bindToController too.
angular.module('MyApp')
.directive('slider', function ($rootScope) {
return {
controller: SliderController,
controllerAs: 'vm',
bindToController: {
value: '='
},
replace: true,
restrict: 'E',
scope: true,
....
See if that works.
Also, don't forget to import the slidercontroller.
import SliderController from './slider.controller.js';
(or whatever your path/name is)
Or if import is not available, write the controller directly into the same file as the directive. So the same as above, without the import, but add in the controller:
function SliderController($scope) {
... etc
}
Then the controller: SliderController; line in the directive should work.
I have a directive in angular and a form which is bound to a scope variable. Code:
<my-directive></my-directive>
<form>
<input ng-model="username" required>
</form>
Directive:
.directive('myDirective', function(){
restrict : 'E',
controller: function($scope){
console.log($scope.username); // Displays user name, same scope!!!
},
link: function(scope, element, attrs){
// Other codes
},
templateUrl: "templates/my-template-url.html"
}
})
The username variable can be reached inside the controller in my directive. This is not why I expected since I close the directive and they shouldn't share the same scope?
Why does this work?
Well you are using scope:false . It can access and change it's parent scope.
So your node scope doesn't matter here because username is in it's parent scope.
<my-directive></my-directive>
<form>
<input ng-model="username" required>
</form>
If your don't wanna to access parent scope then create an isolate scope
Like this
.directive('myDirective', function(){
restrict : 'E',
scope : {},
controller: function($scope){
console.log($scope.username); // Displays user name, same scope!!!
},
link: function(scope, element, attrs){
// Other codes
},
templateUrl: "templates/my-template-url.html"
}
})
I started to learn Angular not so long time ago and I'm trying to understand scope, binding and etc.
I have an order details controller:
orderApp.controller('OrderDetailsController', ['$http','$routeParams','$scope','config', function($http, $routeParams, $scope, config){
var orderCtrl = this;
orderCtrl.orderId = $routeParams.orderId;
orderCtrl.order = {};
orderCtrl.editingView = false;
...
}]);
On order details page I want to output all information about selected order. Also we need to give user ability to edit order. Information about editing mode is stored in orderCtrl.editingView.
I decided to create custom directive. If edit mode is off - display text, otherwise display input.
orderApp.directive('editableText', function(){
return {
restrict: 'E',
scope: {
property: '=property',
editMode: '=editMode'
},
controller: 'OrderDetailsController',
controllerAs: 'orderCtrl',
templateUrl: '/pages/editable-text.html'
}
});
This is template:
<div class="col-xs-8" ng-if="!editMode">{{property}}</div>
<div class="col-xs-8" ng-if="editMode"><input type="text" class="form-control" ng-model="property"></div>
And this is how I use directive in html files:
<editable-text property="orderCtrl.order.coid" edit-mode="orderCtrl.editingView"></editable-text>
Text and input are switching when edit mode is on/off. Problem is that orderCtrl.order.coid property is not updated when I change it in input.
Before edit property looks like:
Turn on edit mode and change value:
Turn off edit mode and we see old value:
Do I need to synchronise controller values and directive scope? I thought that with 2-ways binding it should happen automatically. Probably there is any other way to write this functionality? Will appreciate any help.
UPD
Directive code:
orderApp.directive('editableText', function(){
return {
restrict: 'E',
bindToController: {
property: '=property',
editMode: '=editMode'
},
controller: 'OrderDetailsController',
controllerAs: 'orderCtrl',
templateUrl: '/pages/editable-text.html'
}
});
Directive template:
<div class="col-xs-8" ng-if="!orderCtrl.editMode">{{orderCtrl.property}}</div>
<div class="col-xs-8" ng-if="orderCtrl.editMode"><input type="text" class="form-control" ng-model="orderCtrl.property"/></div>
Directive usage:
<editable-text property="orderCtrl.order.coid" edit-mode="orderCtrl.editingView"></editable-text>
I'm not sure that we really need to pass edit-mode attribute.
You should use bindToController: { ..scope properties.. } option here inside your directive to make sure that isolated scope properties should get bounded to controller this context.
Directive
orderApp.directive('editableText', function(){
return {
restrict: 'E',
bindToController: {
property: '=property',
editMode: '=editMode'
},
controller: 'OrderDetailsController',
controllerAs: 'orderCtrl',
templateUrl: '/pages/editable-text.html'
}
});
Template
<div class="col-xs-8" ng-if="!orderCtrl.editMode">
{{orderCtrl.property}}
</div>
<div class="col-xs-8" ng-if="orderCtrl.editMode">
<input type="text" class="form-control" ng-model="orderCtrl.property"/>
</div>
Note:- this above bindToController: { ..scope properties.. } option available for angular 1.4+ versions.
For Angular 1.3 > version & 1.4 > version you should use former way of doing it by having bindingToController: true to bind scope variable to controller context & do keep the varaibles inside scope: { ...props... }
scope: {
property: '=property',
editMode: '=editMode'
},
bindToController: true