I am trying to pass a function from a controller to a directive so an event fired from the directive could cause a refresh in a different controller.
controllers.controller('UserCtrl', function ($scope) {
$scope.name="Name";
$scope.test = function (t) {
console.log("Inside "+t+" "+$scope.name)
return $scope.test2();
};
$scope.test2 = function(){
return 2;
}
}
<my-test-directive respond="test">
This seems to work fine but when I change it to try and match the Google Angular conventions I get an undefined error on return this.test2();. Here is a plunker with the failing version.
Using the "Google Angular style" how would I handle this?
Please see here: http://plnkr.co/edit/Mugs2C7UOjlXx1L3LsMP?p=preview
You need to change few things :
To call function from directive you should use '&' instead '='
In your html change respond="userController.test" to respond="userController.test(msg)"
Finally you should pass object to function instad of string change scope.respond("So I should be getting inside"); to scope.respond({msg:"So I should be getting inside"})
I hope that will helps.
When you pass a function in javascript the context of the function gets lost so the this keyboard won't work anymore. If you want to pass your test function you need to wrap it in a function that is bound to userCtrl. You can do this with bind() by adding the following line to your controller's constructor and passing boundTest to your directive instead of test
this.boundTest = this.test.bind(this);
Note that bind() was introduced in ES5 so it won't work in IE8
Here is a working plunker http://plnkr.co/edit/BTuwTFf2XsmrR3As4x1x?p=preview
Here is what I came up with
Thanks to rob for the idea, I don't know that I like this though for two reasons...
1.) I cannot seem to use prototype, limiting my inheritance options (as I understand it)
2.) This looks rather hacky
$scope.userController.test2();
Depending on the vote count and comments will depend what I mark as the answer so please provide feedback
Related
For a mockup I need a simple mechanism like
ng-click="alert('Clicked')"
but the code above is not working, can someone help me? I don't want to touch the Controller..
Refer to previous answer, ng-click = "alert('Hello World!')" will work only if $scope points to window.alert i.e
$scope.alert = window.alert;
But even it creates eval problem so correct syntax must be:
HTML
<div ng-click = "alert('Hello World!')">Click me</div>
Controller
$scope.alert = function(arg){
alert(arg);
}
As far as I know, ng-click works only within your $scope. So you would only be able to call functions, defined in your $scope itself. To use alert, you may try accessing the window element, just by using window.alert('Clicked').
EIDT: Thanks to Ibrahim. I forgot. You shouldn't be able to use window.alert, as far as you won't define:
$scope.alert = window.alert;
In this case, using alert('Clicked') in your ng-clicked directive should work. But at the end, this method would not solve your problem of not touching your controller.
You can use
onclick="alert('Clicked')"
for debugging purposes
As Neeraj mentioned, the accepted answer does not work. Add something like this to your controller to avoid an Illegal Invocation error:
$scope.alert = alert.bind(window);
I have a simple js array being retrieved by an angular factory, injected into a control, watched, then displayed in a table using ng-repeat from within a view state managed by ui-router.
Initially I attempted to subscribe to this array using $watchCollection...
self.$watchCollection( self.Data, function(newData, oldData){
self.total = newData.length;
});
However this was only running when I initially load the app. I found that the only way to subscribe to the running collection was to use an anonymous function returning the array in question.
self.$watchCollection( function() { return self.Data }, function(newData, oldData){
self.totalWatchedWithAnonFunc = newData.length;
})
View this all in http://plnkr.co/edit/L7mycl
From everything I read, all I should have needed to do for a valid subscription was to pass in the array itself and not an anonymous function that returns the array.
The reason I included ui-router is because my actual application is using it heavily and I wanted to mock up my environment as closely as possible to how I've got things set up.
What am I not understanding? Could I be doing something differently?
Thanks.
Are you looking for self.$watchCollection("Data", ...) instead of self.$watchCollection(self.Data, ...)? Try it out! See the docs to see why: the first argument is a string evaluated on the scope, or a function taking a scope that returns something you want to watch.
In angularJs is possible to watch a global variable?
I set a window.test variable from legacy code, then I need to watch that variable to know if it exists.
I've tried something like
$window.$watch("test" , function(n,o){
//some code here...
}
Somewhat. You can if you include the Angular $window service (which is safer, as explained in the docs, than accessing window directly):
app.controller('myCtrl', function ($scope,$window) {...}
And then use a watch function as the first parameter to your $watch like so:
$scope.$watch(
function () {
return $window.test
}, function(n,o){
console.log("changed ",n);
}
);
demo fiddle
But note that the $watch won't execute until something triggers Angular to do a $digest. One possible way to do that is to wrap your legacy code in a $scope.$apply or trigger a $digest once the legacy code has exectuted. Here's some good documentation on this.
Basically whenever a change happens outside of angular (for instance this is a common issue when jQuery causes the change) something has to tell Angular to go see if something changed. It's one way Angular maintains reasonable performance.
Angular.js provides a banch of global functions like angular.lowercase, angular.isArray etc.
Suppose I have a string in my scope:
function MyController($scope) {
$scope.myString = "TEST"
}
Calling angular.lowercase has no effect:
{{lowercase(myString)}}
{{angular.lowercase(myString)}}
How can I call such function in my template?
UPDATE
Example with angular.isArray
<div ng-show="isArray(myVar)">...</div>
The expression in the {{}} is not actual javascript although it looks that way - it's an angularjs expression. For this reason not everything will be available to you.
charlietfl is right that your particular case can be solved with an existing filter. Not every angular.* function is exposed this way, however, in which case you should create your own custom filters.
Filters are cleanest but as a dirty workaround you could also just have the following line in your controller:
$scope.lowercase = angular.lowercase; // not angular.lowercase()
Using the Angular UI Select2 directive, with tags defined on an input field. If the input is itself inside a custom directive, then it is not initialised correctly and the console gives an error:
query function not defined for Select2 tagging
I suspect this might be to do with the order in which the directives are compiled / linked vs when the select 2 function is called.
Maybe there is a simple workaround, perhaps using the compile function or a directive controller instead of a link function? Or maybe it is an issue with the Angular UI select2 directive.
I have made a plunker that displays the problem:
http://plnkr.co/edit/myE5wZ
So my question is - How do you get get select2 tags working from inside a custom Angular directive?
In the end I managed to find a solution I was happy with involving nesting two directives, that way the logic can be encapsulated inside the parent directive (not spilling out into the controller).
A Plunker of my solution is here for anyone who may stumble across the same issue:
http://plnkr.co/edit/ZxAPF5BzkgPtn9xddCRM
I just encountered this today and summarily realized the fix:
PostLinking functions are executed in reverse order (deepest grandchild to greatest grandparent).
Put your custom modal's code (or anything that sets $scope data for use in its children) inside a PreLinking function. PreLinking functions go from parent to child, and all PreLinking functions are performed before the PostLinking functions.
I had a similar issue. Your solution works but IMHO I think an even better solution is to use the controller function instead of the link function inside the directive. Doing this you do need nested directives.
By using the controller function instead of the link function in the directive it's working. Example:
function myFunction() {
var dir = {};
dir.scope = { myModel: '=' };
dir.restrict = 'E';
dir.templateUrl = 'myTemplate.html';
dir.replace = true;
dir.controller = function ($scope) {
$scope.myVar = ...;
};
return dir;
};
I have this error too. My short solution:
<input type="hidden"
name="citizenship"
class="form-control input-sm col-sm-10"
style="width:500px"
multiple
ui-select2="params.options.citizenshipOptions"
ng-model="cvLang.content.citizenship"
ng-repeat="a in [1]"
/>
ng-repeat="a in [1]" is a magical thing!!! It is not clear for me a logic of a context, but this is working. May be this can help?