How can i use controller object values in angular directive? - javascript

I have angular select on main page once user select value i want these object values in directive e.g $scope.selectedFileSize.value and $scope.selectedFileSize.size so i can further implement logic in directive. Any idea ?
main.html
<div class="col-md-3">
<select class="form-control" ng-model="selectedFileSize" ng-options="item as item.value for item in FileSizeOptions" ng-change="onSizeChange()"><option value="">Select</option></select>
</div>
<progress-bar-custom message="event"></progress-bar-custom>
Controller.js
$scope.onSizeChange = function(){
$scope.maxMb = $scope.selectedFileSize.size;
$scope.maxBytes = 3000;
$scope.max = $scope.maxBytes;
$scope.FileSizeString = $scope.selectedFileSize.value;
console.log('FileSize',$scope.maxMb);
}
directive.js
angular.module("App").directive('progressBarCustom', function() {
return {
restrict: 'E',
scope: {
message: "="
},
templateUrl: '/view/partials/progressbar.html',
controller: function($scope) {
var data = $scope.message;
var currentFileBytes = [];
var currentBytesSum;
$scope.maxBytes = 3000; // how to get these values from controller
$scope.max = $scope.maxBytes;
$scope.FileSizeString = $scope.selectedFileSize.value; //How can i get these values from controller.
$scope.random = function(value) {
$scope.dynamic = value;
$scope.downloadPercentage = parseFloat((value / $scope.maxBytes) * 100).toFixed(0);
console.log('current value-dynamic', $scope.dynamic);
};
}
});

You can define them as bindings in your directive scope:
scope: {
message: "=",
objToBind: "=" // add this one
},
And in HTML:
<progress-bar-custom message="event" obj-to-bind="selectedFileSize"></progress-bar-custom>
Then you could access it in your directive controller:
$scope.FileSizeString = $scope.objToBind.value
EDIT
I guess you want to dynamically change $scope.FileSizeString when your select is changed, right? Then I think you need to $watch in directive, otherwise it's always the initial value, and you won't aware of the changes in the future.
I don't know exactly how you implement your app, so I wrote a simple demo that demonstrate the key points:
I moved your default select option into ng-options array, and instead use ng-init to set default option.
I use $watch in directive to observe the binding's value change.
var app = angular.module('myApp', [])
app.controller('myCtrl', ['$scope', function($scope) {
$scope.fileSizes = [
{size: -1, value: 'Select'},
{size: 1, value: '1MB'},
{size: 2, value: '2MB'},
{size: 3, value: '3MB'}
]
$scope.onSizeChange = function() {
console.log($scope.selected.size)
}
}])
app.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
selectedSize: '='
},
template: '<div style="font-family:monospace"><p><b>Your choice:</b> {{myChoice}}</p><p><b>Actual Choice:</b> {{selectedSize}}</p></div>',
controller: function($scope) {
$scope.myChoice = ''
$scope.$watch('selectedSize', function (newVal, oldVal) {
$scope.myChoice = (newVal && newVal.size !== -1) ? newVal.value : ''
})
}
}
})
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<select ng-options="opt as opt.value for opt in fileSizes"
ng-model="selected"
ng-init="selected = fileSizes[0]"
ng-change="onSizeChange()">
</select>
<my-directive selected-size="selected"></my-directive>
</div>
</div>

Pass your required object through the isolate scope
HTML
<progress-bar-custom message="event" file="selectedFileSize"></progress-bar-custom>
JS
restrict: 'E',
scope: {
message: "=",
file: "="
},
templateUrl: '/view/partials/progressbar.html',

Since you have created an isolate scope in your directive, it is not normally recommended to use the $parent property, but rather to identify which variables you want to use from your parent scope. I would recommend that you pass in the variables you want to include in your directive in your html like so:
<progress-bar-custom message="event" fileSize="selectedFileSize.size" fileValue="selectedFileSize.value"></progress-bar-custom>
Then, in your directive in your scope attribute, you can add the variables.
scope: {
message: "=",
fileSize: "=",
fileValue: "="
},

You can use :-
scope.$parent.propertyName
inside your controller to access $scope level variables

Related

Pass controller variable value to directive in AngularJS

