AngularJS broadcast Of $routeChangeSuccess fires twice in directive - angularjs

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

Related

watch on attribute change angular from directive controller

I have a directive but I am facing problem in watching an attribute from the directive controller.
angular.module('app',[])
.directive('timer1', function () {
return {
template: '<div class="timerCont1"><div class="progressBar"></div></div>',
restrict: 'E',
replace:true,
scope: true,
controller: function ($scope, $element, $attrs) {
$scope.$watch($attrs.timerevent, function (value) {
switch ($attrs.timerevent)
{
case "start":
$scope.timeoutId = null;
$scope.countdown = Number($attrs.timer);
$scope.tick();
break;
case "stop":
$scope.stop();
break;
case "destroy":
alert()
$scope.stop();
$scope.$emit('destroy_pizza', {
});
}
},true);
$scope.tick = function () {
$scope.timeoutId = setTimeout(function () {
if ($scope.countdown <= 0) {
$scope.$apply(function () {
$attrs.$set('timerevent', 'destroy')
});
}
else {
$scope.countdown--;
$scope.tick();
}
$scope.$apply();
}, $attrs.interval);
};
$scope.stop = function () {
clearTimeout($scope.timeoutId);
$scope.timeoutId = null;
};
}
};
});
And here goes my hTML
<timer1 interval="1000" timerevent="start" timer="10"></timer1>
When I am setting the attribute timerevent to "destroy" my watch is not getting called, whereas the attribute is updated successfully.
If you are going to get changes in $watch use the scope instead of $attrs.
angular.module('abc').directive('timer1', function () {
return {
template: '<div class="timerCont1"><div class="progressBar"></div></div>',
restrict: 'E',
replace:true,
scope: {
timerevent:"=",
timer:"#",
interval:"#"
},
controller: function (scope, $element, $attrs) {
scope.$watch('timerevent', function () {
//this section will be run after chnaging the timerevent
},true);
}
};
});
I managed to get a solution to my own problem :)
Instead of watch I tried observing the attribute
Here is my working code https://plnkr.co/edit/LKuYcCU5z5wa7dTe1Uzo
Since its a long piece of code I am writing my controller
<timer1 interval="1000" timer-event="start" timer="10"></timer1>
$attrs.$observe('timerEvent', function(value) {
switch (value.toLowerCase()) {
case "start":
$scope.timeoutId = null;
$scope.countdown = Number($attrs.timer);
$scope.tick();
break;
case "stop":
$scope.stop();
break;
case "destroy":
alert("It is watched")
$scope.stop();
$scope.$emit('destroy_pizza', {
});
}
}, true);
For more information, see AngularJS $compile Attributes API Reference - $observe.

The checkbox generated by angular directive not responding to ng-change

my directive:
(function () {
var directive = function ($compile, $http, $rootScope, $translate) {
return {
restrict: 'E',
scope: {
baseUrl: '#rmsUrl',
},
link: function (scope, element, attrs) {
$rootScope.languageSwitcher = {
toggle: true,
changeLanguage: function () {
if ($rootScope.languageSwitcher.toggle) {
$translate.use('ENG');
} else {
$translate.use('FRE');
}
}
}
$rootScope.$on('oauth2:authSuccess', function (data) {
var html2 = 'French <label class="switch">'
html2 += '<input type="checkbox" ng-model="languageSwitcher.toggle" ng-change="languageSwitcher.changeLanguage()" /><div></div>'
html2 += '</label>English'
element.html(html2);
$compile(element.contents())(scope);
});
}
};
};
angular.module('testingApp')
.directive('rmsLanguageToggler', directive);
}());
my index file contain the directive:
<rms-language-toggler rms-url='blah blah blah'></rms-language-toggler>
my question:
The html render correctly, however changing/clicking the checkbox doesn't trigger the function: $rootScope.languageSwitcher.changeLanguage()
I found out why now. Turns out the ng-change and ng-model inside the directive is still referencing to the inner isolated scope. I have to use $parent. to access the outer model, i.e. $parent.languageSwitcher.toggle

element.on("click", ...) don't trigger $watch

Why does not the click event fire $watch in the code below? If I include $apply, $watch is triggered.
angulartest.factory("Fac", function () {
var v = "foo";
return {
getV: function () {
return v;
},
setV: function (v_) {
v = v_;
}
};
});
angulartest.directive("wdirective", function (Fac) {
return {
restrict: "E",
template: "<p>Hello</p>",
link: function (scope, element, attrs) {
element.on("click", function (event) {
Fac.setV("bar");
//scope.$apply(); <-- Need this to fire $watch
});
}
};
});
angulartest.controller("wController", function($scope, Fac) {
$scope.$watch(Fac.getV, function(newValue, oldValue) {
console.log("v = " + newValue);
});
});
Because Angulars $digest cycle is not triggered by pure JS click events.

angular directive (ng-class) inside custom directive

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

How do I modify the button configuration (buttonConfig) in angular ui.bootstrap.buttons module?

Looking at the angular-ui bootstrap code, I notice that a button config gets passed into the directive. The config defines the active class and toggle event. I'd like to modify those without modifying the angular-ui bootstrap code. How can I pass in my own configuration when using this directive?
Here is the code provided by angular-ui bootstrap:
angular.module('ui.bootstrap.buttons', [])
.constant('buttonConfig', {
activeClass:'active',
toggleEvent:'click'
})
.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
var activeClass = buttonConfig.activeClass || 'active';
var toggleEvent = buttonConfig.toggleEvent || 'click';
return {
require:'ngModel',
link:function (scope, element, attrs, ngModelCtrl) {
var value = scope.$eval(attrs.btnRadio);
//model -> UI
scope.$watch(function () {
return ngModelCtrl.$modelValue;
}, function (modelValue) {
if (angular.equals(modelValue, value)){
element.addClass(activeClass);
} else {
element.removeClass(activeClass);
}
});
//ui->model
element.bind(toggleEvent, function () {
if (!element.hasClass(activeClass)) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(value);
});
}
});
}
};
}])
It is very simple, just create a constant named buttonConfig in your application's module:
angular.module('myAppModule', ['ui.bootstrap'])
.constant('buttonConfig', {
activeClass:'my-active-class'
});
Here is a working plunker: http://plnkr.co/edit/Hw5ahEos8UC5P23nV4oW?p=preview

Resources