angular directive (ng-class) inside custom directive - angularjs

I just would like to show and hide an spinner every time that a user click on the link, in this case I'm using a promise to wrap the actual click method, when the promise get resolved I want hide the spinner.
for some reason it seems like the directive isn't binding the value that I have in the scope with the ng-class in the template
any ideas?
app.directive('toogleTextLink', function($compile,$q) {
return {
restrict: 'AE',
scope: { callback: "&targetMethod" },
template: '<div><a style="cursor: pointer" ><b>{{text}}</b></a> <div ng-class="{previewLoader: show}"></div></div>',
link: function (scope, element, attr) {
scope.value = attr.value;
scope.show = false;
scope.$watch('value', function () {
if (scope.value) {
scope.text = "yes";
} else {
scope.text = "no";
}
});
element.bind('click', function () {
scope.show = true;
scope.value = !scope.value;
scope.$apply();
if (scope.callback) {
var deferred = $q.defer();
deferred.resolve(scope.callback());
deferred.promise.then(function () {
scope.show = false;
console.log("then called");
});
}
});
}
};
});
take a look to the plunker

The problem seams the size of the spinner (CSS) also you are resolving the promise immediately, so you wont be able to see the spinner.
Check these changes
http://plnkr.co/edit/viwzCb?p=preview

Related

AngularJS broadcast Of $routeChangeSuccess fires twice in directive

I am using the following code to broadcast a route change to a directive:
function run($rootScope) {
$rootScope.$on('$routeChangeSuccess',
function(event, current, previous, rejection) {
if (current.$$route.originalPath !== '') {
$rootScope.$broadcast(event.name, { loadedTemplateUrl: current.loadedTemplateUrl });
}
});
}
The directive is receiving the broadcast twice. The directive is placed upon an html template. There is no controller. How can I prevent from firing twice in directive?
function optimizely($compile) {
var directive = {
restrict: 'E',
link: function (scope, element) {
scope.$on('$routeChangeSuccess',
function (event, data) {
var template = '';
switch (data.loadedTemplateUrl) {
case '/app/views/china.html':
template = '<script src=""></script>';
break;
default:
template = '<script src="App/optimizelyTest.js"></script>';
}
scope.$apply(function () {
var content = $compile(template)(scope);
element.append(content);
});
});
}
};
return directive;
}
Thanks,
Mark

Why does a function passed to a directive not update a scope variable?

In this AngularJS code:
http://jsfiddle.net/edwardtanguay/xfbgjun5/8/
I have a scope function addCustomer() which will not update the scope variable score:
.controller('mainController', function ($scope) {
$scope.customers = ['First','Second','Third'];
$scope.score = 'sdfkj';
$scope.addCustomer = function() {
$scope.score = 'this does not work';
console.log('but it obviously gets here');
}
$scope.changeIt = function() {
$scope.score = 'this works';
}
...
})
I pass in the function addCustomer() as add:
return {
restrict: 'A',
scope: {
datasource: '=',
add: '&'
},
link: link
};
and then call it in my directive:
function addItem() {
scope.add();
items.push('new customer');
render();
}
Why doesn't the scope function addCustomer() update the scope variable score?
Looking at your fiddle your issue is here:
element.on('click', function(event) {
if(event.target.id === 'addItem') {
addItem();
event.preventDefault();
}
});
By doing an element.on you're wiring up your own event in angular. This won't work and you need to do this as well:
element.on('click', function(event) {
if(event.target.id === 'addItem') {
addItem();
event.preventDefault();
scope.$apply();
}
});
This is because the 'click' happenned outside of angular if you build it this way. You should also look into how to build a directive as this is not how you build it (with an html variable and then adding it in). There shouldn't be any html (expect in specific circumstances) in your directive code.

Passing ng-click/ng-submit promise to directive

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);
});
});

Angular directive removes ng-click functionality

I have a directive that is almost an exact copy of the old uiIf directive from the angular-ui project.
What is happening is that when I add my "restrict" directive, the button is successfully added/removed based upon what the user is authorized to do.
The problem is that the ng-click action no longer works. It doesn't call in to the controller's scope and trigger the function to be called. Does anyone see what might be causing my issue?
See: http://plnkr.co/edit/38UeVCCYkdzxBkxOLe5g?p=preview
<button restrict="'canPerformAction'" ng-click="action()">Action</button>
'use strict';
angular.module('directives.restrict', [])
.directive('restrict', function(_){
return{
transclude: 'element',
prioriry: 1000,
terminal: true,
restrict: 'A',
compile: function(element, attr, transclude) {
var user = { caps: [ 'canPerformAction', 'canDance', 'canWrite' ] };
return function(scope, element, attr) {
var childElement;
var childScope;
scope.$watch(attr.restrict, function(attributes) {
if (childElement) {
childElement.remove();
childElement = undefined;
}
if (childScope) {
childScope.$destroy();
childScope = undefined;
}
if(_.intersection(user.caps, attributes.split(' ')).length > 0) {
childScope = scope.$new();
transclude(childScope, function(clone) {
childElement = clone;
element.after(clone);
});
}
});
};
}
};
});

$apply with two operations, where one depends on the other

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);
});

Resources