I'm working on a fiddle that I found from this answer on SO
I've modified the fiddle for my situation in the following way:
angular.module('sampleApp', [])
.controller('myCtrl', function($scope) {
$scope.func = function() {
$scope.name = "Test Name";
}
})
.directive("myDirective", function($compile) {
return {
template: "<div>{{name}}</div>",
scope: {
name: '='
},
link: function(scope, element, attrs) {
alert(scope.name);
}
}
});
Basically, I am trying to pass a variable value from a scope function to the directive - but the alert message shows up an undefined value.
Any idea as to what is going wrong here? How can I pass the value stored within $scope.name within the $scope.func function and pass it to the directive?
The updated fiddle can be found here.
The problem is that you are defining name inside a function in your controller and that function is never called. Change to this.
angular.module('sampleApp', [])
.controller('myCtrl', function($scope) {
$scope.name = "Test Name";
})
.directive("myDirective", function($compile) {
return {
template: "<div>{{name}}</div>",
scope: {
name: '='
},
link: function(scope, element, attrs) {
alert(scope.name);
}
}
});
<div ng-app="sampleApp" ng-controller="myCtrl">
<div my-directive name="name">
</div>
</div>
The alert function is executing before the data is set by the controller.
To see value changes, add a controller and use $onChanges Life-Cycle Hook:
app.directive("myDirective", function() {
return {
template: "<div>{{name}}</div>",
scope: {
̶n̶a̶m̶e̶:̶ ̶'̶=̶'̶
name: '<'
},
controller: function() {
this.onChanges = function(changesObj) {
if (changesObj.name) {
alert(changesObj.name.currentValue);
};
};
}
}
});
Also note that one-time < binding is used instead of two-way = binding.

Directive in directive Angular

I am new to AngularJS and I am trying to create directive which contains another directive inside.
Here how first directive look like
(
function () {
app.directive("cmEventBar", function () {
var controller = function () {
var vm = this;
vm.events = [
{name: "Truckdriver1", eventId: 1 },
{name: "Truckdriver2", eventId: 1 },
{name: "Truckdriver3", eventId: 1 }
];
}
return {
templateUrl: "app/shared/eventsBar/eventBar.html",
restrict: "E",
controller: controller,
priority: 1000,
terminal: true,
controllerAs: "vm",
scope: {}
};
});
})();
Inside html of this directive I am using ng-repeat to show all events. Insinde ng-repeat I have another directive:
<div ng-repeat="item in vm.events">
<cm-single-event name="{{item.name}}" eventId="{{item.eventId}}"></cm-single-event>
</div>
Here how second directive look like:
(function () {
app.directive("cmSingleEvent", function () {
var controller = function () {
var vm = this;
vm.info = switchEvent(eventId);
}
return {
template: "<li class={{vm.info.itemClass}}> {{vm.name}} {{vm.info.messege}} </li>",
restrict: "E",
controller: controller,
controllerAs: "vm",
scope: {
name: "=",
eventId: "="
}
};
});
})();
The output is a little weird because event has 3 elements and in output I see only one element + there are no vm.info from directive inside.
Output
{{vm.name}} {{vm.info.messege}}
What am I doing wrong here?
Thanks in advance!
As you are using = for name & eventId, you should not use {{}} while assigning there value in attribute & cmSingleEvent directive should have bindToController: true to retrieve value from isolated scope to controller this(context)
<cm-single-event name="item.name" event-id="item.eventId"></cm-single-event>

ng-click in angular directive - pass function from root scope

Fixed the issue, here is the final fiddle that shows it working:
http://jsfiddle.net/mbaranski/tfLeexdc/
I have a directive:
var StepFormDirective = function ($timeout, $sce, dataFactory, $rootScope) {
return {
replace: false,
restrict: 'AE',
scope: {
context: "=",
title: "="
},
template: '<h3>{{title}}</h3><form id="actionForm" class="step-form"></form><button ng-click="alert()" type="button">Save</button>',
link: function (scope, elem, attrs) {
}
}
}
How do I make the alert() do something from the controller?
Here is a fiddle:
http://jsfiddle.net/mbaranski/tfLeexdc/
Angular can be twitchy, so I've built a whole new fiddle to demonstrate all of the "glue-up" pieces you need to make this work.
First, you weren't passing the properties through to the directive, so I've made that adjustment:
// You have to pass the function in as an attribute
<hello-directive list="osList" func="myFunc()"></hello-directive>
Second, you were using onclick instead of ng-click in your template, which was part of the problem, so I made that switch:
// You need to use "ng-click" instead of "onclick"
template: '<h3>{{list}}</h3><button ng-click="func()" type="button">Button</button>',
And lastly, you need to bind the function in the scope of the directive, and then call it by the bound name:
scope: {
list: "=",
// Bind the function as a function to the attribute from the directive
func: "&"
},
Here's a Working Fiddle
All of this glued up together looks like this:
HTML
<div ng-controller="MyCtrl">
Hello, {{name}}!
<hello-directive list="osList" func="myFunc()"></hello-directive>
</div>
Javascript
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.name = 'Angular Directive';
$scope.osList = "Original value";
$scope.stuffFromController = {};
$scope.myFunc = function(){ alert("Function in controller");};
};
var HelloDirective = function() {
return {
scope: {
list: "=",
func: "&"
}, // use a new isolated scope
restrict: 'AE',
replace: false,
template: '<h3>{{list}}</h3><button ng-click="func()" type="button">Button</button>',
link: function(scope, elem, attrs) {
}
};
};
myApp.directive("helloDirective", HelloDirective);
If you'd like to execute a function defined somewhere else, make sure you pass it in by the scope directive attribute.
Here you can do:
scope: {
context: '=',
title: '=',
alert='&' // '&' is for functions
}
In the place where you using the directive, you'll pass the "expression" of the function (meaning not just the function, but the actual invocation of the function you want to happen when the click occurs.
<step-form-directive alert="alert()" title=".." context=".."></step-form-directive>

