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.
Related
i want to do something like this in an angular directive function:
app.directive("detectFocus", function ($focusTest, $location, $rootScope) {
return {
restrict: "A",
scope: {
onBlur: '&onBlur',
},
link: function (scope, elem) {
elem.on("blur", function () {
console.log("blur");
if(back button is pressed) {
$focusTest.setFocusOnBlur(false);
}
else {
$focusTest.setFocusOnBlur(true);
}
});
}
}
});
How can i detect whether back button was pressed or not....
You can keep a $rootScope variable to check whether the backbutton is pressed or not.
$rootScope.navigated = false;
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
if (from.name) { $rootScope.navigated = true; }
});
Then inside your link function, you can do something like this
link: function(scope, elem) {
elem.on("blur", function() {
console.log("blur");
if ($rootScope.navigated) {
$focusTest.setFocusOnBlur(false);
} else {
$focusTest.setFocusOnBlur(true);
}
});
}
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
This is some directive that i use for detecting enter key
.directive('enterSubmit', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('keydown', function(event) {
var code = event.keyCode || event.which;
if (code === 13) {
if (!event.shiftKey) {
event.preventDefault();
scope.$apply(attrs.enterSubmit);
}
}
});
}
}
})
I have a function that i wanna get $event as a parameter to it.
$scope.test = function(evt){
var el = angular.element(evt.target);
console.log(el[0]);
}
But when i use $event as i could in built-in directives
<textarea enter-submit="test($event)"></textarea>
It says evt is undefined so how to do it?
Change your if to this:
if (!event.shiftKey) {
event.preventDefault();
var enterSubmitFunction = $parse(attrs['enterSubmit']);
enterSubmitFunction(scope, { $event: event });
scope.$apply();
}
You'll need to inject $parse now, and i'm not sure if you need to use scope.$parent in the enterSubmitFunction or just scope. Try both.
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);
});
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