I'm trying to make a directive which receives expression as a callback to bootstrap's 'hidden.bs.modal' event:
//the use
<div class="modal" modal-on-hide="currPane = 'firstPanel'">
//the implementation
app.directive('modalOnHide', function () {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
element.on('hidden.bs.modal', function hideCallback () {
scope.$eval(attrs.modalOnHide);
});
}
};
});
currPane is an attr on the parent scope which is the same scope as the directive's, yet, when hideCallback executes, it's not being set to the new value. Idea?
Try this way:
element.on('hidden.bs.modal', function hideCallback () {
scope.$apply(function(){
scope.$eval(attrs.modalOnHide);
});
});
Or:
element.on('hidden.bs.modal', function hideCallback () {
scope.$apply(attrs.modalOnHide);
});
Related
Hi I am working on angularjs. I am facing an issue in directive.
I have set the scope.user.name="amin shah" on link/click event
and want to access this in controller how is this possible?
var dataSourceDirective = angular.module('mydirective', []);
dataSourceDirective.directive('dir', function () {
return {
restrict: 'C',
scope: true,
link: function ($scope, element, attrs) {
element.bind('click', function () {
$scope.user.name ="amin shah";
$scope.$apply();
$('.sourceType_panel').hide();
$('#sourceType_1_panel').show();
});
}
}
});
controller code
$scope.demo = function () {
console.log($scope.user);`
},
You need to create Isolated scope in your directive.
The given controller should be parent of this directive.
var dataSourceDirective = angular.module('mydirective', []);
dataSourceDirective.directive('dir', function () {
return {
restrict: 'C',
scope: {user:"=user"},
link: function ($scope, element, attrs) {
element.bind('click', function () {
$scope.user.name ="amin shah";
});
}
}
});
In html :
<div ng-copntroller='yourCtrl'>
<dir user="user"></dir>
</div>
In Controller you should initialize the user.
OR
you use $broadcast & $emit if the parent is controller.
Withing link function of directive you can use $rootScope.$emit('user_name_update',user);
And in the controller you can listen this event
$scope.$on('user_name_update',function(data){
console.log(user) // its should give your updated `user` object
})
First of all you should correct your link method and I think you shouldn't need child sope at there. So you should delete your scope bind in directive too. You can reach parent scope with link method.
app.directive('dir', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
element.bind('click', function () {
scope.user.name ="amin shah";
scope.$apply();
});
}
}
});
and in your controller you can define scope variable like that:
app.controller('MainCtrl', function($scope) {
$scope.user = {
name: ''
}
});
also you should add this directive to HTML :
<dir>Element</dir>
<p>{{user.name}}</p>
here is the working plunkr you should click Element than you can see your name from directive but in parent scope
https://plnkr.co/edit/umTdfukZ22hARoLjxdL3?p=preview
Basically, I created a directive that passes a promise to the link function from ng-click and and detects when the promise is done so that I can attach a class to it.
Example:
.directive('myDirective', function($parse) {
return {
restrict: 'A',
scope: {
ng-click: '&'
},
link: function(scope) {
var d = $parse(scope.ngClick);
element.on('click', function(event) {
d().then(function() {
element.addClass(attrs.myDirective);
});
});
}
};
});
<element ng-click="promise();" my-directive="class"></element>
//controller function
$scope.promise = function() {
return promise().then(function() {});
}
It is doing what I want except that the controller function is getting called three times. I would really like to just use require: '^ngClick' here but since the ngClick directive does not have any controllers, I can't do that. Can anyone point me in the right direction? Thanks!
Added event.preventDefault() to the event.on('click') function in the link of my directive:
element.on('click', function(event) {
event.preventDefault();
d().then(function() {
element.addClass(attrs.myDirective);
});
});
Assume that I have a directive like this
<div my-directive callback='doSomething(myArg)'></div>
angular.module('directives').directive('myDirective', function() {
return {
restrict: 'A',
scope: {
callback: '&'
},
link: function(scope, element, attrs) {
element.bind('someEvent', function() {
scope.callback({myArg: 'bla'});
});
}
}
});
If I want to pass a parameter to my scope's function, I have to do scope.callback({myArg: 'bla'}). I wonder if there's a way pass the argument without having to specify its name?
Use can use shared service in this case and inject it to directive:
angular.module("yourAppName", []).factory("mySharedService", function($rootScope){
var mySharedService = {};
mySharedService.values = {};
mySharedService.setValues = function(params){
mySharedService.values = params;
$rootScope.$broadcast('dataPassed');
}
return mySharedService;
});
And after inject it to directive. For example:
app.directive('myDirective', ['mySharedService', function(mySharedService){
return {
restrict: 'C',
link: function (scope, element, attrs) {
mySharedService.setValues(//some value//);
}
}
}]);
Then, you can get necessary value in controller.
function MyCtrl($scope, mySharedService) {
$scope.$on('dataPassed', function () {
$scope.newItems = mySharedService.values;
});
}
I have created a directive, ngAfterRender, that I am trying to use to wire up fancybox:
Template
<div ng-after-render="wireUpFancyBox($event)" ng-bind-html="Content"></div>
Directive
.directive('ngAfterRender', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
$timeout(function () {
scope.$eval(attrs.ngAfterRender, { $element: element });
});
}
};
}]);
Controller
$scope.wireUpFancyBox = function ($element) {
$element.find('a').fancybox($.extend(true, {}, fancyboxOptions, {
scrolling: 'auto',
type: 'inline'
}));
};
Unfortunately, the wireUpFancyBox() method is not called when the HTML Content binding changes.
What can I do here?
If you want wireUpFancyBox called every time the ng-bind changes then you want something like this
myApp.directive('ngAfterRender', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.$eval(attrs.ngBindHtml);
},
function (value) {
$timeout(function () {
scope.$eval(attrs.ngAfterRender, { $element: element });
});
});
}
};
}]);
Here we put a watch on the evaluated ng-bind-html expression and then fire off your eval on a change.
fiddle
In my angular directive, in a callback, I call $apply to:
Set $scope.model.something
Invoke $scope.onAction() which uses model.something.
I do this in one $apply call, but at the time onAction() is invoked, model.something is still undefined.
At the same time, after $apply, {{model.something}} has a correct value, so model.something is updated correctly.
I want model.something to be set, so I can use it in onAction(). How to fix the following code?
Here's the directive (I skipped not relevant code):
.directive(function () {
return {
scope: {
ngModel: '=',
onAction: '='
},
compile: function (element, attrs) {
return function (scope) {
// This is some callback which is invoked
// outside of digest cycle.
function callback() {
// Here I want to set model and call onAction callback
scope.$apply(function () {
scope.ngModel = 'something';
scope.onAction();
});
}
}
}
};
})
At the same time, my controller looks like:
var MyController = function ($scope) {
$scope.model = {};
$scope.onAction = function () {
// Here I want $scope.model.something to be set to "something"
// But it's undefined.
alert($scope.model.something);
};
}
Finally, HTML:
<div ng-controller="MyController">
{{ model.something }}
<my-directive ng-model="model.something" on-action="onAction"/>
</div>
One more thing, I know I could just call scope.onAction('something'), I'm looking for some other solution.
Here's the fiddle.
You can simply wrap each line into it's own $apply callback:
compile: function (element, attrs, transclude) {
return function (scope, element, attrs) {
setTimeout(function () {
var something = 'lorem ipsum';
scope.$apply(function () {
scope.ngModel = something;
});
scope.$apply(function () {
scope.onAction();
});
}, 200);
};
}
Fiddle
Use $timeout:
$timeout(function(){
scope.onAction(something);
});
Or use $watch:
scope.$watch("ngModel",function(){
scope.onAction(something);
});