Disable item in angularjs directive with expression from parent controller

I have a list of items which are a custom directive and each of those items has a remove button. Now I want to disable this remove button when there is only one item left in my list, but for some reason it doesn't work as expected.
I've made a plunker example where you an watch this behavior.
I guess there is something wrong with the canRemove: '&' part of my directive. But I don't know how to get it working.
View:
<body ng-controller="MainCtrl as vm">
<div ng-repeat="item in vm.items">
<my-directive item="item"
canRemove="vm.items.length != 1"
remove="vm.remove(item)">
</my-directive>
</div>
</body>
Controller:
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.items = [
{
number: 1
} , {
number: 2
}
];
vm.remove = function(item) {
vm.items.splice(vm.items.indexOf(item), 1);
}
});
Directive:
app.directive('myDirective', function() {
return {
restrict: 'EA',
scope: {
item: '=',
canRemove: '&',
remove: '&'
},
controller: function() {
var vm = this;
vm.onRemove = function() {
vm.remove({ item: vm.item });
};
},
controllerAs: 'vm',
bindToController: true,
template: '<button ng-disabled="!vm.canRemove" ng-click="vm.onRemove()">' +
' Remove {{ vm.item.number }}' +
'</button>'
}
});
PS: Since I'm pretty new to angular is the way I'm handling the removing of the items a good practice? Or should I use broadcast and on instead?
First of all attribute should look like can-remove:
<my-directive item="item" can-remove="vm.items.length > 1" remove="vm.remove(item)"></my-directive>
Then in scope configuration you need to use = binding instead of &:
scope: {
item: '=',
canRemove: '=',
remove: '&'
},
Demo: http://plnkr.co/edit/DlZafON6HEdoyhzvwNIh?p=preview

How to make a variable change in one directive to get reflected in another directve

How do i change the value of bar from directive2 so that it is reflected in directive1
If i make the scope:false it is happening.Is there any other way, to make this happen.(because in the code i am writting , i cannot make scope:false).
My basic requirement is to make one directive to talk to another.
Here you can try the plunkr version of the below code
HTML snippet
<body ng-controller="MainCtrl">
this is directive1: <div directive1></div>.<br/>
this is directive2: <div directive2></div>.
</body>
JS snippet
var app = angular.module('myApp', []);
app.directive('directive1', function() {
return {
restrict: 'A',
replace: true,
template: '<span>{{bar}}</span>'
}
});
app.directive('directive2', function() {
return {
restrict: 'A',
scope:{
},
replace: true,
link:function(s,e,a){
s.bar = "Changed value";
},
template: '<b>{{bar}}</b>'
}
});
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.bar ="original value";
});
You could simply use bar inside your isolate scope, that will do two way binding with your variable which is assigned to bar attribute, That means change inside a directive on bar variable will reflect the changes on controller scope variable.
Markup
<body ng-controller="MainCtrl">
this is directive1: <div directive1></div>.
<br />
this is directive2: <div directive2 bar="bar"></div>.
</body>
Directive
app.directive('directive2', function() {
return {
restrict: 'A',
scope:{
'bar': '=' //<-- Change here
},
replace: true,
link:function(s,e,a){
s.bar = "Changed value";
},
template: '<b>{{bar}}</b>'
}
});
Working Plunkr
I have modified your code in here
Share the variable in both directives by passing it as '=' in the scope, changing it in one directive will change it in the the other.
<body ng-controller="MainCtrl">
this is directive1: <div directive1 bar="bar"></div>.
<br />
this is directive2: <div directive2 bar="bar"></div>.
</body>
var app = angular.module('myApp', []);
app.directive('directive1', function() {
return {
restrict: 'A',
scope:{bar:'='},
replace: true,
template: '<span>{{bar}}</span>'
}
});
app.directive('directive2', function() {
return {
restrict: 'A',
scope:{bar:'='},
replace: true,
link:function(s,e,a){
s.bar = "Changed value";
},
template: '<b>{{bar}}</b>'
}
});
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.bar ="original value";
});
If they don't share the same $scope, the only way is using angularjs events.
In first directive you put:
$rootScope.$on('myEvent', function (event, data) {
$scope.bar = data.bar;
});
In the second one when bar change:
$scope.$emit('myEvent', {bar: bar});
Taking into account that are directives completely unrelated.

Categories